root/kern/fs/sfs/sfs_vnode.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sfs_clearblock
  2. sfs_sync_inode
  3. sfs_balloc
  4. sfs_bfree
  5. sfs_bused
  6. sfs_bmap
  7. sfs_partialio
  8. sfs_blockio
  9. sfs_io
  10. sfs_readdir
  11. sfs_writedir
  12. sfs_dir_nentries
  13. sfs_dir_findname
  14. sfs_dir_link
  15. sfs_dir_unlink
  16. sfs_lookonce
  17. sfs_makeobj
  18. sfs_open
  19. sfs_opendir
  20. sfs_close
  21. sfs_reclaim
  22. sfs_read
  23. sfs_write
  24. sfs_ioctl
  25. sfs_stat
  26. sfs_gettype
  27. sfs_tryseek
  28. sfs_fsync
  29. sfs_mmap
  30. sfs_truncate
  31. sfs_namefile
  32. sfs_creat
  33. sfs_link
  34. sfs_remove
  35. sfs_rename
  36. sfs_lookparent
  37. sfs_lookup
  38. sfs_notdir
  39. sfs_isdir
  40. sfs_unimp
  41. sfs_loadvnode
  42. sfs_getroot

   1 /*
   2  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
   3  *      The President and Fellows of Harvard College.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * SFS filesystem
  32  *
  33  * File-level (vnode) interface routines.
  34  */
  35 #include <types.h>
  36 #include <kern/errno.h>
  37 #include <kern/fcntl.h>
  38 #include <stat.h>
  39 #include <lib.h>
  40 #include <array.h>
  41 #include <bitmap.h>
  42 #include <uio.h>
  43 #include <synch.h>
  44 #include <vfs.h>
  45 #include <device.h>
  46 #include <sfs.h>
  47 
  48 /* At bottom of file */
  49 static int sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int type,
  50                          struct sfs_vnode **ret);
  51 
  52 ////////////////////////////////////////////////////////////
  53 //
  54 // Simple stuff
  55 
  56 /* Zero out a disk block. */
  57 static
  58 int
  59 sfs_clearblock(struct sfs_fs *sfs, uint32_t block)
  60 {
  61         /* static -> automatically initialized to zero */
  62         static char zeros[SFS_BLOCKSIZE];
  63         return sfs_wblock(sfs, zeros, block);
  64 }
  65 
  66 /* Write an on-disk inode structure back out to disk. */
  67 static
  68 int
  69 sfs_sync_inode(struct sfs_vnode *sv)
  70 {
  71         if (sv->sv_dirty) {
  72                 struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
  73                 int result = sfs_wblock(sfs, &sv->sv_i, sv->sv_ino);
  74                 if (result) {
  75                         return result;
  76                 }
  77                 sv->sv_dirty = false;
  78         }
  79         return 0;
  80 }
  81 
  82 ////////////////////////////////////////////////////////////
  83 //
  84 // Space allocation
  85 
  86 /*
  87  * Allocate a block.
  88  */
  89 static
  90 int
  91 sfs_balloc(struct sfs_fs *sfs, uint32_t *diskblock)
  92 {
  93         int result;
  94 
  95         result = bitmap_alloc(sfs->sfs_freemap, diskblock);
  96         if (result) {
  97                 return result;
  98         }
  99         sfs->sfs_freemapdirty = true;
 100 
 101         if (*diskblock >= sfs->sfs_super.sp_nblocks) {
 102                 panic("sfs: balloc: invalid block %u\n", *diskblock);
 103         }
 104 
 105         /* Clear block before returning it */
 106         return sfs_clearblock(sfs, *diskblock);
 107 }
 108 
 109 /*
 110  * Free a block.
 111  */
 112 static
 113 void
 114 sfs_bfree(struct sfs_fs *sfs, uint32_t diskblock)
 115 {
 116         bitmap_unmark(sfs->sfs_freemap, diskblock);
 117         sfs->sfs_freemapdirty = true;
 118 }
 119 
 120 /*
 121  * Check if a block is in use.
 122  */
 123 static
 124 int
 125 sfs_bused(struct sfs_fs *sfs, uint32_t diskblock)
 126 {
 127         if (diskblock >= sfs->sfs_super.sp_nblocks) {
 128                 panic("sfs: sfs_bused called on out of range block %u\n", 
 129                       diskblock);
 130         }
 131         return bitmap_isset(sfs->sfs_freemap, diskblock);
 132 }
 133 
 134 ////////////////////////////////////////////////////////////
 135 //
 136 // Block mapping/inode maintenance
 137 
 138 /*
 139  * Look up the disk block number (from 0 up to the number of blocks on
 140  * the disk) given a file and the logical block number within that
 141  * file. If DOALLOC is set, and no such block exists, one will be
 142  * allocated.
 143  */
 144 static
 145 int
 146 sfs_bmap(struct sfs_vnode *sv, uint32_t fileblock, int doalloc,
 147          uint32_t *diskblock)
 148 {
 149         /*
 150          * I/O buffer for handling indirect blocks.
 151          *
 152          * Note: in real life (and when you've done the fs assignment)
 153          * you would get space from the disk buffer cache for this,
 154          * not use a static area.
 155          */
 156         static uint32_t idbuf[SFS_DBPERIDB];
 157 
 158         struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
 159         uint32_t block;
 160         uint32_t idblock;
 161         uint32_t idnum, idoff;
 162         int result;
 163 
 164         KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
 165 
 166         /*
 167          * If the block we want is one of the direct blocks...
 168          */
 169         if (fileblock < SFS_NDIRECT) {
 170                 /*
 171                  * Get the block number
 172                  */
 173                 block = sv->sv_i.sfi_direct[fileblock];
 174 
 175                 /*
 176                  * Do we need to allocate?
 177                  */
 178                 if (block==0 && doalloc) {
 179                         result = sfs_balloc(sfs, &block);
 180                         if (result) {
 181                                 return result;
 182                         }
 183 
 184                         /* Remember what we allocated; mark inode dirty */
 185                         sv->sv_i.sfi_direct[fileblock] = block;
 186                         sv->sv_dirty = true;
 187                 }
 188 
 189                 /*
 190                  * Hand back the block
 191                  */
 192                 if (block != 0 && !sfs_bused(sfs, block)) {
 193                         panic("sfs: Data block %u (block %u of file %u) "
 194                               "marked free\n", block, fileblock, sv->sv_ino);
 195                 }
 196                 *diskblock = block;
 197                 return 0;
 198         }
 199 
 200         /*
 201          * It's not a direct block; it must be in the indirect block.
 202          * Subtract off the number of direct blocks, so FILEBLOCK is
 203          * now the offset into the indirect block space.
 204          */
 205 
 206         fileblock -= SFS_NDIRECT;
 207 
 208         /* Get the indirect block number and offset w/i that indirect block */
 209         idnum = fileblock / SFS_DBPERIDB;
 210         idoff = fileblock % SFS_DBPERIDB;
 211 
 212         /*
 213          * We only have one indirect block. If the offset we were asked for
 214          * is too large, we can't handle it, so fail.
 215          */
 216         if (idnum > 0) {
 217                 return EFBIG;
 218         }
 219 
 220         /* Get the disk block number of the indirect block. */
 221         idblock = sv->sv_i.sfi_indirect;
 222 
 223         if (idblock==0 && !doalloc) {
 224                 /*
 225                  * There's no indirect block allocated. We weren't
 226                  * asked to allocate anything, so pretend the indirect
 227                  * block was filled with all zeros.
 228                  */
 229                 *diskblock = 0;
 230                 return 0;
 231         }
 232         else if (idblock==0) {
 233                 /*
 234                  * There's no indirect block allocated, but we need to
 235                  * allocate a block whose number needs to be stored in
 236                  * the indirect block. Thus, we need to allocate an
 237                  * indirect block.
 238                  */
 239                 result = sfs_balloc(sfs, &idblock);
 240                 if (result) {
 241                         return result;
 242                 }
 243 
 244                 /* Remember the block we just allocated */
 245                 sv->sv_i.sfi_indirect = idblock;
 246 
 247                 /* Mark the inode dirty */
 248                 sv->sv_dirty = true;
 249 
 250                 /* Clear the indirect block buffer */
 251                 bzero(idbuf, sizeof(idbuf));
 252         }
 253         else {
 254                 /*
 255                  * We already have an indirect block allocated; load it.
 256                  */
 257                 result = sfs_rblock(sfs, idbuf, idblock);
 258                 if (result) {
 259                         return result;
 260                 }
 261         }
 262 
 263         /* Get the block out of the indirect block buffer */
 264         block = idbuf[idoff];
 265 
 266         /* If there's no block there, allocate one */
 267         if (block==0 && doalloc) {
 268                 result = sfs_balloc(sfs, &block);
 269                 if (result) {
 270                         return result;
 271                 }
 272 
 273                 /* Remember the block we allocated */
 274                 idbuf[idoff] = block;
 275 
 276                 /* The indirect block is now dirty; write it back */
 277                 result = sfs_wblock(sfs, idbuf, idblock);
 278                 if (result) {
 279                         return result;
 280                 }
 281         }
 282 
 283         /* Hand back the result and return. */
 284         if (block != 0 && !sfs_bused(sfs, block)) {
 285                 panic("sfs: Data block %u (block %u of file %u) marked free\n",
 286                       block, fileblock, sv->sv_ino);
 287         }
 288         *diskblock = block;
 289         return 0;
 290 }
 291 
 292 ////////////////////////////////////////////////////////////
 293 //
 294 // File-level I/O
 295 
 296 /*
 297  * Do I/O to a block of a file that doesn't cover the whole block.  We
 298  * need to read in the original block first, even if we're writing, so
 299  * we don't clobber the portion of the block we're not intending to
 300  * write over.
 301  *
 302  * skipstart is the number of bytes to skip past at the beginning of
 303  * the sector; len is the number of bytes to actually read or write.
 304  * uio is the area to do the I/O into.
 305  */
 306 static
 307 int
 308 sfs_partialio(struct sfs_vnode *sv, struct uio *uio,
 309               uint32_t skipstart, uint32_t len)
 310 {
 311         /*
 312          * I/O buffer for handling partial sectors.
 313          *
 314          * Note: in real life (and when you've done the fs assignment)
 315          * you would get space from the disk buffer cache for this,
 316          * not use a static area.
 317          */
 318         static char iobuf[SFS_BLOCKSIZE];
 319 
 320         struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
 321         uint32_t diskblock;
 322         uint32_t fileblock;
 323         int result;
 324         
 325         /* Allocate missing blocks if and only if we're writing */
 326         int doalloc = (uio->uio_rw==UIO_WRITE);
 327 
 328         KASSERT(skipstart + len <= SFS_BLOCKSIZE);
 329 
 330         /* Compute the block offset of this block in the file */
 331         fileblock = uio->uio_offset / SFS_BLOCKSIZE;
 332 
 333         /* Get the disk block number */
 334         result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
 335         if (result) {
 336                 return result;
 337         }
 338 
 339         if (diskblock == 0) {
 340                 /*
 341                  * There was no block mapped at this point in the file.
 342                  * Zero the buffer.
 343                  */
 344                 KASSERT(uio->uio_rw == UIO_READ);
 345                 bzero(iobuf, sizeof(iobuf));
 346         }
 347         else {
 348                 /*
 349                  * Read the block.
 350                  */
 351                 result = sfs_rblock(sfs, iobuf, diskblock);
 352                 if (result) {
 353                         return result;
 354                 }
 355         }
 356 
 357         /*
 358          * Now perform the requested operation into/out of the buffer.
 359          */
 360         result = uiomove(iobuf+skipstart, len, uio);
 361         if (result) {
 362                 return result;
 363         }
 364 
 365         /*
 366          * If it was a write, write back the modified block.
 367          */
 368         if (uio->uio_rw == UIO_WRITE) {
 369                 result = sfs_wblock(sfs, iobuf, diskblock);
 370                 if (result) {
 371                         return result;
 372                 }
 373         }
 374 
 375         return 0;
 376 }
 377 
 378 /*
 379  * Do I/O (either read or write) of a single whole block.
 380  */
 381 static
 382 int
 383 sfs_blockio(struct sfs_vnode *sv, struct uio *uio)
 384 {
 385         struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
 386         uint32_t diskblock;
 387         uint32_t fileblock;
 388         int result;
 389         int doalloc = (uio->uio_rw==UIO_WRITE);
 390         off_t saveoff;
 391         off_t diskoff;
 392         off_t saveres;
 393         off_t diskres;
 394 
 395         /* Get the block number within the file */
 396         fileblock = uio->uio_offset / SFS_BLOCKSIZE;
 397 
 398         /* Look up the disk block number */
 399         result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
 400         if (result) {
 401                 return result;
 402         }
 403 
 404         if (diskblock == 0) {
 405                 /*
 406                  * No block - fill with zeros.
 407                  *
 408                  * We must be reading, or sfs_bmap would have
 409                  * allocated a block for us.
 410                  */
 411                 KASSERT(uio->uio_rw == UIO_READ);
 412                 return uiomovezeros(SFS_BLOCKSIZE, uio);
 413         }
 414 
 415         /*
 416          * Do the I/O directly to the uio region. Save the uio_offset,
 417          * and substitute one that makes sense to the device.
 418          */
 419         saveoff = uio->uio_offset;
 420         diskoff = diskblock * SFS_BLOCKSIZE;
 421         uio->uio_offset = diskoff;
 422 
 423         /*
 424          * Temporarily set the residue to be one block size.
 425          */
 426         KASSERT(uio->uio_resid >= SFS_BLOCKSIZE);
 427         saveres = uio->uio_resid;
 428         diskres = SFS_BLOCKSIZE;
 429         uio->uio_resid = diskres;
 430         
 431         result = sfs_rwblock(sfs, uio);
 432 
 433         /*
 434          * Now, restore the original uio_offset and uio_resid and update 
 435          * them by the amount of I/O done.
 436          */
 437         uio->uio_offset = (uio->uio_offset - diskoff) + saveoff;
 438         uio->uio_resid = (uio->uio_resid - diskres) + saveres;
 439 
 440         return result;
 441 }
 442 
 443 /*
 444  * Do I/O of a whole region of data, whether or not it's block-aligned.
 445  */
 446 static
 447 int
 448 sfs_io(struct sfs_vnode *sv, struct uio *uio)
 449 {
 450         uint32_t blkoff;
 451         uint32_t nblocks, i;
 452         int result = 0;
 453         uint32_t extraresid = 0;
 454 
 455         /*
 456          * If reading, check for EOF. If we can read a partial area,
 457          * remember how much extra there was in EXTRARESID so we can
 458          * add it back to uio_resid at the end.
 459          */
 460         if (uio->uio_rw == UIO_READ) {
 461                 off_t size = sv->sv_i.sfi_size;
 462                 off_t endpos = uio->uio_offset + uio->uio_resid;
 463 
 464                 if (uio->uio_offset >= size) {
 465                         /* At or past EOF - just return */
 466                         return 0;
 467                 }
 468 
 469                 if (endpos > size) {
 470                         extraresid = endpos - size;
 471                         KASSERT(uio->uio_resid > extraresid);
 472                         uio->uio_resid -= extraresid;
 473                 }
 474         }
 475 
 476         /*
 477          * First, do any leading partial block.
 478          */
 479         blkoff = uio->uio_offset % SFS_BLOCKSIZE;
 480         if (blkoff != 0) {
 481                 /* Number of bytes at beginning of block to skip */
 482                 uint32_t skip = blkoff;
 483 
 484                 /* Number of bytes to read/write after that point */
 485                 uint32_t len = SFS_BLOCKSIZE - blkoff;
 486 
 487                 /* ...which might be less than the rest of the block */
 488                 if (len > uio->uio_resid) {
 489                         len = uio->uio_resid;
 490                 }
 491 
 492                 /* Call sfs_partialio() to do it. */
 493                 result = sfs_partialio(sv, uio, skip, len);
 494                 if (result) {
 495                         goto out;
 496                 }
 497         }
 498 
 499         /* If we're done, quit. */
 500         if (uio->uio_resid==0) {
 501                 goto out;
 502         }
 503 
 504         /*
 505          * Now we should be block-aligned. Do the remaining whole blocks.
 506          */
 507         KASSERT(uio->uio_offset % SFS_BLOCKSIZE == 0);
 508         nblocks = uio->uio_resid / SFS_BLOCKSIZE;
 509         for (i=0; i<nblocks; i++) {
 510                 result = sfs_blockio(sv, uio);
 511                 if (result) {
 512                         goto out;
 513                 }
 514         }
 515 
 516         /*
 517          * Now do any remaining partial block at the end.
 518          */
 519         KASSERT(uio->uio_resid < SFS_BLOCKSIZE);
 520 
 521         if (uio->uio_resid > 0) {
 522                 result = sfs_partialio(sv, uio, 0, uio->uio_resid);
 523                 if (result) {
 524                         goto out;
 525                 }
 526         }
 527 
 528  out:
 529 
 530         /* If writing, adjust file length */
 531         if (uio->uio_rw == UIO_WRITE && 
 532             uio->uio_offset > (off_t)sv->sv_i.sfi_size) {
 533                 sv->sv_i.sfi_size = uio->uio_offset;
 534                 sv->sv_dirty = true;
 535         }
 536 
 537         /* Add in any extra amount we couldn't read because of EOF */
 538         uio->uio_resid += extraresid;
 539 
 540         /* Done */
 541         return result;
 542 }
 543 
 544 ////////////////////////////////////////////////////////////
 545 //
 546 // Directory I/O
 547 
 548 /*
 549  * Read the directory entry out of slot SLOT of a directory vnode.
 550  * The "slot" is the index of the directory entry, starting at 0.
 551  */
 552 static
 553 int
 554 sfs_readdir(struct sfs_vnode *sv, struct sfs_dir *sd, int slot)
 555 {
 556         struct iovec iov;
 557         struct uio ku;
 558         off_t actualpos;
 559         int result;
 560 
 561         /* Compute the actual position in the directory to read. */
 562         actualpos = slot * sizeof(struct sfs_dir);
 563 
 564         /* Set up a uio to do the read */ 
 565         uio_kinit(&iov, &ku, sd, sizeof(struct sfs_dir), actualpos, UIO_READ);
 566 
 567         /* do it */
 568         result = sfs_io(sv, &ku);
 569         if (result) {
 570                 return result;
 571         }
 572 
 573         /* We should not hit EOF in the middle of a directory entry */
 574         if (ku.uio_resid > 0) {
 575                 panic("sfs: readdir: Short entry (inode %u)\n", sv->sv_ino);
 576         }
 577 
 578         /* Done */
 579         return 0;
 580 }
 581 
 582 /*
 583  * Write (overwrite) the directory entry in slot SLOT of a directory
 584  * vnode.
 585  */
 586 static
 587 int
 588 sfs_writedir(struct sfs_vnode *sv, struct sfs_dir *sd, int slot)
 589 {
 590         struct iovec iov;
 591         struct uio ku;
 592         off_t actualpos;
 593         int result;
 594 
 595         /* Compute the actual position in the directory. */
 596         KASSERT(slot>=0);
 597         actualpos = slot * sizeof(struct sfs_dir);
 598 
 599         /* Set up a uio to do the write */ 
 600         uio_kinit(&iov, &ku, sd, sizeof(struct sfs_dir), actualpos, UIO_WRITE);
 601 
 602         /* do it */
 603         result = sfs_io(sv, &ku);
 604         if (result) {
 605                 return result;
 606         }
 607 
 608         /* Should not end up with a partial entry! */
 609         if (ku.uio_resid > 0) {
 610                 panic("sfs: writedir: Short write (ino %u)\n", sv->sv_ino);
 611         }
 612 
 613         /* Done */
 614         return 0;
 615 }
 616 
 617 /*
 618  * Compute the number of entries in a directory.
 619  * This actually computes the number of existing slots, and does not
 620  * account for empty slots.
 621  */
 622 static
 623 int
 624 sfs_dir_nentries(struct sfs_vnode *sv)
 625 {
 626         off_t size;
 627 
 628         KASSERT(sv->sv_i.sfi_type == SFS_TYPE_DIR);
 629 
 630         size = sv->sv_i.sfi_size;
 631         if (size % sizeof(struct sfs_dir) != 0) {
 632                 panic("sfs: directory %u: Invalid size %llu\n",
 633                       sv->sv_ino, size);
 634         }
 635 
 636         return size / sizeof(struct sfs_dir);
 637 }
 638 
 639 /*
 640  * Search a directory for a particular filename in a directory, and
 641  * return its inode number, its slot, and/or the slot number of an
 642  * empty directory slot if one is found.
 643  */
 644 
 645 static
 646 int
 647 sfs_dir_findname(struct sfs_vnode *sv, const char *name,
 648                     uint32_t *ino, int *slot, int *emptyslot)
 649 {
 650         struct sfs_dir tsd;
 651         int found = 0;
 652         int nentries = sfs_dir_nentries(sv);
 653         int i, result;
 654 
 655         /* For each slot... */
 656         for (i=0; i<nentries; i++) {
 657 
 658                 /* Read the entry from that slot */
 659                 result = sfs_readdir(sv, &tsd, i);
 660                 if (result) {
 661                         return result;
 662                 }
 663                 if (tsd.sfd_ino == SFS_NOINO) {
 664                         /* Free slot - report it back if one was requested */
 665                         if (emptyslot != NULL) {
 666                                 *emptyslot = i;
 667                         }
 668                 }
 669                 else {
 670                         /* Ensure null termination, just in case */
 671                         tsd.sfd_name[sizeof(tsd.sfd_name)-1] = 0;
 672                         if (!strcmp(tsd.sfd_name, name)) {
 673 
 674                                 /* Each name may legally appear only once... */
 675                                 KASSERT(found==0);
 676 
 677                                 found = 1;
 678                                 if (slot != NULL) {
 679                                         *slot = i;
 680                                 }
 681                                 if (ino != NULL) {
 682                                         *ino = tsd.sfd_ino;
 683                                 }
 684                         }
 685                 }
 686         }
 687 
 688         return found ? 0 : ENOENT;
 689 }
 690 
 691 /*
 692  * Create a link in a directory to the specified inode by number, with
 693  * the specified name, and optionally hand back the slot.
 694  */
 695 static
 696 int
 697 sfs_dir_link(struct sfs_vnode *sv, const char *name, uint32_t ino, int *slot)
 698 {
 699         int emptyslot = -1;
 700         int result;
 701         struct sfs_dir sd;
 702 
 703         /* Look up the name. We want to make sure it *doesn't* exist. */
 704         result = sfs_dir_findname(sv, name, NULL, NULL, &emptyslot);
 705         if (result!=0 && result!=ENOENT) {
 706                 return result;
 707         }
 708         if (result==0) {
 709                 return EEXIST;
 710         }
 711 
 712         if (strlen(name)+1 > sizeof(sd.sfd_name)) {
 713                 return ENAMETOOLONG;
 714         }
 715 
 716         /* If we didn't get an empty slot, add the entry at the end. */
 717         if (emptyslot < 0) {
 718                 emptyslot = sfs_dir_nentries(sv);
 719         }
 720 
 721         /* Set up the entry. */
 722         bzero(&sd, sizeof(sd));
 723         sd.sfd_ino = ino;
 724         strcpy(sd.sfd_name, name);
 725 
 726         /* Hand back the slot, if so requested. */
 727         if (slot) {
 728                 *slot = emptyslot;
 729         }
 730 
 731         /* Write the entry. */
 732         return sfs_writedir(sv, &sd, emptyslot);
 733         
 734 }
 735 
 736 /*
 737  * Unlink a name in a directory, by slot number.
 738  */
 739 static
 740 int
 741 sfs_dir_unlink(struct sfs_vnode *sv, int slot)
 742 {
 743         struct sfs_dir sd;
 744 
 745         /* Initialize a suitable directory entry... */ 
 746         bzero(&sd, sizeof(sd));
 747         sd.sfd_ino = SFS_NOINO;
 748 
 749         /* ... and write it */
 750         return sfs_writedir(sv, &sd, slot);
 751 }
 752 
 753 /*
 754  * Look for a name in a directory and hand back a vnode for the
 755  * file, if there is one.
 756  */
 757 static
 758 int
 759 sfs_lookonce(struct sfs_vnode *sv, const char *name, 
 760                 struct sfs_vnode **ret,
 761                 int *slot)
 762 {
 763         struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
 764         uint32_t ino;
 765         int result;
 766 
 767         result = sfs_dir_findname(sv, name, &ino, slot, NULL);
 768         if (result) {
 769                 return result;
 770         }
 771 
 772         result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, ret);
 773         if (result) {
 774                 return result;
 775         }
 776 
 777         if ((*ret)->sv_i.sfi_linkcount == 0) {
 778                 panic("sfs: Link count of file %u found in dir %u is 0\n",
 779                       (*ret)->sv_ino, sv->sv_ino);
 780         }
 781 
 782         return 0;
 783 }
 784 
 785 ////////////////////////////////////////////////////////////
 786 //
 787 // Object creation
 788 
 789 /*
 790  * Create a new filesystem object and hand back its vnode.
 791  */
 792 static
 793 int
 794 sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret)
 795 {
 796         uint32_t ino;
 797         int result;
 798 
 799         /*
 800          * First, get an inode. (Each inode is a block, and the inode 
 801          * number is the block number, so just get a block.)
 802          */
 803 
 804         result = sfs_balloc(sfs, &ino);
 805         if (result) {
 806                 return result;
 807         }
 808 
 809         /*
 810          * Now load a vnode for it.
 811          */
 812 
 813         return sfs_loadvnode(sfs, ino, type, ret);
 814 }
 815 
 816 ////////////////////////////////////////////////////////////
 817 //
 818 // Vnode ops
 819 
 820 /*
 821  * This is called on *each* open().
 822  */
 823 static
 824 int
 825 sfs_open(struct vnode *v, int openflags)
 826 {
 827         /*
 828          * At this level we do not need to handle O_CREAT, O_EXCL, or O_TRUNC.
 829          * We *would* need to handle O_APPEND, but we don't support it.
 830          *
 831          * Any of O_RDONLY, O_WRONLY, and O_RDWR are valid, so we don't need
 832          * to check that either.
 833          */
 834 
 835         if (openflags & O_APPEND) {
 836                 return EUNIMP;
 837         }
 838 
 839         (void)v;
 840 
 841         return 0;
 842 }
 843 
 844 /*
 845  * This is called on *each* open() of a directory.
 846  * Directories may only be open for read.
 847  */
 848 static
 849 int
 850 sfs_opendir(struct vnode *v, int openflags)
 851 {
 852         switch (openflags & O_ACCMODE) {
 853             case O_RDONLY:
 854                 break;
 855             case O_WRONLY:
 856             case O_RDWR:
 857             default:
 858                 return EISDIR;
 859         }
 860         if (openflags & O_APPEND) {
 861                 return EISDIR;
 862         }
 863 
 864         (void)v;
 865         return 0;
 866 }
 867 
 868 /*
 869  * Called on the *last* close().
 870  *
 871  * This function should attempt to avoid returning errors, as handling
 872  * them usefully is often not possible.
 873  */
 874 static
 875 int
 876 sfs_close(struct vnode *v)
 877 {
 878         /* Sync it. */
 879         return VOP_FSYNC(v);
 880 }
 881 
 882 /*
 883  * Called when the vnode refcount (in-memory usage count) hits zero.
 884  *
 885  * This function should try to avoid returning errors other than EBUSY.
 886  */
 887 static
 888 int
 889 sfs_reclaim(struct vnode *v)
 890 {
 891         struct sfs_vnode *sv = v->vn_data;
 892         struct sfs_fs *sfs = v->vn_fs->fs_data;
 893         unsigned ix, i, num;
 894         int result;
 895 
 896         vfs_biglock_acquire();
 897 
 898         /*
 899          * Make sure someone else hasn't picked up the vnode since the
 900          * decision was made to reclaim it. (You must also synchronize
 901          * this with sfs_loadvnode.)
 902          */
 903         if (v->vn_refcount != 1) {
 904 
 905                 /* consume the reference VOP_DECREF gave us */
 906                 KASSERT(v->vn_refcount>1);
 907                 v->vn_refcount--;
 908 
 909                 vfs_biglock_release();
 910                 return EBUSY;
 911         }
 912 
 913         /* If there are no on-disk references to the file either, erase it. */
 914         if (sv->sv_i.sfi_linkcount==0) {
 915                 result = VOP_TRUNCATE(&sv->sv_v, 0);
 916                 if (result) {
 917                         vfs_biglock_release();
 918                         return result;
 919                 }
 920         }
 921 
 922         /* Sync the inode to disk */
 923         result = sfs_sync_inode(sv);
 924         if (result) {
 925                 vfs_biglock_release();
 926                 return result;
 927         }
 928 
 929         /* If there are no on-disk references, discard the inode */
 930         if (sv->sv_i.sfi_linkcount==0) {
 931                 sfs_bfree(sfs, sv->sv_ino);
 932         }
 933 
 934         /* Remove the vnode structure from the table in the struct sfs_fs. */
 935         num = vnodearray_num(sfs->sfs_vnodes);
 936         ix = num;
 937         for (i=0; i<num; i++) {
 938                 struct vnode *v2 = vnodearray_get(sfs->sfs_vnodes, i);
 939                 struct sfs_vnode *sv2 = v2->vn_data;
 940                 if (sv2 == sv) {
 941                         ix = i;
 942                         break;
 943                 }
 944         }
 945         if (ix == num) {
 946                 panic("sfs: reclaim vnode %u not in vnode pool\n",
 947                       sv->sv_ino);
 948         }
 949         vnodearray_remove(sfs->sfs_vnodes, ix);
 950 
 951         VOP_CLEANUP(&sv->sv_v);
 952 
 953         vfs_biglock_release();
 954 
 955         /* Release the storage for the vnode structure itself. */
 956         kfree(sv);
 957 
 958         /* Done */
 959         return 0;
 960 }
 961 
 962 /*
 963  * Called for read(). sfs_io() does the work.
 964  */
 965 static
 966 int
 967 sfs_read(struct vnode *v, struct uio *uio)
 968 {
 969         struct sfs_vnode *sv = v->vn_data;
 970         int result;
 971 
 972         KASSERT(uio->uio_rw==UIO_READ);
 973 
 974         vfs_biglock_acquire();
 975         result = sfs_io(sv, uio);
 976         vfs_biglock_release();
 977 
 978         return result;
 979 }
 980 
 981 /*
 982  * Called for write(). sfs_io() does the work.
 983  */
 984 static
 985 int
 986 sfs_write(struct vnode *v, struct uio *uio)
 987 {
 988         struct sfs_vnode *sv = v->vn_data;
 989         int result;
 990 
 991         KASSERT(uio->uio_rw==UIO_WRITE);
 992 
 993         vfs_biglock_acquire();
 994         result = sfs_io(sv, uio);
 995         vfs_biglock_release();
 996 
 997         return result;
 998 }
 999 
