kern

annotate src/fs.c @ 97:8717eb590727

ok stopping with the filesystem to manage to write the article in time
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 17 Dec 2011 14:09:17 +0200
parents 07fe6a614185
children
rev   line source
nuclear@96 1 /* This code is used by the kernel AND by userspace filesystem-related tools. */
nuclear@97 2
nuclear@97 3 /* XXX convention:
nuclear@97 4 * - functions that accept or return a struct inode, do not read/write it to disk
nuclear@97 5 * - functions that accept or return an int ino, do read/write it to disk
nuclear@97 6 * other kinds of blocks (data, indirect, etc) always hit the disk directly.
nuclear@97 7 */
nuclear@97 8
nuclear@88 9 #include <stdio.h>
nuclear@89 10 #include <stdlib.h>
nuclear@94 11 #include <string.h>
nuclear@90 12 #include <errno.h>
nuclear@94 13 #include <assert.h>
nuclear@88 14 #include "fs.h"
nuclear@93 15 #include "bdev.h"
nuclear@96 16 #include "kdef.h"
nuclear@96 17
nuclear@96 18 /* number of inodes in a block */
nuclear@96 19 #define BLK_INODES (BLKSZ / sizeof(struct inode))
nuclear@96 20 /* number of directory entries in a block */
nuclear@96 21 #define BLK_DIRENT (BLKSZ / sizeof(struct dir_entry))
nuclear@96 22
nuclear@96 23 #define BLKBITS (BLKSZ * 8)
nuclear@90 24
nuclear@95 25 #define BM_IDX(x) ((x) / 32)
nuclear@95 26 #define BM_BIT(x) ((x) & 0x1f)
nuclear@95 27
nuclear@95 28 #define BM_ISFREE(bm, x) (((bm)[BM_IDX(x)] & (1 << BM_BIT(x))) == 0)
nuclear@95 29 #define BM_SET(bm, x) ((bm)[BM_IDX(x)] |= (1 << BM_BIT(x)))
nuclear@95 30 #define BM_CLR(bm, x) ((bm)[BM_IDX(x)] &= ~(1 << BM_BIT(x)))
nuclear@95 31
nuclear@89 32
nuclear@96 33 static struct inode *newdir(struct filesys *fs, struct inode *parent);
nuclear@96 34 static int addlink(struct filesys *fs, struct inode *target, struct inode *node, const char *name);
nuclear@94 35 static int read_superblock(struct filesys *fs);
nuclear@94 36 static int write_superblock(struct filesys *fs);
nuclear@94 37 static int get_inode(struct filesys *fs, int ino, struct inode *inode);
nuclear@94 38 static int put_inode(struct filesys *fs, struct inode *inode);
nuclear@96 39 static int find_free(uint32_t *bm, int sz);
nuclear@96 40 static int alloc_inode(struct filesys *fs);
nuclear@97 41 #define free_inode(fs, ino) BM_CLR((fs)->sb->ibm, (ino))
nuclear@96 42 static int alloc_block(struct filesys *fs);
nuclear@97 43 #define free_block(fs, bno) BM_CLR((fs)->sb->bm, (bno))
nuclear@97 44 #define zero_block(fs, bno) \
nuclear@97 45 do { \
nuclear@97 46 assert(bno > 0); \
nuclear@97 47 blk_write((fs)->bdev, (bno), 1, (fs)->zeroblock); \
nuclear@97 48 } while(0)
nuclear@97 49
nuclear@97 50 static int file_block(struct filesys *fs, struct inode *node, int boffs, int allocate);
nuclear@97 51 #define get_file_block(fs, node, boffs) file_block(fs, node, boffs, 0)
nuclear@97 52 #define alloc_file_block(fs, node, boffs) file_block(fs, node, boffs, 1)
nuclear@97 53
nuclear@90 54
nuclear@93 55 int openfs(struct filesys *fs, dev_t dev)
nuclear@93 56 {
nuclear@93 57 int res;
nuclear@93 58 struct block_device *bdev;
nuclear@94 59
nuclear@94 60 assert(BLKSZ % sizeof(struct inode) == 0);
nuclear@89 61
nuclear@93 62 if(!(bdev = blk_open(dev))) {
nuclear@93 63 return -ENOENT;
nuclear@90 64 }
nuclear@94 65 fs->bdev = bdev;
nuclear@90 66
nuclear@93 67 /* read the superblock */
nuclear@94 68 if(!(fs->sb = malloc(BLKSZ))) {
nuclear@96 69 blk_close(bdev);
nuclear@96 70 return -ENOMEM;
nuclear@93 71 }
nuclear@94 72 if((res = read_superblock(fs)) != 0) {
nuclear@96 73 blk_close(bdev);
nuclear@96 74 return res;
nuclear@93 75 }
nuclear@90 76
nuclear@97 77 /* allocate the zero-block buffer written to zero-out blocks */
nuclear@97 78 if(!(fs->zeroblock = malloc(fs->sb->blksize))) {
nuclear@97 79 blk_close(bdev);
nuclear@97 80 free(fs->sb->ibm);
nuclear@97 81 free(fs->sb->bm);
nuclear@97 82 free(fs->sb->root);
nuclear@97 83 return -ENOMEM;
nuclear@97 84 }
nuclear@97 85 memset(fs->zeroblock, 0xff, fs->sb->blksize);
nuclear@97 86
nuclear@96 87 return 0;
nuclear@96 88 }
nuclear@93 89
nuclear@96 90 int mkfs(struct filesys *fs, dev_t dev)
nuclear@96 91 {
nuclear@96 92 struct superblock *sb;
nuclear@96 93 struct block_device *bdev;
nuclear@96 94 int i, bcount;
nuclear@96 95
nuclear@96 96 if(!(bdev = blk_open(dev))) {
nuclear@96 97 return -1;
nuclear@96 98 }
nuclear@96 99 fs->bdev = bdev;
nuclear@96 100
nuclear@96 101 if(!(sb = malloc(BLKSZ))) {
nuclear@96 102 blk_close(bdev);
nuclear@96 103 return -1;
nuclear@96 104 }
nuclear@96 105 fs->sb = sb;
nuclear@96 106
nuclear@96 107 /* populate the superblock */
nuclear@96 108 sb->magic = MAGIC;
nuclear@96 109 sb->ver = FS_VER;
nuclear@96 110 sb->blksize = BLKSZ;
nuclear@96 111
nuclear@96 112 sb->num_blocks = bdev->size;
nuclear@96 113 sb->num_inodes = sb->num_blocks / 4;
nuclear@96 114
nuclear@96 115 /* inode bitmap just after the superblock */
nuclear@96 116 sb->ibm_start = 2;
nuclear@96 117 sb->ibm_count = (sb->num_inodes + BLKBITS - 1) / BLKBITS;
nuclear@96 118 /* also allocate and initialize in-memory inode bitmap */
nuclear@96 119 sb->ibm = malloc(sb->ibm_count * BLKSZ);
nuclear@96 120 assert(sb->ibm);
nuclear@96 121 memset(sb->ibm, 0, sb->ibm_count * BLKSZ);
nuclear@96 122
nuclear@96 123 /* XXX mark inode 0 as used always */
nuclear@96 124 BM_SET(sb->ibm, 0);
nuclear@96 125
nuclear@96 126 /* block bitmap just after the inode bitmap */
nuclear@96 127 sb->bm_start = sb->ibm_start + sb->ibm_count;
nuclear@96 128 sb->bm_count = (sb->num_blocks + BLKBITS - 1) / BLKBITS;
nuclear@96 129 /* also allocate and initialize in-memory block bitmap */
nuclear@96 130 sb->bm = malloc(sb->bm_count * BLKSZ);
nuclear@96 131 assert(sb->bm);
nuclear@96 132 memset(sb->bm, 0, sb->bm_count * BLKSZ);
nuclear@96 133
nuclear@96 134 /* inode table, just after the block bitmap */
nuclear@96 135 sb->itbl_start = sb->bm_start + sb->bm_count;
nuclear@96 136 sb->itbl_count = (sb->num_inodes * sizeof(struct inode) + BLKSZ - 1) / BLKSZ;
nuclear@96 137
nuclear@96 138 /* mark all used blocks as used */
nuclear@96 139 bcount = sb->itbl_start + sb->itbl_count;
nuclear@96 140 memset(sb->bm, 0xff, bcount / 8);
nuclear@96 141 for(i=0; i<bcount % 8; i++) {
nuclear@96 142 int bit = bcount / 8 + i;
nuclear@96 143 BM_SET(sb->bm, bit);
nuclear@96 144 }
nuclear@96 145
nuclear@96 146 /* create the root directory */
nuclear@96 147 sb->root = newdir(fs, 0);
nuclear@96 148 sb->root_ino = sb->root->ino;
nuclear@97 149 /* and write the inode to disk */
nuclear@97 150 put_inode(fs, sb->root);
nuclear@97 151
nuclear@97 152 return 0;
nuclear@90 153 }
nuclear@88 154
nuclear@96 155 static struct inode *newdir(struct filesys *fs, struct inode *parent)
nuclear@96 156 {
nuclear@96 157 struct inode *dirnode;
nuclear@96 158
nuclear@96 159 /* allocate and initialize inode */
nuclear@96 160 if(!(dirnode = malloc(sizeof *dirnode))) {
nuclear@96 161 return 0;
nuclear@96 162 }
nuclear@96 163 memset(dirnode, 0, sizeof *dirnode);
nuclear@96 164
nuclear@96 165 if((dirnode->ino = alloc_inode(fs)) == -1) {
nuclear@96 166 printf("failed to allocate inode for a new directory\n");
nuclear@96 167 free(dirnode);
nuclear@96 168 return 0;
nuclear@96 169 }
nuclear@96 170 dirnode->mode = S_IFDIR;
nuclear@96 171
nuclear@96 172 /* add . and .. links */
nuclear@96 173 addlink(fs, dirnode, dirnode, ".");
nuclear@96 174 addlink(fs, dirnode, parent ? parent : dirnode, "..");
nuclear@96 175
nuclear@96 176 return dirnode;
nuclear@96 177 }
nuclear@96 178
nuclear@96 179 static int addlink(struct filesys *fs, struct inode *target, struct inode *node, const char *name)
nuclear@96 180 {
nuclear@96 181 struct dir_entry ent, *data;
nuclear@97 182 int i, boffs, bidx, len;
nuclear@96 183
nuclear@96 184 if(!(target->mode & S_IFDIR)) {
nuclear@96 185 return -ENOTDIR;
nuclear@96 186 }
nuclear@96 187 if(node->mode & S_IFDIR) {
nuclear@96 188 return -EPERM;
nuclear@96 189 }
nuclear@96 190 /* TODO check that the link does not already exist (EEXIST) */
nuclear@96 191
nuclear@97 192 if((len = strlen(name)) > NAME_MAX) {
nuclear@96 193 return -ENAMETOOLONG;
nuclear@96 194 }
nuclear@97 195 ent.ino = node->ino;
nuclear@97 196 memcpy(ent.name, name, len + 1);
nuclear@96 197
nuclear@96 198 /* find a place to put it */
nuclear@96 199 if(!(data = malloc(BLKSZ))) {
nuclear@96 200 return -ENOMEM;
nuclear@96 201 }
nuclear@96 202
nuclear@96 203 boffs = 0;
nuclear@97 204 while((bidx = get_file_block(fs, target, boffs)) > 0) {
nuclear@96 205 /* read the block, and search for an empty entry */
nuclear@96 206 blk_read(fs->bdev, bidx, 1, data);
nuclear@96 207
nuclear@96 208 /* for all directory entries in this block... */
nuclear@96 209 for(i=0; i<BLK_DIRENT; i++) {
nuclear@96 210 if(data[i].ino == 0) {
nuclear@96 211 /* found empty */
nuclear@96 212 memcpy(data + i, &ent, sizeof ent);
nuclear@96 213 goto success;
nuclear@96 214 }
nuclear@96 215 }
nuclear@96 216 boffs++;
nuclear@96 217 }
nuclear@96 218
nuclear@96 219 /* didn't find any free entries amongst our blocks, allocate a new one */
nuclear@96 220 if(!(bidx = alloc_file_block(fs, target, boffs))) {
nuclear@96 221 free(data);
nuclear@96 222 return -ENOSPC;
nuclear@96 223 }
nuclear@96 224 /* zero-fill the new block and add the first entry */
nuclear@96 225 memset(data, 0, BLKSZ);
nuclear@96 226 *data = ent;
nuclear@96 227
nuclear@96 228 success:
nuclear@96 229 /* write to disk */
nuclear@96 230 blk_write(fs->bdev, bidx, 1, data);
nuclear@96 231 node->nlink++; /* increase reference count */
nuclear@96 232
nuclear@96 233 free(data);
nuclear@96 234 return 0;
nuclear@96 235 }
nuclear@96 236
nuclear@96 237
nuclear@94 238 static int read_superblock(struct filesys *fs)
nuclear@88 239 {
nuclear@94 240 struct superblock *sb = fs->sb;
nuclear@94 241
nuclear@93 242 /* read superblock and verify */
nuclear@94 243 if(blk_read(fs->bdev, 1, 1, sb) == -1) {
nuclear@93 244 printf("failed to read superblock\n");
nuclear@93 245 return -EIO;
nuclear@93 246 }
nuclear@93 247 if(sb->magic != MAGIC) {
nuclear@93 248 printf("invalid magic\n");
nuclear@93 249 return -EINVAL;
nuclear@93 250 }
nuclear@93 251 if(sb->ver > FS_VER) {
nuclear@93 252 printf("invalid version: %d\n", sb->ver);
nuclear@93 253 return -EINVAL;
nuclear@93 254 }
nuclear@93 255 if(sb->blksize != BLKSZ) {
nuclear@93 256 printf("invalid block size: %d\n", sb->blksize);
nuclear@93 257 return -EINVAL;
nuclear@93 258 }
nuclear@89 259
nuclear@93 260 /* allocate and populate in-memory bitmaps */
nuclear@93 261 if(!(sb->ibm = malloc(sb->ibm_count * sb->blksize))) {
nuclear@93 262 return -ENOMEM;
nuclear@88 263 }
nuclear@94 264 if(blk_read(fs->bdev, sb->ibm_start, sb->ibm_count, sb->ibm) == -1) {
nuclear@93 265 printf("failed to read inode bitmap\n");
nuclear@93 266 free(sb->ibm);
nuclear@93 267 return -EIO;
nuclear@93 268 }
nuclear@93 269 if(!(sb->bm = malloc(sb->bm_count * sb->blksize))) {
nuclear@93 270 free(sb->ibm);
nuclear@93 271 return -ENOMEM;
nuclear@93 272 }
nuclear@94 273 if(blk_read(fs->bdev, sb->bm_start, sb->bm_count, sb->bm) == -1) {
nuclear@93 274 printf("failed to read block bitmap\n");
nuclear@93 275 free(sb->ibm);
nuclear@93 276 free(sb->bm);
nuclear@93 277 return -EIO;
nuclear@93 278 }
nuclear@93 279
nuclear@94 280 /* read the root inode */
nuclear@94 281 if(!(sb->root = malloc(sizeof *sb->root))) {
nuclear@94 282 free(sb->ibm);
nuclear@94 283 free(sb->bm);
nuclear@94 284 return -ENOMEM;
nuclear@94 285 }
nuclear@94 286 if(get_inode(fs, sb->root_ino, sb->root) == -1) {
nuclear@94 287 printf("failed to read root inode\n");
nuclear@94 288 return -1;
nuclear@94 289 }
nuclear@94 290
nuclear@93 291 return 0;
nuclear@88 292 }
nuclear@94 293
nuclear@94 294 static int write_superblock(struct filesys *fs)
nuclear@94 295 {
nuclear@94 296 struct superblock *sb = fs->sb;
nuclear@94 297
nuclear@94 298 /* write back any changes in the root inode */
nuclear@94 299 if(put_inode(fs, sb->root) == -1) {
nuclear@94 300 return -1;
nuclear@94 301 }
nuclear@94 302 /* write back the block bitmap */
nuclear@94 303 if(blk_write(fs->bdev, sb->bm_start, sb->bm_count, sb->bm) == -1) {
nuclear@94 304 return -1;
nuclear@94 305 }
nuclear@94 306 /* write back the inode bitmap */
nuclear@94 307 if(blk_write(fs->bdev, sb->ibm_start, sb->ibm_count, sb->ibm) == -1) {
nuclear@94 308 return -1;
nuclear@94 309 }
nuclear@96 310 /* write the superblock itself */
nuclear@96 311 if(blk_write(fs->bdev, 1, 1, sb) == -1) {
nuclear@96 312 return -1;
nuclear@96 313 }
nuclear@94 314 return 0;
nuclear@94 315 }
nuclear@94 316
nuclear@94 317 /* copy the requested inode from the disk, into the buffer passed in the last arg */
nuclear@94 318 static int get_inode(struct filesys *fs, int ino, struct inode *inode)
nuclear@94 319 {
nuclear@94 320 struct inode *buf = malloc(BLKSZ);
nuclear@94 321 assert(buf);
nuclear@94 322
nuclear@94 323 if(blk_read(fs->bdev, fs->sb->itbl_start + ino / BLK_INODES, 1, buf) == -1) {
nuclear@94 324 free(buf);
nuclear@94 325 return -1;
nuclear@94 326 }
nuclear@94 327 memcpy(inode, buf + ino % BLK_INODES, sizeof *inode);
nuclear@94 328 free(buf);
nuclear@94 329 return 0;
nuclear@94 330 }
nuclear@94 331
nuclear@94 332 /* write the inode to the disk */
nuclear@94 333 static int put_inode(struct filesys *fs, struct inode *inode)
nuclear@94 334 {
nuclear@94 335 struct inode *buf = malloc(BLKSZ);
nuclear@94 336 assert(buf);
nuclear@94 337
nuclear@94 338 if(blk_read(fs->bdev, fs->sb->itbl_start + inode->ino / BLK_INODES, 1, buf) == -1) {
nuclear@94 339 free(buf);
nuclear@94 340 return -1;
nuclear@94 341 }
nuclear@94 342 memcpy(buf + inode->ino % BLK_INODES, inode, sizeof *inode);
nuclear@94 343
nuclear@94 344 if(blk_write(fs->bdev, fs->sb->itbl_start + inode->ino / BLK_INODES, 1, buf) == -1) {
nuclear@94 345 free(buf);
nuclear@94 346 return -1;
nuclear@94 347 }
nuclear@94 348 free(buf);
nuclear@94 349 return 0;
nuclear@94 350 }
nuclear@95 351
nuclear@96 352 /* find a free element in the bitmap and return its number */
nuclear@96 353 static int find_free(uint32_t *bm, int nbits)
nuclear@95 354 {
nuclear@96 355 int i, j, nwords = nbits / 32;
nuclear@96 356 uint32_t ent = 0;
nuclear@95 357
nuclear@96 358 for(i=0; i<=nwords; i++) {
nuclear@95 359 if(bm[i] != 0xffffffff) {
nuclear@95 360 for(j=0; j<32; j++) {
nuclear@95 361 if(BM_ISFREE(bm, ent)) {
nuclear@95 362 return ent;
nuclear@95 363 }
nuclear@96 364 ent++;
nuclear@95 365 }
nuclear@95 366
nuclear@95 367 panic("shouldn't happen (in find_free:fs.c)");
nuclear@96 368 } else {
nuclear@96 369 ent += 32;
nuclear@95 370 }
nuclear@95 371 }
nuclear@95 372
nuclear@95 373 return -1;
nuclear@95 374 }
nuclear@95 375
nuclear@95 376 static int alloc_inode(struct filesys *fs)
nuclear@95 377 {
nuclear@95 378 int ino;
nuclear@95 379
nuclear@96 380 if((ino = find_free(fs->sb->ibm, fs->sb->num_inodes)) == -1) {
nuclear@95 381 return -1;
nuclear@95 382 }
nuclear@96 383 BM_SET(fs->sb->ibm, ino);
nuclear@95 384 return 0;
nuclear@95 385 }
nuclear@96 386
nuclear@96 387 static int alloc_block(struct filesys *fs)
nuclear@96 388 {
nuclear@97 389 int bno;
nuclear@96 390
nuclear@97 391 if((bno = find_free(fs->sb->bm, fs->sb->num_blocks)) == -1) {
nuclear@96 392 return -1;
nuclear@96 393 }
nuclear@97 394 BM_SET(fs->sb->bm, bno);
nuclear@96 395 return 0;
nuclear@96 396 }
nuclear@96 397
nuclear@96 398 #define BLK_BLKID (BLKSZ / sizeof(blkid))
nuclear@96 399 #define MAX_IND (NDIRBLK + BLK_BLKID)
nuclear@96 400 #define MAX_DIND (MAX_IND + BLK_BLKID * BLK_BLKID)
nuclear@96 401
nuclear@97 402 static int file_block(struct filesys *fs, struct inode *node, int boffs, int allocate)
nuclear@96 403 {
nuclear@97 404 int res, idx, node_dirty = 0;
nuclear@96 405 blkid *barr;
nuclear@96 406
nuclear@97 407 /* out of bounds */
nuclear@97 408 if(boffs < 0 || boffs >= MAX_DIND) {
nuclear@97 409 return 0;
nuclear@97 410 }
nuclear@97 411
nuclear@96 412 /* is it a direct block ? */
nuclear@96 413 if(boffs < NDIRBLK) {
nuclear@97 414 if(!(res = node->blk[boffs]) && allocate) {
nuclear@97 415 res = node->blk[boffs] = alloc_block(fs);
nuclear@97 416 if(res) {
nuclear@97 417 zero_block(fs, res);
nuclear@97 418 /* also write back the modified inode */
nuclear@97 419 put_inode(fs, node);
nuclear@97 420 }
nuclear@97 421 }
nuclear@97 422 return res;
nuclear@96 423 }
nuclear@96 424
nuclear@97 425 barr = malloc(fs->sb->blksize);
nuclear@96 426 assert(barr);
nuclear@96 427
nuclear@96 428 /* is it an indirect block ? */
nuclear@96 429 if(boffs < MAX_IND) {
nuclear@97 430 int ind_dirty = 0;
nuclear@97 431
nuclear@97 432 if(node->ind) {
nuclear@97 433 /* read the indirect block */
nuclear@97 434 blk_read(fs->bdev, node->ind, 1, barr);
nuclear@97 435 } else {
nuclear@97 436 /* does not exist... try to allocate if requested */
nuclear@97 437 if(!allocate || !(node->ind = alloc_block(fs))) {
nuclear@97 438 res = 0;
nuclear@97 439 goto end;
nuclear@97 440 }
nuclear@97 441
nuclear@97 442 /* allocated a block clear the buffer, and invalidate everything */
nuclear@97 443 memset(barr, 0, sizeof fs->sb->blksize);
nuclear@97 444 node_dirty = 1;
nuclear@97 445 ind_dirty = 1;
nuclear@96 446 }
nuclear@97 447
nuclear@97 448 idx = boffs - NDIRBLK;
nuclear@97 449
nuclear@97 450 if(!(res = barr[idx])) {
nuclear@97 451 if(allocate && (res = barr[idx] = alloc_block(fs))) {
nuclear@97 452 ind_dirty = 1;
nuclear@97 453 }
nuclear@97 454 }
nuclear@97 455
nuclear@97 456 /* write back the indirect block if needed */
nuclear@97 457 if(ind_dirty) {
nuclear@97 458 blk_write(fs->bdev, node->ind, 1, barr);
nuclear@97 459 }
nuclear@96 460 goto end;
nuclear@96 461 }
nuclear@96 462
nuclear@97 463 /* TODO check/rewrite this */
nuclear@97 464 #if 0
nuclear@96 465 /* is it a double-indirect block ? */
nuclear@96 466 if(boffs < MAX_DIND) {
nuclear@96 467 /* first read the dind block and find the index of the ind block */
nuclear@96 468 if(!node->dind) {
nuclear@97 469 if(allocate) {
nuclear@97 470 /* allocate and zero-out the double indirect block */
nuclear@97 471 res = node->dind = alloc_block(fs);
nuclear@97 472 if(res) {
nuclear@97 473 zero_block(fs, res);
nuclear@97 474 }
nuclear@97 475 } else {
nuclear@97 476 res = 0;
nuclear@97 477 goto end;
nuclear@97 478 }
nuclear@96 479 }
nuclear@96 480 blk_read(fd->bdev, node->dind, 1, barr);
nuclear@96 481 idx = (boffs - MAX_IND) / BLK_BLKID;
nuclear@96 482
nuclear@96 483 /* then read the ind block and find the index of the block */
nuclear@96 484 if(!barr[idx]) {
nuclear@96 485 res = 0;
nuclear@96 486 goto end;
nuclear@96 487 }
nuclear@96 488 blk_read(fd->bdev, barr[idx], 1, barr);
nuclear@96 489 res = barr[(boffs - MAX_IND) % BLK_BLKID];
nuclear@96 490 }
nuclear@97 491 #endif
nuclear@96 492
nuclear@96 493 end:
nuclear@97 494 if(node_dirty) {
nuclear@97 495 put_inode(fs, node);
nuclear@97 496 }
nuclear@96 497 free(barr);
nuclear@96 498 return res;
nuclear@96 499 }