kern

changeset 96:07fe6a614185

filesystem
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 15 Dec 2011 04:39:00 +0200
parents ec62cbe00b55
children 8717eb590727
files include/kdef.h src/fs.c src/fs.h src/proc.c src/proc.h
diffstat 5 files changed, 314 insertions(+), 31 deletions(-) [+]
line diff
     1.1 --- a/include/kdef.h	Sun Dec 11 21:15:35 2011 +0200
     1.2 +++ b/include/kdef.h	Thu Dec 15 04:39:00 2011 +0200
     1.3 @@ -31,13 +31,16 @@
     1.4  #if defined(KERNEL) || defined(KDEF_ERRNO_H)
     1.5  #define EFOO		1 /* I just like to return -1 some times :) */
     1.6  
     1.7 -#define EAGAIN		2
     1.8 -#define EINVAL		3
     1.9 -#define ECHILD		4
    1.10 -#define EBUSY		5
    1.11 -#define ENOMEM		6
    1.12 -#define EIO			7
    1.13 -#define ENOENT		8
    1.14 +#define EAGAIN			2
    1.15 +#define EINVAL			3
    1.16 +#define ECHILD			4
    1.17 +#define EBUSY			5
    1.18 +#define ENOMEM			6
    1.19 +#define EIO				7
    1.20 +#define ENOENT			8
    1.21 +#define ENAMETOOLONG	9
    1.22 +#define ENOSPC			10
    1.23 +#define EPERM			11
    1.24  
    1.25  #define EBUG		127	/* for missing features and known bugs */
    1.26  #endif	/* errno.h */
    1.27 @@ -68,4 +71,36 @@
    1.28  
    1.29  #endif	/* syscall.h */
    1.30  
    1.31 +/* --- defines for sys/stat.h */
    1.32 +#if defined(KERNEL) || defined(STAT_H)
    1.33 +
    1.34 +#define S_IFMT		0170000	/* bit mask for the file type bit fields */
    1.35 +#define S_IFSOCK	0140000	/* socket */
    1.36 +#define S_IFLNK		0120000	/* symbolic link */
    1.37 +#define S_IFREG		0100000	/* regular file */
    1.38 +#define S_IFBLK		0060000	/* block device */
    1.39 +#define S_IFDIR		0040000	/* directory */
    1.40 +#define S_IFCHR		0020000	/* character device */
    1.41 +#define S_IFIFO		0010000	/* FIFO */
    1.42 +
    1.43 +#define S_ISUID		0004000	/* set UID bit */
    1.44 +#define S_ISGID		0002000	/* set-group-ID bit (see below) */
    1.45 +#define S_ISVTX		0001000	/* sticky bit (see below) */
    1.46 +
    1.47 +#define S_IRWXU		00700	/* mask for file owner permissions */
    1.48 +#define S_IRUSR		00400	/* owner has read permission */
    1.49 +#define S_IWUSR		00200	/* owner has write permission */
    1.50 +#define S_IXUSR		00100	/* owner has execute permission */
    1.51 +#define S_IRWXG		00070	/* mask for group permissions */
    1.52 +#define S_IRGRP		00040	/* group has read permission */
    1.53 +#define S_IWGRP		00020	/* group has write permission */
    1.54 +#define S_IXGRP		00010	/* group has execute permission */
    1.55 +#define S_IRWXO		00007	/* mask for permissions for others (not in group) */
    1.56 +#define S_IROTH		00004	/* others have read permission */
    1.57 +#define S_IWOTH		00002	/* others have write permission */
    1.58 +#define S_IXOTH		00001	/* others have execute permission */
    1.59 +
    1.60 +#endif	/* sys/stat.h */
    1.61 +
    1.62 +
    1.63  #endif	/* KERNEL_DEFS_H_ */
     2.1 --- a/src/fs.c	Sun Dec 11 21:15:35 2011 +0200
     2.2 +++ b/src/fs.c	Thu Dec 15 04:39:00 2011 +0200
     2.3 @@ -1,7 +1,4 @@
     2.4 -/* This code is used by the kernel AND by userspace filesystem-related tools.
     2.5 - * The kernel-specific parts are conditionally compiled in #ifdef KERNEL blocks
     2.6 - * the rest of the code should be independent.
     2.7 - */
     2.8 +/* This code is used by the kernel AND by userspace filesystem-related tools. */
     2.9  #include <stdio.h>
    2.10  #include <stdlib.h>
    2.11  #include <string.h>
    2.12 @@ -9,6 +6,14 @@
    2.13  #include <assert.h>
    2.14  #include "fs.h"
    2.15  #include "bdev.h"
    2.16 +#include "kdef.h"
    2.17 +
    2.18 +/* number of inodes in a block */
    2.19 +#define BLK_INODES		(BLKSZ / sizeof(struct inode))
    2.20 +/* number of directory entries in a block */
    2.21 +#define BLK_DIRENT		(BLKSZ / sizeof(struct dir_entry))
    2.22 +
    2.23 +#define BLKBITS				(BLKSZ * 8)
    2.24  
    2.25  #define BM_IDX(x)			((x) / 32)
    2.26  #define BM_BIT(x)			((x) & 0x1f)
    2.27 @@ -18,11 +23,18 @@
    2.28  #define BM_CLR(bm, x)		((bm)[BM_IDX(x)] &= ~(1 << BM_BIT(x)))
    2.29  
    2.30  
    2.31 -int openfs(struct filesys *fs, dev_t dev);
    2.32 +static struct inode *newdir(struct filesys *fs, struct inode *parent);
    2.33 +static int addlink(struct filesys *fs, struct inode *target, struct inode *node, const char *name);
    2.34  static int read_superblock(struct filesys *fs);
    2.35  static int write_superblock(struct filesys *fs);
    2.36  static int get_inode(struct filesys *fs, int ino, struct inode *inode);
    2.37  static int put_inode(struct filesys *fs, struct inode *inode);
    2.38 +static int find_free(uint32_t *bm, int sz);
    2.39 +static int alloc_inode(struct filesys *fs);
    2.40 +static void free_inode(struct filesys *fs, int ino);
    2.41 +static int alloc_block(struct filesys *fs);
    2.42 +static void free_block(struct filesys *fs, int ino);
    2.43 +static int file_block(struct filesys *fs, struct inode *node, int boffs);
    2.44  
    2.45  int openfs(struct filesys *fs, dev_t dev)
    2.46  {
    2.47 @@ -38,19 +50,164 @@
    2.48  
    2.49  	/* read the superblock */
    2.50  	if(!(fs->sb = malloc(BLKSZ))) {
    2.51 -		res = -ENOMEM;
    2.52 -		goto done;
    2.53 +		blk_close(bdev);
    2.54 +		return -ENOMEM;
    2.55  	}
    2.56  	if((res = read_superblock(fs)) != 0) {
    2.57 -		goto done;
    2.58 +		blk_close(bdev);
    2.59 +		return res;
    2.60  	}
    2.61  
    2.62 +	return 0;
    2.63 +}
    2.64  
    2.65 -done:
    2.66 -	blk_close(bdev);
    2.67 -	return res;
    2.68 +int mkfs(struct filesys *fs, dev_t dev)
    2.69 +{
    2.70 +	struct filesys *fs;
    2.71 +	struct superblock *sb;
    2.72 +	struct block_device *bdev;
    2.73 +	int i, bcount;
    2.74 +
    2.75 +	if(!(bdev = blk_open(dev))) {
    2.76 +		return -1;
    2.77 +	}
    2.78 +	fs->bdev = bdev;
    2.79 +
    2.80 +	if(!(sb = malloc(BLKSZ))) {
    2.81 +		blk_close(bdev);
    2.82 +		return -1;
    2.83 +	}
    2.84 +	fs->sb = sb;
    2.85 +
    2.86 +	/* populate the superblock */
    2.87 +	sb->magic = MAGIC;
    2.88 +	sb->ver = FS_VER;
    2.89 +	sb->blksize = BLKSZ;
    2.90 +
    2.91 +	sb->num_blocks = bdev->size;
    2.92 +	sb->num_inodes = sb->num_blocks / 4;
    2.93 +
    2.94 +	/* inode bitmap just after the superblock */
    2.95 +	sb->ibm_start = 2;
    2.96 +	sb->ibm_count = (sb->num_inodes + BLKBITS - 1) / BLKBITS;
    2.97 +	/* also allocate and initialize in-memory inode bitmap */
    2.98 +	sb->ibm = malloc(sb->ibm_count * BLKSZ);
    2.99 +	assert(sb->ibm);
   2.100 +	memset(sb->ibm, 0, sb->ibm_count * BLKSZ);
   2.101 +
   2.102 +	/* XXX mark inode 0 as used always */
   2.103 +	BM_SET(sb->ibm, 0);
   2.104 +
   2.105 +	/* block bitmap just after the inode bitmap */
   2.106 +	sb->bm_start = sb->ibm_start + sb->ibm_count;
   2.107 +	sb->bm_count = (sb->num_blocks + BLKBITS - 1) / BLKBITS;
   2.108 +	/* also allocate and initialize in-memory block bitmap */
   2.109 +	sb->bm = malloc(sb->bm_count * BLKSZ);
   2.110 +	assert(sb->bm);
   2.111 +	memset(sb->bm, 0, sb->bm_count * BLKSZ);
   2.112 +
   2.113 +	/* inode table, just after the block bitmap */
   2.114 +	sb->itbl_start = sb->bm_start + sb->bm_count;
   2.115 +	sb->itbl_count = (sb->num_inodes * sizeof(struct inode) + BLKSZ - 1) / BLKSZ;
   2.116 +
   2.117 +	/* mark all used blocks as used */
   2.118 +	bcount = sb->itbl_start + sb->itbl_count;
   2.119 +	memset(sb->bm, 0xff, bcount / 8);
   2.120 +	for(i=0; i<bcount % 8; i++) {
   2.121 +		int bit = bcount / 8 + i;
   2.122 +		BM_SET(sb->bm, bit);
   2.123 +	}
   2.124 +
   2.125 +	/* create the root directory */
   2.126 +	sb->root = newdir(fs, 0);
   2.127 +	sb->root_ino = sb->root->ino;
   2.128  }
   2.129  
   2.130 +static struct inode *newdir(struct filesys *fs, struct inode *parent)
   2.131 +{
   2.132 +	struct inode *dirnode;
   2.133 +
   2.134 +	/* allocate and initialize inode */
   2.135 +	if(!(dirnode = malloc(sizeof *dirnode))) {
   2.136 +		return 0;
   2.137 +	}
   2.138 +	memset(dirnode, 0, sizeof *dirnode);
   2.139 +
   2.140 +	if((dirnode->ino = alloc_inode(fs)) == -1) {
   2.141 +		printf("failed to allocate inode for a new directory\n");
   2.142 +		free(dirnode);
   2.143 +		return 0;
   2.144 +	}
   2.145 +	dirnode->mode = S_IFDIR;
   2.146 +
   2.147 +	/* add . and .. links */
   2.148 +	addlink(fs, dirnode, dirnode, ".");
   2.149 +	addlink(fs, dirnode, parent ? parent : dirnode, "..");
   2.150 +
   2.151 +	/* and write the inode to disk */
   2.152 +	put_inode(fs, dirnode);
   2.153 +	return dirnode;
   2.154 +}
   2.155 +
   2.156 +static int addlink(struct filesys *fs, struct inode *target, struct inode *node, const char *name)
   2.157 +{
   2.158 +	struct dir_entry ent, *data;
   2.159 +	int boffs, bidx, len;
   2.160 +
   2.161 +	if(!(target->mode & S_IFDIR)) {
   2.162 +		return -ENOTDIR;
   2.163 +	}
   2.164 +	if(node->mode & S_IFDIR) {
   2.165 +		return -EPERM;
   2.166 +	}
   2.167 +	/* TODO check that the link does not already exist (EEXIST) */
   2.168 +
   2.169 +	if((len = strlen(name)) > MAX_FNAME) {
   2.170 +		return -ENAMETOOLONG;
   2.171 +	}
   2.172 +	ent->ino = node->ino;
   2.173 +	memcpy(newent->name, name, len + 1);
   2.174 +
   2.175 +	/* find a place to put it */
   2.176 +	if(!(data = malloc(BLKSZ))) {
   2.177 +		return -ENOMEM;
   2.178 +	}
   2.179 +
   2.180 +	boffs = 0;
   2.181 +	while((bidx = file_block(fs, target, boffs)) > 0) {
   2.182 +		/* read the block, and search for an empty entry */
   2.183 +		blk_read(fs->bdev, bidx, 1, data);
   2.184 +
   2.185 +		/* for all directory entries in this block... */
   2.186 +		for(i=0; i<BLK_DIRENT; i++) {
   2.187 +			if(data[i].ino == 0) {
   2.188 +				/* found empty */
   2.189 +				memcpy(data + i, &ent, sizeof ent);
   2.190 +				goto success;
   2.191 +			}
   2.192 +		}
   2.193 +		boffs++;
   2.194 +	}
   2.195 +
   2.196 +	/* didn't find any free entries amongst our blocks, allocate a new one */
   2.197 +	if(!(bidx = alloc_file_block(fs, target, boffs))) {
   2.198 +		free(data);
   2.199 +		return -ENOSPC;
   2.200 +	}
   2.201 +	/* zero-fill the new block and add the first entry */
   2.202 +	memset(data, 0, BLKSZ);
   2.203 +	*data = ent;
   2.204 +
   2.205 +success:
   2.206 +	/* write to disk */
   2.207 +	blk_write(fs->bdev, bidx, 1, data);
   2.208 +	node->nlink++;	/* increase reference count */
   2.209 +
   2.210 +	free(data);
   2.211 +	return 0;
   2.212 +}
   2.213 +
   2.214 +
   2.215  static int read_superblock(struct filesys *fs)
   2.216  {
   2.217  	struct superblock *sb = fs->sb;
   2.218 @@ -123,12 +280,13 @@
   2.219  	if(blk_write(fs->bdev, sb->ibm_start, sb->ibm_count, sb->ibm) == -1) {
   2.220  		return -1;
   2.221  	}
   2.222 +	/* write the superblock itself */
   2.223 +	if(blk_write(fs->bdev, 1, 1, sb) == -1) {
   2.224 +		return -1;
   2.225 +	}
   2.226  	return 0;
   2.227  }
   2.228  
   2.229 -/* number of inodes in a block */
   2.230 -#define BLK_INODES		(BLKSZ / sizeof(struct inode))
   2.231 -
   2.232  /* copy the requested inode from the disk, into the buffer passed in the last arg */
   2.233  static int get_inode(struct filesys *fs, int ino, struct inode *inode)
   2.234  {
   2.235 @@ -164,21 +322,24 @@
   2.236  	return 0;
   2.237  }
   2.238  
   2.239 -static int find_free(uint32_t *bm, int sz)
   2.240 +/* find a free element in the bitmap and return its number */
   2.241 +static int find_free(uint32_t *bm, int nbits)
   2.242  {
   2.243 -	int i;
   2.244 -	uint32_t ent;
   2.245 +	int i, j, nwords = nbits / 32;
   2.246 +	uint32_t ent = 0;
   2.247  
   2.248 -	for(i=0; i<=sz/32; i++) {
   2.249 +	for(i=0; i<=nwords; i++) {
   2.250  		if(bm[i] != 0xffffffff) {
   2.251 -			ent = i * 32;
   2.252  			for(j=0; j<32; j++) {
   2.253  				if(BM_ISFREE(bm, ent)) {
   2.254  					return ent;
   2.255  				}
   2.256 +				ent++;
   2.257  			}
   2.258  
   2.259  			panic("shouldn't happen (in find_free:fs.c)");
   2.260 +		} else {
   2.261 +			ent += 32;
   2.262  		}
   2.263  	}
   2.264  
   2.265 @@ -189,9 +350,82 @@
   2.266  {
   2.267  	int ino;
   2.268  
   2.269 -	if((ino = find_free(fs->ibm, fs->ibm_count)) == -1) {
   2.270 +	if((ino = find_free(fs->sb->ibm, fs->sb->num_inodes)) == -1) {
   2.271  		return -1;
   2.272  	}
   2.273 -	BM_SET(fs->ibm, ino);
   2.274 +	BM_SET(fs->sb->ibm, ino);
   2.275  	return 0;
   2.276  }
   2.277 +
   2.278 +static void free_inode(struct filesys *fs, int ino)
   2.279 +{
   2.280 +	BM_CLR(fs->sb->ibm, ino);
   2.281 +}
   2.282 +
   2.283 +static int alloc_block(struct filesys *fs)
   2.284 +{
   2.285 +	int ino;
   2.286 +
   2.287 +	if((ino = find_free(fs->sb->bm, fs->sb->num_blocks)) == -1) {
   2.288 +		return -1;
   2.289 +	}
   2.290 +	BM_SET(fs->sb->bm, ino);
   2.291 +	return 0;
   2.292 +}
   2.293 +
   2.294 +static void free_block(struct filesys *fs, int ino)
   2.295 +{
   2.296 +	BM_CLR(fs->sb->bm, ino);
   2.297 +}
   2.298 +
   2.299 +#define BLK_BLKID	(BLKSZ / sizeof(blkid))
   2.300 +#define MAX_IND		(NDIRBLK + BLK_BLKID)
   2.301 +#define MAX_DIND	(MAX_IND + BLK_BLKID * BLK_BLKID)
   2.302 +
   2.303 +static int file_block(struct filesys *fs, struct inode *node, int boffs)
   2.304 +{
   2.305 +	int res, idx;
   2.306 +	blkid *barr;
   2.307 +
   2.308 +	/* is it a direct block ? */
   2.309 +	if(boffs < NDIRBLK) {
   2.310 +		return node->blk[boffs];
   2.311 +	}
   2.312 +
   2.313 +	barr = malloc(BLKSZ);
   2.314 +	assert(barr);
   2.315 +
   2.316 +	/* is it an indirect block ? */
   2.317 +	if(boffs < MAX_IND) {
   2.318 +		if(!node->ind) {
   2.319 +			res = 0;
   2.320 +			goto end;
   2.321 +		}
   2.322 +		blk_read(fs->bdev, node->ind, 1, barr);
   2.323 +		res = barr[boffs - NDIRBLK];
   2.324 +		goto end;
   2.325 +	}
   2.326 +
   2.327 +	/* is it a double-indirect block ? */
   2.328 +	if(boffs < MAX_DIND) {
   2.329 +		/* first read the dind block and find the index of the ind block */
   2.330 +		if(!node->dind) {
   2.331 +			res = 0;
   2.332 +			goto end;
   2.333 +		}
   2.334 +		blk_read(fd->bdev, node->dind, 1, barr);
   2.335 +		idx = (boffs - MAX_IND) / BLK_BLKID;
   2.336 +
   2.337 +		/* then read the ind block and find the index of the block */
   2.338 +		if(!barr[idx]) {
   2.339 +			res = 0;
   2.340 +			goto end;
   2.341 +		}
   2.342 +		blk_read(fd->bdev, barr[idx], 1, barr);
   2.343 +		res = barr[(boffs - MAX_IND) % BLK_BLKID];
   2.344 +	}
   2.345 +
   2.346 +end:
   2.347 +	free(barr);
   2.348 +	return res;
   2.349 +}
     3.1 --- a/src/fs.h	Sun Dec 11 21:15:35 2011 +0200
     3.2 +++ b/src/fs.h	Thu Dec 15 04:39:00 2011 +0200
     3.3 @@ -3,9 +3,12 @@
     3.4  
     3.5  #include <inttypes.h>
     3.6  
     3.7 -#define MAGIC	0xccf5ccf5
     3.8 -#define FS_VER	1
     3.9 -#define BLKSZ	1024
    3.10 +#define MAGIC		0xccf5ccf5
    3.11 +#define FS_VER		1
    3.12 +#define BLKSZ		1024
    3.13 +
    3.14 +#define NAME_MAX	27	/* +1 termin. +4 ino = 32 per dirent */
    3.15 +#define PATH_MAX	256
    3.16  
    3.17  #define SECT_TO_BLK(x)	((x) / (BLKSZ / 512))
    3.18  
    3.19 @@ -32,6 +35,10 @@
    3.20  	blkid dind;			/* double-indirect */
    3.21  } __attribute__((packed));
    3.22  
    3.23 +struct dir_entry {
    3.24 +	int ino;
    3.25 +	char name[NAME_MAX + 1];
    3.26 +} __attribute__((packed));
    3.27  
    3.28  struct superblock {
    3.29  	uint32_t magic;	/* magic number */
    3.30 @@ -74,6 +81,7 @@
    3.31  
    3.32  /* defined in fs.c */
    3.33  int openfs(struct filesys *fs, dev_t dev);
    3.34 +int mkfs(struct filesys *fs, dev_t dev);
    3.35  void closefs(struct filesys *fs);
    3.36  int find_inode(const char *path);
    3.37  
     4.1 --- a/src/proc.c	Sun Dec 11 21:15:35 2011 +0200
     4.2 +++ b/src/proc.c	Thu Dec 15 04:39:00 2011 +0200
     4.3 @@ -77,6 +77,8 @@
     4.4  	p->id = 1;
     4.5  	p->parent = 0;	/* no parent for init */
     4.6  
     4.7 +	p->umask = 022;
     4.8 +
     4.9  	p->ticks_left = TIMESLICE_TICKS;
    4.10  	p->next = p->prev = 0;
    4.11  
    4.12 @@ -168,6 +170,8 @@
    4.13  	/* copy file table */
    4.14  	memcpy(p->files, parent->files, sizeof p->files);
    4.15  
    4.16 +	p->umask = parent->umask;
    4.17 +
    4.18  	/* allocate a kernel stack for the new process */
    4.19  	if((p->kern_stack_pg = pgalloc(KERN_STACK_SIZE / PGSIZE, MEM_KERNEL)) == -1) {
    4.20  		return -EAGAIN;
     5.1 --- a/src/proc.h	Sun Dec 11 21:15:35 2011 +0200
     5.2 +++ b/src/proc.h	Thu Dec 15 04:39:00 2011 +0200
     5.3 @@ -51,6 +51,8 @@
     5.4  	/* open files */
     5.5  	struct file files[MAX_FD];
     5.6  
     5.7 +	unsigned int umask;
     5.8 +
     5.9  	struct process *child_list;
    5.10  
    5.11  	struct process *next, *prev;	/* for the scheduler queues */