1000 /*
1001  * Called for ioctl()
1002  */
1003 static
1004 int
1005 sfs_ioctl(struct vnode *v, int op, userptr_t data)
1006 {
1007         /*
1008          * No ioctls.
1009          */
1010 
1011         (void)v;
1012         (void)op;
1013         (void)data;
1014 
1015         return EINVAL;
1016 }
1017 
1018 /*
1019  * Called for stat/fstat/lstat.
1020  */
1021 static
1022 int
1023 sfs_stat(struct vnode *v, struct stat *statbuf)
1024 {
1025         struct sfs_vnode *sv = v->vn_data;
1026         int result;
1027 
1028         /* Fill in the stat structure */
1029         bzero(statbuf, sizeof(struct stat));
1030 
1031         result = VOP_GETTYPE(v, &statbuf->st_mode);
1032         if (result) {
1033                 return result;
1034         }
1035 
1036         statbuf->st_size = sv->sv_i.sfi_size;
1037 
1038         /* We don't support these yet; you get to implement them */
1039         statbuf->st_nlink = 0;
1040         statbuf->st_blocks = 0;
1041 
1042         /* Fill in other field as desired/possible... */
1043 
1044         return 0;
1045 }
1046 
1047 /*
1048  * Return the type of the file (types as per kern/stat.h)
1049  */
1050 static
1051 int
1052 sfs_gettype(struct vnode *v, uint32_t *ret)
1053 {
1054         struct sfs_vnode *sv = v->vn_data;
1055 
1056         vfs_biglock_acquire();
1057 
1058         switch (sv->sv_i.sfi_type) {
1059         case SFS_TYPE_FILE:
1060                 *ret = S_IFREG;
1061                 vfs_biglock_release();
1062                 return 0;
1063         case SFS_TYPE_DIR:
1064                 *ret = S_IFDIR;
1065                 vfs_biglock_release();
1066                 return 0;
1067         }
1068         panic("sfs: gettype: Invalid inode type (inode %u, type %u)\n",
1069               sv->sv_ino, sv->sv_i.sfi_type);
1070         return EINVAL;
1071 }
1072 
1073 /*
1074  * Check for legal seeks on files. Allow anything non-negative.
1075  * We could conceivably, here, prohibit seeking past the maximum
1076  * file size our inode structure can support, but we don't - few
1077  * people ever bother to check lseek() for failure and having 
1078  * read() or write() fail is sufficient.
1079  */
1080 static
1081 int
1082 sfs_tryseek(struct vnode *v, off_t pos)
1083 {
1084         if (pos<0) {
1085                 return EINVAL;
1086         }
1087 
1088         /* Allow anything else */
1089         (void)v;
1090 
1091         return 0;
1092 }
1093 
1094 /*
1095  * Called for fsync(), and also on filesystem unmount, global sync(),
1096  * and some other cases.
1097  */
1098 static
1099 int
1100 sfs_fsync(struct vnode *v)
1101 {
1102         struct sfs_vnode *sv = v->vn_data;
1103         int result;
1104 
1105         vfs_biglock_acquire();
1106         result = sfs_sync_inode(sv);
1107         vfs_biglock_release();
1108 
1109         return result;
1110 }
1111 
1112 /*
1113  * Called for mmap().
1114  */
1115 static
1116 int
1117 sfs_mmap(struct vnode *v   /* add stuff as needed */)
1118 {
1119         (void)v;
1120         return EUNIMP;
1121 }
1122 
1123 /*
1124  * Called for ftruncate() and from sfs_reclaim.
1125  */
1126 static
1127 int
1128 sfs_truncate(struct vnode *v, off_t len)
1129 {
1130         /*
1131          * I/O buffer for handling the indirect block.
1132          *
1133          * Note: in real life (and when you've done the fs assignment)
1134          * you would get space from the disk buffer cache for this,
1135          * not use a static area.
1136          */
1137         static uint32_t idbuf[SFS_DBPERIDB];
1138 
1139         struct sfs_vnode *sv = v->vn_data;
1140         struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
1141 
1142         /* Length in blocks (divide rounding up) */
1143         uint32_t blocklen = DIVROUNDUP(len, SFS_BLOCKSIZE);
1144 
1145         uint32_t i, j, block;
1146         uint32_t idblock, baseblock, highblock;
1147         int result;
1148         int hasnonzero, iddirty;
1149 
1150         KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
1151 
1152         vfs_biglock_acquire();
1153 
1154         /*
1155          * Go through the direct blocks. Discard any that are
1156          * past the limit we're truncating to.
1157          */
1158         for (i=0; i<SFS_NDIRECT; i++) {
1159                 block = sv->sv_i.sfi_direct[i];
1160                 if (i >= blocklen && block != 0) {
1161                         sfs_bfree(sfs, block);
1162                         sv->sv_i.sfi_direct[i] = 0;
1163                         sv->sv_dirty = true;
1164                 }
1165         }
1166 
1167         /* Indirect block number */
1168         idblock = sv->sv_i.sfi_indirect;
1169 
1170         /* The lowest block in the indirect block */
1171         baseblock = SFS_NDIRECT;
1172 
1173         /* The highest block in the indirect block */
1174         highblock = baseblock + SFS_DBPERIDB - 1;
1175 
1176         if (blocklen < highblock && idblock != 0) {
1177                 /* We're past the proposed EOF; may need to free stuff */
1178 
1179                 /* Read the indirect block */
1180                 result = sfs_rblock(sfs, idbuf, idblock);
1181                 if (result) {
1182                         vfs_biglock_release();
1183                         return result;
1184                 }
1185                 
1186                 hasnonzero = 0;
1187                 iddirty = 0;
1188                 for (j=0; j<SFS_DBPERIDB; j++) {
1189                         /* Discard any blocks that are past the new EOF */
1190                         if (blocklen < baseblock+j && idbuf[j] != 0) {
1191                                 sfs_bfree(sfs, idbuf[j]);
1192                                 idbuf[j] = 0;
1193                                 iddirty = 1;
1194                         }
1195                         /* Remember if we see any nonzero blocks in here */
1196                         if (idbuf[j]!=0) {
1197                                 hasnonzero=1;
1198                         }
1199                 }
1200 
1201                 if (!hasnonzero) {
1202                         /* The whole indirect block is empty now; free it */
1203                         sfs_bfree(sfs, idblock);
1204                         sv->sv_i.sfi_indirect = 0;
1205                         sv->sv_dirty = true;
1206                 }
1207                 else if (iddirty) {
1208                         /* The indirect block is dirty; write it back */
1209                         result = sfs_wblock(sfs, idbuf, idblock);
1210                         if (result) {
1211                                 vfs_biglock_release();
1212                                 return result;
1213                         }
1214                 }
1215         }
1216 
1217         /* Set the file size */
1218         sv->sv_i.sfi_size = len;
1219 
1220         /* Mark the inode dirty */
1221         sv->sv_dirty = true;
1222 
1223         vfs_biglock_release();
1224         return 0;
1225 }
1226 
1227 /*
1228  * Get the full pathname for a file. This only needs to work on directories.
1229  * Since we don't support subdirectories, assume it's the root directory
1230  * and hand back the empty string. (The VFS layer takes care of the
1231  * device name, leading slash, etc.)
1232  */
1233 static
1234 int
1235 sfs_namefile(struct vnode *vv, struct uio *uio)
1236 {
1237         struct sfs_vnode *sv = vv->vn_data;
1238         KASSERT(sv->sv_ino == SFS_ROOT_LOCATION);
1239 
1240         /* send back the empty string - just return */
1241 
1242         (void)uio;
1243 
1244         return 0;
1245 }
1246 
1247 /*
1248  * Create a file. If EXCL is set, insist that the filename not already
1249  * exist; otherwise, if it already exists, just open it.
1250  */
1251 static
1252 int
1253 sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
1254           struct vnode **ret)
1255 {
1256         struct sfs_fs *sfs = v->vn_fs->fs_data;
1257         struct sfs_vnode *sv = v->vn_data;
1258         struct sfs_vnode *newguy;
1259         uint32_t ino;
1260         int result;
1261 
1262         vfs_biglock_acquire();
1263 
1264         /* Look up the name */
1265         result = sfs_dir_findname(sv, name, &ino, NULL, NULL);
1266         if (result!=0 && result!=ENOENT) {
1267                 vfs_biglock_release();
1268                 return result;
1269         }
1270 
1271         /* If it exists and we didn't want it to, fail */
1272         if (result==0 && excl) {
1273                 vfs_biglock_release();
1274                 return EEXIST;
1275         }
1276 
1277         if (result==0) {
1278                 /* We got a file; load its vnode and return */
1279                 result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy);
1280                 if (result) {
1281                         vfs_biglock_release();
1282                         return result;
1283                 }
1284                 *ret = &newguy->sv_v;
1285                 vfs_biglock_release();
1286                 return 0;
1287         }
1288 
1289         /* Didn't exist - create it */
1290         result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy);
1291         if (result) {
1292                 vfs_biglock_release();
1293                 return result;
1294         }
1295 
1296         /* We don't currently support file permissions; ignore MODE */
1297         (void)mode;
1298 
1299         /* Link it into the directory */
1300         result = sfs_dir_link(sv, name, newguy->sv_ino, NULL);
1301         if (result) {
1302                 VOP_DECREF(&newguy->sv_v);
1303                 vfs_biglock_release();
1304                 return result;
1305         }
1306 
1307         /* Update the linkcount of the new file */
1308         newguy->sv_i.sfi_linkcount++;
1309 
1310         /* and consequently mark it dirty. */
1311         newguy->sv_dirty = true;
1312 
1313         *ret = &newguy->sv_v;
1314         
1315         vfs_biglock_release();
1316         return 0;
1317 }
1318 
1319 /*
1320  * Make a hard link to a file.
1321  * The VFS layer should prevent this being called unless both
1322  * vnodes are ours.
1323  */
1324 static
1325 int
1326 sfs_link(struct vnode *dir, const char *name, struct vnode *file)
1327 {
1328         struct sfs_vnode *sv = dir->vn_data;
1329         struct sfs_vnode *f = file->vn_data;
1330         int result;
1331 
1332         KASSERT(file->vn_fs == dir->vn_fs);
1333 
1334         vfs_biglock_acquire();
1335 
1336         /* Just create a link */
1337         result = sfs_dir_link(sv, name, f->sv_ino, NULL);
1338         if (result) {
1339                 vfs_biglock_release();
1340                 return result;
1341         }
1342 
1343         /* and update the link count, marking the inode dirty */
1344         f->sv_i.sfi_linkcount++;
1345         f->sv_dirty = true;
1346 
1347         vfs_biglock_release();
1348         return 0;
1349 }
1350 
1351 /*
1352  * Delete a file.
1353  */
1354 static
1355 int
1356 sfs_remove(struct vnode *dir, const char *name)
1357 {
1358         struct sfs_vnode *sv = dir->vn_data;
1359         struct sfs_vnode *victim;
1360         int slot;
1361         int result;
1362 
1363         vfs_biglock_acquire();
1364 
1365         /* Look for the file and fetch a vnode for it. */
1366         result = sfs_lookonce(sv, name, &victim, &slot);
1367         if (result) {
1368                 vfs_biglock_release();
1369                 return result;
1370         }
1371 
1372         /* Erase its directory entry. */
1373         result = sfs_dir_unlink(sv, slot);
1374         if (result==0) {
1375                 /* If we succeeded, decrement the link count. */
1376                 KASSERT(victim->sv_i.sfi_linkcount > 0);
1377                 victim->sv_i.sfi_linkcount--;
1378                 victim->sv_dirty = true;
1379         }
1380 
1381         /* Discard the reference that sfs_lookonce got us */
1382         VOP_DECREF(&victim->sv_v);
1383 
1384         vfs_biglock_release();
1385         return result;
1386 }
1387 
1388 /*
1389  * Rename a file.
1390  *
1391  * Since we don't support subdirectories, assumes that the two
1392  * directories passed are the same.
1393  */
1394 static
1395 int
1396 sfs_rename(struct vnode *d1, const char *n1, 
1397            struct vnode *d2, const char *n2)
1398 {
1399         struct sfs_vnode *sv = d1->vn_data;
1400         struct sfs_vnode *g1;
1401         int slot1, slot2;
1402         int result, result2;
1403 
1404         vfs_biglock_acquire();
1405 
1406         KASSERT(d1==d2);
1407         KASSERT(sv->sv_ino == SFS_ROOT_LOCATION);
1408 
1409         /* Look up the old name of the file and get its inode and slot number*/
1410         result = sfs_lookonce(sv, n1, &g1, &slot1);
1411         if (result) {
1412                 vfs_biglock_release();
1413                 return result;
1414         }
1415 
1416         /* We don't support subdirectories */
1417         KASSERT(g1->sv_i.sfi_type == SFS_TYPE_FILE);
1418 
1419         /*
1420          * Link it under the new name.
1421          *
1422          * We could theoretically just overwrite the original
1423          * directory entry, except that we need to check to make sure
1424          * the new name doesn't already exist; might as well use the
1425          * existing link routine.
1426          */
1427         result = sfs_dir_link(sv, n2, g1->sv_ino, &slot2);
1428         if (result) {
1429                 goto puke;
1430         }
1431         
1432         /* Increment the link count, and mark inode dirty */
1433         g1->sv_i.sfi_linkcount++;
1434         g1->sv_dirty = true;
1435 
1436         /* Unlink the old slot */
1437         result = sfs_dir_unlink(sv, slot1);
1438         if (result) {
1439                 goto puke_harder;
1440         }
1441 
1442         /*
1443          * Decrement the link count again, and mark the inode dirty again,
1444          * in case it's been synced behind our back.
1445          */
1446         KASSERT(g1->sv_i.sfi_linkcount>0);
1447         g1->sv_i.sfi_linkcount--;
1448         g1->sv_dirty = true;
1449 
1450         /* Let go of the reference to g1 */
1451         VOP_DECREF(&g1->sv_v);
1452 
1453         vfs_biglock_release();
1454         return 0;
1455 
1456  puke_harder:
1457         /*
1458          * Error recovery: try to undo what we already did
1459          */
1460         result2 = sfs_dir_unlink(sv, slot2);
1461         if (result2) {
1462                 kprintf("sfs: rename: %s\n", strerror(result));
1463                 kprintf("sfs: rename: while cleaning up: %s\n", 
1464                         strerror(result2));
1465                 panic("sfs: rename: Cannot recover\n");
1466         }
1467         g1->sv_i.sfi_linkcount--;
1468  puke:
1469         /* Let go of the reference to g1 */
1470         VOP_DECREF(&g1->sv_v);
1471         vfs_biglock_release();
1472         return result;
1473 }
1474 
1475 /*
1476  * lookparent returns the last path component as a string and the
1477  * directory it's in as a vnode.
1478  *
1479  * Since we don't support subdirectories, this is very easy - 
1480  * return the root dir and copy the path.
1481  */
1482 static
1483 int
1484 sfs_lookparent(struct vnode *v, char *path, struct vnode **ret,
1485                   char *buf, size_t buflen)
1486 {
1487         struct sfs_vnode *sv = v->vn_data;
1488 
1489         vfs_biglock_acquire();
1490 
1491         if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
1492                 vfs_biglock_release();
1493                 return ENOTDIR;
1494         }
1495 
1496         if (strlen(path)+1 > buflen) {
1497                 vfs_biglock_release();
1498                 return ENAMETOOLONG;
1499         }
1500         strcpy(buf, path);
1501 
1502         VOP_INCREF(&sv->sv_v);
1503         *ret = &sv->sv_v;
1504 
1505         vfs_biglock_release();
1506         return 0;
1507 }
1508 
1509 /*
1510  * Lookup gets a vnode for a pathname.
1511  *
1512  * Since we don't support subdirectories, it's easy - just look up the
1513  * name.
1514  */
1515 static
1516 int
1517 sfs_lookup(struct vnode *v, char *path, struct vnode **ret)
1518 {
1519         struct sfs_vnode *sv = v->vn_data;
1520         struct sfs_vnode *final;
1521         int result;
1522 
1523         vfs_biglock_acquire();
1524 
1525         if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
1526                 vfs_biglock_release();
1527                 return ENOTDIR;
1528         }
1529         
1530         result = sfs_lookonce(sv, path, &final, NULL);
1531         if (result) {
1532                 vfs_biglock_release();
1533                 return result;
1534         }
1535 
1536         *ret = &final->sv_v;
1537 
1538         vfs_biglock_release();
1539         return 0;
1540 }
1541 
1542 //////////////////////////////////////////////////
1543 
1544 static
1545 int
1546 sfs_notdir(void)
1547 {
1548         return ENOTDIR;
1549 }
1550 
1551 static
1552 int
1553 sfs_isdir(void)
1554 {
1555         return EISDIR;
1556 }
1557 
1558 static
1559 int
1560 sfs_unimp(void)
1561 {
1562         return EUNIMP;
1563 }
1564 
1565 /*
1566  * Casting through void * prevents warnings.
1567  * All of the vnode ops return int, and it's ok to cast functions that
1568  * take args to functions that take no args.
1569  */
1570 
1571 #define ISDIR ((void *)sfs_isdir)
1572 #define NOTDIR ((void *)sfs_notdir)
1573 #define UNIMP ((void *)sfs_unimp)
1574 
1575 /*
1576  * Function table for sfs files.
1577  */
1578 static const struct vnode_ops sfs_fileops = {
1579         VOP_MAGIC,      /* mark this a valid vnode ops table */
1580 
1581         sfs_open,
1582         sfs_close,
1583         sfs_reclaim,
1584 
1585         sfs_read,
1586         NOTDIR,  /* readlink */
1587         NOTDIR,  /* getdirentry */
1588         sfs_write,
1589         sfs_ioctl,
1590         sfs_stat,
1591         sfs_gettype,
1592         sfs_tryseek,
1593         sfs_fsync,
1594         sfs_mmap,
1595         sfs_truncate,
1596         NOTDIR,  /* namefile */
1597 
1598         NOTDIR,  /* creat */
1599         NOTDIR,  /* symlink */
1600         NOTDIR,  /* mkdir */
1601         NOTDIR,  /* link */
1602         NOTDIR,  /* remove */
1603         NOTDIR,  /* rmdir */
1604         NOTDIR,  /* rename */
1605 
1606         NOTDIR,  /* lookup */
1607         NOTDIR,  /* lookparent */
1608 };
1609 
1610 /*
1611  * Function table for the sfs directory.
1612  */
1613 static const struct vnode_ops sfs_dirops = {
1614         VOP_MAGIC,      /* mark this a valid vnode ops table */
1615 
1616         sfs_opendir,
1617         sfs_close,
1618         sfs_reclaim,
1619         
1620         ISDIR,   /* read */
1621         ISDIR,   /* readlink */
1622         UNIMP,   /* getdirentry */
1623         ISDIR,   /* write */
1624         sfs_ioctl,
1625         sfs_stat,
1626         sfs_gettype,
1627         UNIMP,   /* tryseek */
1628         sfs_fsync,
1629         ISDIR,   /* mmap */
1630         ISDIR,   /* truncate */
1631         sfs_namefile,
1632 
1633         sfs_creat,
1634         UNIMP,   /* symlink */
1635         UNIMP,   /* mkdir */
1636         sfs_link,
1637         sfs_remove,
1638         UNIMP,   /* rmdir */
1639         sfs_rename,
1640 
1641         sfs_lookup,
1642         sfs_lookparent,
1643 };
1644 
1645 /*
1646  * Function to load a inode into memory as a vnode, or dig up one
1647  * that's already resident.
1648  */
1649 static
1650 int
1651 sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int forcetype,
1652                  struct sfs_vnode **ret)
1653 {
1654         struct vnode *v;
1655         struct sfs_vnode *sv;
1656         const struct vnode_ops *ops = NULL;
1657         unsigned i, num;
1658         int result;
1659 
1660         /* Look in the vnodes table */
1661         num = vnodearray_num(sfs->sfs_vnodes);
1662 
1663         /* Linear search. Is this too slow? You decide. */
1664         for (i=0; i<num; i++) {
1665                 v = vnodearray_get(sfs->sfs_vnodes, i);
1666                 sv = v->vn_data;
1667 
1668                 /* Every inode in memory must be in an allocated block */
1669                 if (!sfs_bused(sfs, sv->sv_ino)) {
1670                         panic("sfs: Found inode %u in unallocated block\n",
1671                               sv->sv_ino);
1672                 }
1673 
1674                 if (sv->sv_ino==ino) {
1675                         /* Found */
1676 
1677                         /* May only be set when creating new objects */
1678                         KASSERT(forcetype==SFS_TYPE_INVAL);
1679 
1680                         VOP_INCREF(&sv->sv_v);
1681                         *ret = sv;
1682                         return 0;
1683                 }
1684         }
1685 
1686         /* Didn't have it loaded; load it */
1687 
1688         sv = kmalloc(sizeof(struct sfs_vnode));
1689         if (sv==NULL) {
1690                 return ENOMEM;
1691         }
1692 
1693         /* Must be in an allocated block */
1694         if (!sfs_bused(sfs, ino)) {
1695                 panic("sfs: Tried to load inode %u from unallocated block\n",
1696                       ino);
1697         }
1698 
1699         /* Read the block the inode is in */
1700         result = sfs_rblock(sfs, &sv->sv_i, ino);
1701         if (result) {
1702                 kfree(sv);
1703                 return result;
1704         }
1705 
1706         /* Not dirty yet */
1707         sv->sv_dirty = false;
1708 
1709         /*
1710          * FORCETYPE is set if we're creating a new file, because the
1711          * block on disk will have been zeroed out and thus the type
1712          * recorded there will be SFS_TYPE_INVAL.
1713          */
1714         if (forcetype != SFS_TYPE_INVAL) {
1715                 KASSERT(sv->sv_i.sfi_type == SFS_TYPE_INVAL);
1716                 sv->sv_i.sfi_type = forcetype;
1717                 sv->sv_dirty = true;
1718         }
1719 
1720         /*
1721          * Choose the function table based on the object type.
1722          */
1723         switch (sv->sv_i.sfi_type) {
1724             case SFS_TYPE_FILE:
1725                 ops = &sfs_fileops;
1726                 break;
1727             case SFS_TYPE_DIR:
1728                 ops = &sfs_dirops;
1729                 break;
1730             default: 
1731                 panic("sfs: loadvnode: Invalid inode type "
1732                       "(inode %u, type %u)\n",
1733                       ino, sv->sv_i.sfi_type);
1734         }
1735 
1736         /* Call the common vnode initializer */
1737         result = VOP_INIT(&sv->sv_v, ops, &sfs->sfs_absfs, sv);
1738         if (result) {
1739                 kfree(sv);
1740                 return result;
1741         }
1742 
1743         /* Set the other fields in our vnode structure */
1744         sv->sv_ino = ino;
1745 
1746         /* Add it to our table */
1747         result = vnodearray_add(sfs->sfs_vnodes, &sv->sv_v, NULL);
1748         if (result) {
1749                 VOP_CLEANUP(&sv->sv_v);
1750                 kfree(sv);
1751                 return result;
1752         }
1753 
1754         /* Hand it back */
1755         *ret = sv;
1756         return 0;
1757 }
1758 
1759 /*
1760  * Get vnode for the root of the filesystem.
1761  * The root vnode is always found in block 1 (SFS_ROOT_LOCATION).
1762  */
1763 struct vnode *
1764 sfs_getroot(struct fs *fs)
1765 {
1766         struct sfs_fs *sfs = fs->fs_data;
1767         struct sfs_vnode *sv;
1768         int result;
1769 
1770         vfs_biglock_acquire();
1771 
1772         result = sfs_loadvnode(sfs, SFS_ROOT_LOCATION, SFS_TYPE_INVAL, &sv);
1773         if (result) {
1774                 panic("sfs: getroot: Cannot load root vnode\n");
1775         }
1776 
1777         vfs_biglock_release();
1778 
1779         return &sv->sv_v;
1780 }

/* [<][>][^][v][top][bottom][index][help] */