kern
diff src/fs.c @ 96:07fe6a614185
filesystem
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 15 Dec 2011 04:39:00 +0200 |
parents | ec62cbe00b55 |
children | 8717eb590727 |
line diff
1.1 --- a/src/fs.c Sun Dec 11 21:15:35 2011 +0200 1.2 +++ b/src/fs.c Thu Dec 15 04:39:00 2011 +0200 1.3 @@ -1,7 +1,4 @@ 1.4 -/* This code is used by the kernel AND by userspace filesystem-related tools. 1.5 - * The kernel-specific parts are conditionally compiled in #ifdef KERNEL blocks 1.6 - * the rest of the code should be independent. 1.7 - */ 1.8 +/* This code is used by the kernel AND by userspace filesystem-related tools. */ 1.9 #include <stdio.h> 1.10 #include <stdlib.h> 1.11 #include <string.h> 1.12 @@ -9,6 +6,14 @@ 1.13 #include <assert.h> 1.14 #include "fs.h" 1.15 #include "bdev.h" 1.16 +#include "kdef.h" 1.17 + 1.18 +/* number of inodes in a block */ 1.19 +#define BLK_INODES (BLKSZ / sizeof(struct inode)) 1.20 +/* number of directory entries in a block */ 1.21 +#define BLK_DIRENT (BLKSZ / sizeof(struct dir_entry)) 1.22 + 1.23 +#define BLKBITS (BLKSZ * 8) 1.24 1.25 #define BM_IDX(x) ((x) / 32) 1.26 #define BM_BIT(x) ((x) & 0x1f) 1.27 @@ -18,11 +23,18 @@ 1.28 #define BM_CLR(bm, x) ((bm)[BM_IDX(x)] &= ~(1 << BM_BIT(x))) 1.29 1.30 1.31 -int openfs(struct filesys *fs, dev_t dev); 1.32 +static struct inode *newdir(struct filesys *fs, struct inode *parent); 1.33 +static int addlink(struct filesys *fs, struct inode *target, struct inode *node, const char *name); 1.34 static int read_superblock(struct filesys *fs); 1.35 static int write_superblock(struct filesys *fs); 1.36 static int get_inode(struct filesys *fs, int ino, struct inode *inode); 1.37 static int put_inode(struct filesys *fs, struct inode *inode); 1.38 +static int find_free(uint32_t *bm, int sz); 1.39 +static int alloc_inode(struct filesys *fs); 1.40 +static void free_inode(struct filesys *fs, int ino); 1.41 +static int alloc_block(struct filesys *fs); 1.42 +static void free_block(struct filesys *fs, int ino); 1.43 +static int file_block(struct filesys *fs, struct inode *node, int boffs); 1.44 1.45 int openfs(struct filesys *fs, dev_t dev) 1.46 { 1.47 @@ -38,19 +50,164 @@ 1.48 1.49 /* read the superblock */ 1.50 if(!(fs->sb = malloc(BLKSZ))) { 1.51 - res = -ENOMEM; 1.52 - goto done; 1.53 + blk_close(bdev); 1.54 + return -ENOMEM; 1.55 } 1.56 if((res = read_superblock(fs)) != 0) { 1.57 - goto done; 1.58 + blk_close(bdev); 1.59 + return res; 1.60 } 1.61 1.62 + return 0; 1.63 +} 1.64 1.65 -done: 1.66 - blk_close(bdev); 1.67 - return res; 1.68 +int mkfs(struct filesys *fs, dev_t dev) 1.69 +{ 1.70 + struct filesys *fs; 1.71 + struct superblock *sb; 1.72 + struct block_device *bdev; 1.73 + int i, bcount; 1.74 + 1.75 + if(!(bdev = blk_open(dev))) { 1.76 + return -1; 1.77 + } 1.78 + fs->bdev = bdev; 1.79 + 1.80 + if(!(sb = malloc(BLKSZ))) { 1.81 + blk_close(bdev); 1.82 + return -1; 1.83 + } 1.84 + fs->sb = sb; 1.85 + 1.86 + /* populate the superblock */ 1.87 + sb->magic = MAGIC; 1.88 + sb->ver = FS_VER; 1.89 + sb->blksize = BLKSZ; 1.90 + 1.91 + sb->num_blocks = bdev->size; 1.92 + sb->num_inodes = sb->num_blocks / 4; 1.93 + 1.94 + /* inode bitmap just after the superblock */ 1.95 + sb->ibm_start = 2; 1.96 + sb->ibm_count = (sb->num_inodes + BLKBITS - 1) / BLKBITS; 1.97 + /* also allocate and initialize in-memory inode bitmap */ 1.98 + sb->ibm = malloc(sb->ibm_count * BLKSZ); 1.99 + assert(sb->ibm); 1.100 + memset(sb->ibm, 0, sb->ibm_count * BLKSZ); 1.101 + 1.102 + /* XXX mark inode 0 as used always */ 1.103 + BM_SET(sb->ibm, 0); 1.104 + 1.105 + /* block bitmap just after the inode bitmap */ 1.106 + sb->bm_start = sb->ibm_start + sb->ibm_count; 1.107 + sb->bm_count = (sb->num_blocks + BLKBITS - 1) / BLKBITS; 1.108 + /* also allocate and initialize in-memory block bitmap */ 1.109 + sb->bm = malloc(sb->bm_count * BLKSZ); 1.110 + assert(sb->bm); 1.111 + memset(sb->bm, 0, sb->bm_count * BLKSZ); 1.112 + 1.113 + /* inode table, just after the block bitmap */ 1.114 + sb->itbl_start = sb->bm_start + sb->bm_count; 1.115 + sb->itbl_count = (sb->num_inodes * sizeof(struct inode) + BLKSZ - 1) / BLKSZ; 1.116 + 1.117 + /* mark all used blocks as used */ 1.118 + bcount = sb->itbl_start + sb->itbl_count; 1.119 + memset(sb->bm, 0xff, bcount / 8); 1.120 + for(i=0; i<bcount % 8; i++) { 1.121 + int bit = bcount / 8 + i; 1.122 + BM_SET(sb->bm, bit); 1.123 + } 1.124 + 1.125 + /* create the root directory */ 1.126 + sb->root = newdir(fs, 0); 1.127 + sb->root_ino = sb->root->ino; 1.128 } 1.129 1.130 +static struct inode *newdir(struct filesys *fs, struct inode *parent) 1.131 +{ 1.132 + struct inode *dirnode; 1.133 + 1.134 + /* allocate and initialize inode */ 1.135 + if(!(dirnode = malloc(sizeof *dirnode))) { 1.136 + return 0; 1.137 + } 1.138 + memset(dirnode, 0, sizeof *dirnode); 1.139 + 1.140 + if((dirnode->ino = alloc_inode(fs)) == -1) { 1.141 + printf("failed to allocate inode for a new directory\n"); 1.142 + free(dirnode); 1.143 + return 0; 1.144 + } 1.145 + dirnode->mode = S_IFDIR; 1.146 + 1.147 + /* add . and .. links */ 1.148 + addlink(fs, dirnode, dirnode, "."); 1.149 + addlink(fs, dirnode, parent ? parent : dirnode, ".."); 1.150 + 1.151 + /* and write the inode to disk */ 1.152 + put_inode(fs, dirnode); 1.153 + return dirnode; 1.154 +} 1.155 + 1.156 +static int addlink(struct filesys *fs, struct inode *target, struct inode *node, const char *name) 1.157 +{ 1.158 + struct dir_entry ent, *data; 1.159 + int boffs, bidx, len; 1.160 + 1.161 + if(!(target->mode & S_IFDIR)) { 1.162 + return -ENOTDIR; 1.163 + } 1.164 + if(node->mode & S_IFDIR) { 1.165 + return -EPERM; 1.166 + } 1.167 + /* TODO check that the link does not already exist (EEXIST) */ 1.168 + 1.169 + if((len = strlen(name)) > MAX_FNAME) { 1.170 + return -ENAMETOOLONG; 1.171 + } 1.172 + ent->ino = node->ino; 1.173 + memcpy(newent->name, name, len + 1); 1.174 + 1.175 + /* find a place to put it */ 1.176 + if(!(data = malloc(BLKSZ))) { 1.177 + return -ENOMEM; 1.178 + } 1.179 + 1.180 + boffs = 0; 1.181 + while((bidx = file_block(fs, target, boffs)) > 0) { 1.182 + /* read the block, and search for an empty entry */ 1.183 + blk_read(fs->bdev, bidx, 1, data); 1.184 + 1.185 + /* for all directory entries in this block... */ 1.186 + for(i=0; i<BLK_DIRENT; i++) { 1.187 + if(data[i].ino == 0) { 1.188 + /* found empty */ 1.189 + memcpy(data + i, &ent, sizeof ent); 1.190 + goto success; 1.191 + } 1.192 + } 1.193 + boffs++; 1.194 + } 1.195 + 1.196 + /* didn't find any free entries amongst our blocks, allocate a new one */ 1.197 + if(!(bidx = alloc_file_block(fs, target, boffs))) { 1.198 + free(data); 1.199 + return -ENOSPC; 1.200 + } 1.201 + /* zero-fill the new block and add the first entry */ 1.202 + memset(data, 0, BLKSZ); 1.203 + *data = ent; 1.204 + 1.205 +success: 1.206 + /* write to disk */ 1.207 + blk_write(fs->bdev, bidx, 1, data); 1.208 + node->nlink++; /* increase reference count */ 1.209 + 1.210 + free(data); 1.211 + return 0; 1.212 +} 1.213 + 1.214 + 1.215 static int read_superblock(struct filesys *fs) 1.216 { 1.217 struct superblock *sb = fs->sb; 1.218 @@ -123,12 +280,13 @@ 1.219 if(blk_write(fs->bdev, sb->ibm_start, sb->ibm_count, sb->ibm) == -1) { 1.220 return -1; 1.221 } 1.222 + /* write the superblock itself */ 1.223 + if(blk_write(fs->bdev, 1, 1, sb) == -1) { 1.224 + return -1; 1.225 + } 1.226 return 0; 1.227 } 1.228 1.229 -/* number of inodes in a block */ 1.230 -#define BLK_INODES (BLKSZ / sizeof(struct inode)) 1.231 - 1.232 /* copy the requested inode from the disk, into the buffer passed in the last arg */ 1.233 static int get_inode(struct filesys *fs, int ino, struct inode *inode) 1.234 { 1.235 @@ -164,21 +322,24 @@ 1.236 return 0; 1.237 } 1.238 1.239 -static int find_free(uint32_t *bm, int sz) 1.240 +/* find a free element in the bitmap and return its number */ 1.241 +static int find_free(uint32_t *bm, int nbits) 1.242 { 1.243 - int i; 1.244 - uint32_t ent; 1.245 + int i, j, nwords = nbits / 32; 1.246 + uint32_t ent = 0; 1.247 1.248 - for(i=0; i<=sz/32; i++) { 1.249 + for(i=0; i<=nwords; i++) { 1.250 if(bm[i] != 0xffffffff) { 1.251 - ent = i * 32; 1.252 for(j=0; j<32; j++) { 1.253 if(BM_ISFREE(bm, ent)) { 1.254 return ent; 1.255 } 1.256 + ent++; 1.257 } 1.258 1.259 panic("shouldn't happen (in find_free:fs.c)"); 1.260 + } else { 1.261 + ent += 32; 1.262 } 1.263 } 1.264 1.265 @@ -189,9 +350,82 @@ 1.266 { 1.267 int ino; 1.268 1.269 - if((ino = find_free(fs->ibm, fs->ibm_count)) == -1) { 1.270 + if((ino = find_free(fs->sb->ibm, fs->sb->num_inodes)) == -1) { 1.271 return -1; 1.272 } 1.273 - BM_SET(fs->ibm, ino); 1.274 + BM_SET(fs->sb->ibm, ino); 1.275 return 0; 1.276 } 1.277 + 1.278 +static void free_inode(struct filesys *fs, int ino) 1.279 +{ 1.280 + BM_CLR(fs->sb->ibm, ino); 1.281 +} 1.282 + 1.283 +static int alloc_block(struct filesys *fs) 1.284 +{ 1.285 + int ino; 1.286 + 1.287 + if((ino = find_free(fs->sb->bm, fs->sb->num_blocks)) == -1) { 1.288 + return -1; 1.289 + } 1.290 + BM_SET(fs->sb->bm, ino); 1.291 + return 0; 1.292 +} 1.293 + 1.294 +static void free_block(struct filesys *fs, int ino) 1.295 +{ 1.296 + BM_CLR(fs->sb->bm, ino); 1.297 +} 1.298 + 1.299 +#define BLK_BLKID (BLKSZ / sizeof(blkid)) 1.300 +#define MAX_IND (NDIRBLK + BLK_BLKID) 1.301 +#define MAX_DIND (MAX_IND + BLK_BLKID * BLK_BLKID) 1.302 + 1.303 +static int file_block(struct filesys *fs, struct inode *node, int boffs) 1.304 +{ 1.305 + int res, idx; 1.306 + blkid *barr; 1.307 + 1.308 + /* is it a direct block ? */ 1.309 + if(boffs < NDIRBLK) { 1.310 + return node->blk[boffs]; 1.311 + } 1.312 + 1.313 + barr = malloc(BLKSZ); 1.314 + assert(barr); 1.315 + 1.316 + /* is it an indirect block ? */ 1.317 + if(boffs < MAX_IND) { 1.318 + if(!node->ind) { 1.319 + res = 0; 1.320 + goto end; 1.321 + } 1.322 + blk_read(fs->bdev, node->ind, 1, barr); 1.323 + res = barr[boffs - NDIRBLK]; 1.324 + goto end; 1.325 + } 1.326 + 1.327 + /* is it a double-indirect block ? */ 1.328 + if(boffs < MAX_DIND) { 1.329 + /* first read the dind block and find the index of the ind block */ 1.330 + if(!node->dind) { 1.331 + res = 0; 1.332 + goto end; 1.333 + } 1.334 + blk_read(fd->bdev, node->dind, 1, barr); 1.335 + idx = (boffs - MAX_IND) / BLK_BLKID; 1.336 + 1.337 + /* then read the ind block and find the index of the block */ 1.338 + if(!barr[idx]) { 1.339 + res = 0; 1.340 + goto end; 1.341 + } 1.342 + blk_read(fd->bdev, barr[idx], 1, barr); 1.343 + res = barr[(boffs - MAX_IND) % BLK_BLKID]; 1.344 + } 1.345 + 1.346 +end: 1.347 + free(barr); 1.348 + return res; 1.349 +}