os161-1.99
 All Data Structures
sfs_vnode.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * SFS filesystem
00032  *
00033  * File-level (vnode) interface routines.
00034  */
00035 #include <types.h>
00036 #include <kern/errno.h>
00037 #include <kern/fcntl.h>
00038 #include <stat.h>
00039 #include <lib.h>
00040 #include <array.h>
00041 #include <bitmap.h>
00042 #include <uio.h>
00043 #include <synch.h>
00044 #include <vfs.h>
00045 #include <device.h>
00046 #include <sfs.h>
00047 
00048 /* At bottom of file */
00049 static int sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int type,
00050                          struct sfs_vnode **ret);
00051 
00052 ////////////////////////////////////////////////////////////
00053 //
00054 // Simple stuff
00055 
00056 /* Zero out a disk block. */
00057 static
00058 int
00059 sfs_clearblock(struct sfs_fs *sfs, uint32_t block)
00060 {
00061         /* static -> automatically initialized to zero */
00062         static char zeros[SFS_BLOCKSIZE];
00063         return sfs_wblock(sfs, zeros, block);
00064 }
00065 
00066 /* Write an on-disk inode structure back out to disk. */
00067 static
00068 int
00069 sfs_sync_inode(struct sfs_vnode *sv)
00070 {
00071         if (sv->sv_dirty) {
00072                 struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
00073                 int result = sfs_wblock(sfs, &sv->sv_i, sv->sv_ino);
00074                 if (result) {
00075                         return result;
00076                 }
00077                 sv->sv_dirty = false;
00078         }
00079         return 0;
00080 }
00081 
00082 ////////////////////////////////////////////////////////////
00083 //
00084 // Space allocation
00085 
00086 /*
00087  * Allocate a block.
00088  */
00089 static
00090 int
00091 sfs_balloc(struct sfs_fs *sfs, uint32_t *diskblock)
00092 {
00093         int result;
00094 
00095         result = bitmap_alloc(sfs->sfs_freemap, diskblock);
00096         if (result) {
00097                 return result;
00098         }
00099         sfs->sfs_freemapdirty = true;
00100 
00101         if (*diskblock >= sfs->sfs_super.sp_nblocks) {
00102                 panic("sfs: balloc: invalid block %u\n", *diskblock);
00103         }
00104 
00105         /* Clear block before returning it */
00106         return sfs_clearblock(sfs, *diskblock);
00107 }
00108 
00109 /*
00110  * Free a block.
00111  */
00112 static
00113 void
00114 sfs_bfree(struct sfs_fs *sfs, uint32_t diskblock)
00115 {
00116         bitmap_unmark(sfs->sfs_freemap, diskblock);
00117         sfs->sfs_freemapdirty = true;
00118 }
00119 
00120 /*
00121  * Check if a block is in use.
00122  */
00123 static
00124 int
00125 sfs_bused(struct sfs_fs *sfs, uint32_t diskblock)
00126 {
00127         if (diskblock >= sfs->sfs_super.sp_nblocks) {
00128                 panic("sfs: sfs_bused called on out of range block %u\n", 
00129                       diskblock);
00130         }
00131         return bitmap_isset(sfs->sfs_freemap, diskblock);
00132 }
00133 
00134 ////////////////////////////////////////////////////////////
00135 //
00136 // Block mapping/inode maintenance
00137 
00138 /*
00139  * Look up the disk block number (from 0 up to the number of blocks on
00140  * the disk) given a file and the logical block number within that
00141  * file. If DOALLOC is set, and no such block exists, one will be
00142  * allocated.
00143  */
00144 static
00145 int
00146 sfs_bmap(struct sfs_vnode *sv, uint32_t fileblock, int doalloc,
00147          uint32_t *diskblock)
00148 {
00149         /*
00150          * I/O buffer for handling indirect blocks.
00151          *
00152          * Note: in real life (and when you've done the fs assignment)
00153          * you would get space from the disk buffer cache for this,
00154          * not use a static area.
00155          */
00156         static uint32_t idbuf[SFS_DBPERIDB];
00157 
00158         struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
00159         uint32_t block;
00160         uint32_t idblock;
00161         uint32_t idnum, idoff;
00162         int result;
00163 
00164         KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
00165 
00166         /*
00167          * If the block we want is one of the direct blocks...
00168          */
00169         if (fileblock < SFS_NDIRECT) {
00170                 /*
00171                  * Get the block number
00172                  */
00173                 block = sv->sv_i.sfi_direct[fileblock];
00174 
00175                 /*
00176                  * Do we need to allocate?
00177                  */
00178                 if (block==0 && doalloc) {
00179                         result = sfs_balloc(sfs, &block);
00180                         if (result) {
00181                                 return result;
00182                         }
00183 
00184                         /* Remember what we allocated; mark inode dirty */
00185                         sv->sv_i.sfi_direct[fileblock] = block;
00186                         sv->sv_dirty = true;
00187                 }
00188 
00189                 /*
00190                  * Hand back the block
00191                  */
00192                 if (block != 0 && !sfs_bused(sfs, block)) {
00193                         panic("sfs: Data block %u (block %u of file %u) "
00194                               "marked free\n", block, fileblock, sv->sv_ino);
00195                 }
00196                 *diskblock = block;
00197                 return 0;
00198         }
00199 
00200         /*
00201          * It's not a direct block; it must be in the indirect block.
00202          * Subtract off the number of direct blocks, so FILEBLOCK is
00203          * now the offset into the indirect block space.
00204          */
00205 
00206         fileblock -= SFS_NDIRECT;
00207 
00208         /* Get the indirect block number and offset w/i that indirect block */
00209         idnum = fileblock / SFS_DBPERIDB;
00210         idoff = fileblock % SFS_DBPERIDB;
00211 
00212         /*
00213          * We only have one indirect block. If the offset we were asked for
00214          * is too large, we can't handle it, so fail.
00215          */
00216         if (idnum > 0) {
00217                 return EFBIG;
00218         }
00219 
00220         /* Get the disk block number of the indirect block. */
00221         idblock = sv->sv_i.sfi_indirect;
00222 
00223         if (idblock==0 && !doalloc) {
00224                 /*
00225                  * There's no indirect block allocated. We weren't
00226                  * asked to allocate anything, so pretend the indirect
00227                  * block was filled with all zeros.
00228                  */
00229                 *diskblock = 0;
00230                 return 0;
00231         }
00232         else if (idblock==0) {
00233                 /*
00234                  * There's no indirect block allocated, but we need to
00235                  * allocate a block whose number needs to be stored in
00236                  * the indirect block. Thus, we need to allocate an
00237                  * indirect block.
00238                  */
00239                 result = sfs_balloc(sfs, &idblock);
00240                 if (result) {
00241                         return result;
00242                 }
00243 
00244                 /* Remember the block we just allocated */
00245                 sv->sv_i.sfi_indirect = idblock;
00246 
00247                 /* Mark the inode dirty */
00248                 sv->sv_dirty = true;
00249 
00250                 /* Clear the indirect block buffer */
00251                 bzero(idbuf, sizeof(idbuf));
00252         }
00253         else {
00254                 /*
00255                  * We already have an indirect block allocated; load it.
00256                  */
00257                 result = sfs_rblock(sfs, idbuf, idblock);
00258                 if (result) {
00259                         return result;
00260                 }
00261         }
00262 
00263         /* Get the block out of the indirect block buffer */
00264         block = idbuf[idoff];
00265 
00266         /* If there's no block there, allocate one */
00267         if (block==0 && doalloc) {
00268                 result = sfs_balloc(sfs, &block);
00269                 if (result) {
00270                         return result;
00271                 }
00272 
00273                 /* Remember the block we allocated */
00274                 idbuf[idoff] = block;
00275 
00276                 /* The indirect block is now dirty; write it back */
00277                 result = sfs_wblock(sfs, idbuf, idblock);
00278                 if (result) {
00279                         return result;
00280                 }
00281         }
00282 
00283         /* Hand back the result and return. */
00284         if (block != 0 && !sfs_bused(sfs, block)) {
00285                 panic("sfs: Data block %u (block %u of file %u) marked free\n",
00286                       block, fileblock, sv->sv_ino);
00287         }
00288         *diskblock = block;
00289         return 0;
00290 }
00291 
00292 ////////////////////////////////////////////////////////////
00293 //
00294 // File-level I/O
00295 
00296 /*
00297  * Do I/O to a block of a file that doesn't cover the whole block.  We
00298  * need to read in the original block first, even if we're writing, so
00299  * we don't clobber the portion of the block we're not intending to
00300  * write over.
00301  *
00302  * skipstart is the number of bytes to skip past at the beginning of
00303  * the sector; len is the number of bytes to actually read or write.
00304  * uio is the area to do the I/O into.
00305  */
00306 static
00307 int
00308 sfs_partialio(struct sfs_vnode *sv, struct uio *uio,
00309               uint32_t skipstart, uint32_t len)
00310 {
00311         /*
00312          * I/O buffer for handling partial sectors.
00313          *
00314          * Note: in real life (and when you've done the fs assignment)
00315          * you would get space from the disk buffer cache for this,
00316          * not use a static area.
00317          */
00318         static char iobuf[SFS_BLOCKSIZE];
00319 
00320         struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
00321         uint32_t diskblock;
00322         uint32_t fileblock;
00323         int result;
00324         
00325         /* Allocate missing blocks if and only if we're writing */
00326         int doalloc = (uio->uio_rw==UIO_WRITE);
00327 
00328         KASSERT(skipstart + len <= SFS_BLOCKSIZE);
00329 
00330         /* Compute the block offset of this block in the file */
00331         fileblock = uio->uio_offset / SFS_BLOCKSIZE;
00332 
00333         /* Get the disk block number */
00334         result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
00335         if (result) {
00336                 return result;
00337         }
00338 
00339         if (diskblock == 0) {
00340                 /*
00341                  * There was no block mapped at this point in the file.
00342                  * Zero the buffer.
00343                  */
00344                 KASSERT(uio->uio_rw == UIO_READ);
00345                 bzero(iobuf, sizeof(iobuf));
00346         }
00347         else {
00348                 /*
00349                  * Read the block.
00350                  */
00351                 result = sfs_rblock(sfs, iobuf, diskblock);
00352                 if (result) {
00353                         return result;
00354                 }
00355         }
00356 
00357         /*
00358          * Now perform the requested operation into/out of the buffer.
00359          */
00360         result = uiomove(iobuf+skipstart, len, uio);
00361         if (result) {
00362                 return result;
00363         }
00364 
00365         /*
00366          * If it was a write, write back the modified block.
00367          */
00368         if (uio->uio_rw == UIO_WRITE) {
00369                 result = sfs_wblock(sfs, iobuf, diskblock);
00370                 if (result) {
00371                         return result;
00372                 }
00373         }
00374 
00375         return 0;
00376 }
00377 
00378 /*
00379  * Do I/O (either read or write) of a single whole block.
00380  */
00381 static
00382 int
00383 sfs_blockio(struct sfs_vnode *sv, struct uio *uio)
00384 {
00385         struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
00386         uint32_t diskblock;
00387         uint32_t fileblock;
00388         int result;
00389         int doalloc = (uio->uio_rw==UIO_WRITE);
00390         off_t saveoff;
00391         off_t diskoff;
00392         off_t saveres;
00393         off_t diskres;
00394 
00395         /* Get the block number within the file */
00396         fileblock = uio->uio_offset / SFS_BLOCKSIZE;
00397 
00398         /* Look up the disk block number */
00399         result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
00400         if (result) {
00401                 return result;
00402         }
00403 
00404         if (diskblock == 0) {
00405                 /*
00406                  * No block - fill with zeros.
00407                  *
00408                  * We must be reading, or sfs_bmap would have
00409                  * allocated a block for us.
00410                  */
00411                 KASSERT(uio->uio_rw == UIO_READ);
00412                 return uiomovezeros(SFS_BLOCKSIZE, uio);
00413         }
00414 
00415         /*
00416          * Do the I/O directly to the uio region. Save the uio_offset,
00417          * and substitute one that makes sense to the device.
00418          */
00419         saveoff = uio->uio_offset;
00420         diskoff = diskblock * SFS_BLOCKSIZE;
00421         uio->uio_offset = diskoff;
00422 
00423         /*
00424          * Temporarily set the residue to be one block size.
00425          */
00426         KASSERT(uio->uio_resid >= SFS_BLOCKSIZE);
00427         saveres = uio->uio_resid;
00428         diskres = SFS_BLOCKSIZE;
00429         uio->uio_resid = diskres;
00430         
00431         result = sfs_rwblock(sfs, uio);
00432 
00433         /*
00434          * Now, restore the original uio_offset and uio_resid and update 
00435          * them by the amount of I/O done.
00436          */
00437         uio->uio_offset = (uio->uio_offset - diskoff) + saveoff;
00438         uio->uio_resid = (uio->uio_resid - diskres) + saveres;
00439 
00440         return result;
00441 }
00442 
00443 /*
00444  * Do I/O of a whole region of data, whether or not it's block-aligned.
00445  */
00446 static
00447 int
00448 sfs_io(struct sfs_vnode *sv, struct uio *uio)
00449 {
00450         uint32_t blkoff;
00451         uint32_t nblocks, i;
00452         int result = 0;
00453         uint32_t extraresid = 0;
00454 
00455         /*
00456          * If reading, check for EOF. If we can read a partial area,
00457          * remember how much extra there was in EXTRARESID so we can
00458          * add it back to uio_resid at the end.
00459          */
00460         if (uio->uio_rw == UIO_READ) {
00461                 off_t size = sv->sv_i.sfi_size;
00462                 off_t endpos = uio->uio_offset + uio->uio_resid;
00463 
00464                 if (uio->uio_offset >= size) {
00465                         /* At or past EOF - just return */
00466                         return 0;
00467                 }
00468 
00469                 if (endpos > size) {
00470                         extraresid = endpos - size;
00471                         KASSERT(uio->uio_resid > extraresid);
00472                         uio->uio_resid -= extraresid;
00473                 }
00474         }
00475 
00476         /*
00477          * First, do any leading partial block.
00478          */
00479         blkoff = uio->uio_offset % SFS_BLOCKSIZE;
00480         if (blkoff != 0) {
00481                 /* Number of bytes at beginning of block to skip */
00482                 uint32_t skip = blkoff;
00483 
00484                 /* Number of bytes to read/write after that point */
00485                 uint32_t len = SFS_BLOCKSIZE - blkoff;
00486 
00487                 /* ...which might be less than the rest of the block */
00488                 if (len > uio->uio_resid) {
00489                         len = uio->uio_resid;
00490                 }
00491 
00492                 /* Call sfs_partialio() to do it. */
00493                 result = sfs_partialio(sv, uio, skip, len);
00494                 if (result) {
00495                         goto out;
00496                 }
00497         }
00498 
00499         /* If we're done, quit. */
00500         if (uio->uio_resid==0) {
00501                 goto out;
00502         }
00503 
00504         /*
00505          * Now we should be block-aligned. Do the remaining whole blocks.
00506          */
00507         KASSERT(uio->uio_offset % SFS_BLOCKSIZE == 0);
00508         nblocks = uio->uio_resid / SFS_BLOCKSIZE;
00509         for (i=0; i<nblocks; i++) {
00510                 result = sfs_blockio(sv, uio);
00511                 if (result) {
00512                         goto out;
00513                 }
00514         }
00515 
00516         /*
00517          * Now do any remaining partial block at the end.
00518          */
00519         KASSERT(uio->uio_resid < SFS_BLOCKSIZE);
00520 
00521         if (uio->uio_resid > 0) {
00522                 result = sfs_partialio(sv, uio, 0, uio->uio_resid);
00523                 if (result) {
00524                         goto out;
00525                 }
00526         }
00527 
00528  out:
00529 
00530         /* If writing, adjust file length */
00531         if (uio->uio_rw == UIO_WRITE && 
00532             uio->uio_offset > (off_t)sv->sv_i.sfi_size) {
00533                 sv->sv_i.sfi_size = uio->uio_offset;
00534                 sv->sv_dirty = true;
00535         }
00536 
00537         /* Add in any extra amount we couldn't read because of EOF */
00538         uio->uio_resid += extraresid;
00539 
00540         /* Done */
00541         return result;
00542 }
00543 
00544 ////////////////////////////////////////////////////////////
00545 //
00546 // Directory I/O
00547 
00548 /*
00549  * Read the directory entry out of slot SLOT of a directory vnode.
00550  * The "slot" is the index of the directory entry, starting at 0.
00551  */
00552 static
00553 int
00554 sfs_readdir(struct sfs_vnode *sv, struct sfs_dir *sd, int slot)
00555 {
00556         struct iovec iov;
00557         struct uio ku;
00558         off_t actualpos;
00559         int result;
00560 
00561         /* Compute the actual position in the directory to read. */
00562         actualpos = slot * sizeof(struct sfs_dir);
00563 
00564         /* Set up a uio to do the read */ 
00565         uio_kinit(&iov, &ku, sd, sizeof(struct sfs_dir), actualpos, UIO_READ);
00566 
00567         /* do it */
00568         result = sfs_io(sv, &ku);
00569         if (result) {
00570                 return result;
00571         }
00572 
00573         /* We should not hit EOF in the middle of a directory entry */
00574         if (ku.uio_resid > 0) {
00575                 panic("sfs: readdir: Short entry (inode %u)\n", sv->sv_ino);
00576         }
00577 
00578         /* Done */
00579         return 0;
00580 }
00581 
00582 /*
00583  * Write (overwrite) the directory entry in slot SLOT of a directory
00584  * vnode.
00585  */
00586 static
00587 int
00588 sfs_writedir(struct sfs_vnode *sv, struct sfs_dir *sd, int slot)
00589 {
00590         struct iovec iov;
00591         struct uio ku;
00592         off_t actualpos;
00593         int result;
00594 
00595         /* Compute the actual position in the directory. */
00596         KASSERT(slot>=0);
00597         actualpos = slot * sizeof(struct sfs_dir);
00598 
00599         /* Set up a uio to do the write */ 
00600         uio_kinit(&iov, &ku, sd, sizeof(struct sfs_dir), actualpos, UIO_WRITE);
00601 
00602         /* do it */
00603         result = sfs_io(sv, &ku);
00604         if (result) {
00605                 return result;
00606         }
00607 
00608         /* Should not end up with a partial entry! */
00609         if (ku.uio_resid > 0) {
00610                 panic("sfs: writedir: Short write (ino %u)\n", sv->sv_ino);
00611         }
00612 
00613         /* Done */
00614         return 0;
00615 }
00616 
00617 /*
00618  * Compute the number of entries in a directory.
00619  * This actually computes the number of existing slots, and does not
00620  * account for empty slots.
00621  */
00622 static
00623 int
00624 sfs_dir_nentries(struct sfs_vnode *sv)
00625 {
00626         off_t size;
00627 
00628         KASSERT(sv->sv_i.sfi_type == SFS_TYPE_DIR);
00629 
00630         size = sv->sv_i.sfi_size;
00631         if (size % sizeof(struct sfs_dir) != 0) {
00632                 panic("sfs: directory %u: Invalid size %llu\n",
00633                       sv->sv_ino, size);
00634         }
00635 
00636         return size / sizeof(struct sfs_dir);
00637 }
00638 
00639 /*
00640  * Search a directory for a particular filename in a directory, and
00641  * return its inode number, its slot, and/or the slot number of an
00642  * empty directory slot if one is found.
00643  */
00644 
00645 static
00646 int
00647 sfs_dir_findname(struct sfs_vnode *sv, const char *name,
00648                     uint32_t *ino, int *slot, int *emptyslot)
00649 {
00650         struct sfs_dir tsd;
00651         int found = 0;
00652         int nentries = sfs_dir_nentries(sv);
00653         int i, result;
00654 
00655         /* For each slot... */
00656         for (i=0; i<nentries; i++) {
00657 
00658                 /* Read the entry from that slot */
00659                 result = sfs_readdir(sv, &tsd, i);
00660                 if (result) {
00661                         return result;
00662                 }
00663                 if (tsd.sfd_ino == SFS_NOINO) {
00664                         /* Free slot - report it back if one was requested */
00665                         if (emptyslot != NULL) {
00666                                 *emptyslot = i;
00667                         }
00668                 }
00669                 else {
00670                         /* Ensure null termination, just in case */
00671                         tsd.sfd_name[sizeof(tsd.sfd_name)-1] = 0;
00672                         if (!strcmp(tsd.sfd_name, name)) {
00673 
00674                                 /* Each name may legally appear only once... */
00675                                 KASSERT(found==0);
00676 
00677                                 found = 1;
00678                                 if (slot != NULL) {
00679                                         *slot = i;
00680                                 }
00681                                 if (ino != NULL) {
00682                                         *ino = tsd.sfd_ino;
00683                                 }
00684                         }
00685                 }
00686         }
00687 
00688         return found ? 0 : ENOENT;
00689 }
00690 
00691 /*
00692  * Create a link in a directory to the specified inode by number, with
00693  * the specified name, and optionally hand back the slot.
00694  */
00695 static
00696 int
00697 sfs_dir_link(struct sfs_vnode *sv, const char *name, uint32_t ino, int *slot)
00698 {
00699         int emptyslot = -1;
00700         int result;
00701         struct sfs_dir sd;
00702 
00703         /* Look up the name. We want to make sure it *doesn't* exist. */
00704         result = sfs_dir_findname(sv, name, NULL, NULL, &emptyslot);
00705         if (result!=0 && result!=ENOENT) {
00706                 return result;
00707         }
00708         if (result==0) {
00709                 return EEXIST;
00710         }
00711 
00712         if (strlen(name)+1 > sizeof(sd.sfd_name)) {
00713                 return ENAMETOOLONG;
00714         }
00715 
00716         /* If we didn't get an empty slot, add the entry at the end. */
00717         if (emptyslot < 0) {
00718                 emptyslot = sfs_dir_nentries(sv);
00719         }
00720 
00721         /* Set up the entry. */
00722         bzero(&sd, sizeof(sd));
00723         sd.sfd_ino = ino;
00724         strcpy(sd.sfd_name, name);
00725 
00726         /* Hand back the slot, if so requested. */
00727         if (slot) {
00728                 *slot = emptyslot;
00729         }
00730 
00731         /* Write the entry. */
00732         return sfs_writedir(sv, &sd, emptyslot);
00733         
00734 }
00735 
00736 /*
00737  * Unlink a name in a directory, by slot number.
00738  */
00739 static
00740 int
00741 sfs_dir_unlink(struct sfs_vnode *sv, int slot)
00742 {
00743         struct sfs_dir sd;
00744 
00745         /* Initialize a suitable directory entry... */ 
00746         bzero(&sd, sizeof(sd));
00747         sd.sfd_ino = SFS_NOINO;
00748 
00749         /* ... and write it */
00750         return sfs_writedir(sv, &sd, slot);
00751 }
00752 
00753 /*
00754  * Look for a name in a directory and hand back a vnode for the
00755  * file, if there is one.
00756  */
00757 static
00758 int
00759 sfs_lookonce(struct sfs_vnode *sv, const char *name, 
00760                 struct sfs_vnode **ret,
00761                 int *slot)
00762 {
00763         struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
00764         uint32_t ino;
00765         int result;
00766 
00767         result = sfs_dir_findname(sv, name, &ino, slot, NULL);
00768         if (result) {
00769                 return result;
00770         }
00771 
00772         result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, ret);
00773         if (result) {
00774                 return result;
00775         }
00776 
00777         if ((*ret)->sv_i.sfi_linkcount == 0) {
00778                 panic("sfs: Link count of file %u found in dir %u is 0\n",
00779                       (*ret)->sv_ino, sv->sv_ino);
00780         }
00781 
00782         return 0;
00783 }
00784 
00785 ////////////////////////////////////////////////////////////
00786 //
00787 // Object creation
00788 
00789 /*
00790  * Create a new filesystem object and hand back its vnode.
00791  */
00792 static
00793 int
00794 sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret)
00795 {
00796         uint32_t ino;
00797         int result;
00798 
00799         /*
00800          * First, get an inode. (Each inode is a block, and the inode 
00801          * number is the block number, so just get a block.)
00802          */
00803 
00804         result = sfs_balloc(sfs, &ino);
00805         if (result) {
00806                 return result;
00807         }
00808 
00809         /*
00810          * Now load a vnode for it.
00811          */
00812 
00813         return sfs_loadvnode(sfs, ino, type, ret);
00814 }
00815 
00816 ////////////////////////////////////////////////////////////
00817 //
00818 // Vnode ops
00819 
00820 /*
00821  * This is called on *each* open().
00822  */
00823 static
00824 int
00825 sfs_open(struct vnode *v, int openflags)
00826 {
00827         /*
00828          * At this level we do not need to handle O_CREAT, O_EXCL, or O_TRUNC.
00829          * We *would* need to handle O_APPEND, but we don't support it.
00830          *
00831          * Any of O_RDONLY, O_WRONLY, and O_RDWR are valid, so we don't need
00832          * to check that either.
00833          */
00834 
00835         if (openflags & O_APPEND) {
00836                 return EUNIMP;
00837         }
00838 
00839         (void)v;
00840 
00841         return 0;
00842 }
00843 
00844 /*
00845  * This is called on *each* open() of a directory.
00846  * Directories may only be open for read.
00847  */
00848 static
00849 int
00850 sfs_opendir(struct vnode *v, int openflags)
00851 {
00852         switch (openflags & O_ACCMODE) {
00853             case O_RDONLY:
00854                 break;
00855             case O_WRONLY:
00856             case O_RDWR:
00857             default:
00858                 return EISDIR;
00859         }
00860         if (openflags & O_APPEND) {
00861                 return EISDIR;
00862         }
00863 
00864         (void)v;
00865         return 0;
00866 }
00867 
00868 /*
00869  * Called on the *last* close().
00870  *
00871  * This function should attempt to avoid returning errors, as handling
00872  * them usefully is often not possible.
00873  */
00874 static
00875 int
00876 sfs_close(struct vnode *v)
00877 {
00878         /* Sync it. */
00879         return VOP_FSYNC(v);
00880 }
00881 
00882 /*
00883  * Called when the vnode refcount (in-memory usage count) hits zero.
00884  *
00885  * This function should try to avoid returning errors other than EBUSY.
00886  */
00887 static
00888 int
00889 sfs_reclaim(struct vnode *v)
00890 {
00891         struct sfs_vnode *sv = v->vn_data;
00892         struct sfs_fs *sfs = v->vn_fs->fs_data;
00893         unsigned ix, i, num;
00894         int result;
00895 
00896         vfs_biglock_acquire();
00897 
00898         /*
00899          * Make sure someone else hasn't picked up the vnode since the
00900          * decision was made to reclaim it. (You must also synchronize
00901          * this with sfs_loadvnode.)
00902          */
00903         if (v->vn_refcount != 1) {
00904 
00905                 /* consume the reference VOP_DECREF gave us */
00906                 KASSERT(v->vn_refcount>1);
00907                 v->vn_refcount--;
00908 
00909                 vfs_biglock_release();
00910                 return EBUSY;
00911         }
00912 
00913         /* If there are no on-disk references to the file either, erase it. */
00914         if (sv->sv_i.sfi_linkcount==0) {
00915                 result = VOP_TRUNCATE(&sv->sv_v, 0);
00916                 if (result) {
00917                         vfs_biglock_release();
00918                         return result;
00919                 }
00920         }
00921 
00922         /* Sync the inode to disk */
00923         result = sfs_sync_inode(sv);
00924         if (result) {
00925                 vfs_biglock_release();
00926                 return result;
00927         }
00928 
00929         /* If there are no on-disk references, discard the inode */
00930         if (sv->sv_i.sfi_linkcount==0) {
00931                 sfs_bfree(sfs, sv->sv_ino);
00932         }
00933 
00934         /* Remove the vnode structure from the table in the struct sfs_fs. */
00935         num = vnodearray_num(sfs->sfs_vnodes);
00936         ix = num;
00937         for (i=0; i<num; i++) {
00938                 struct vnode *v2 = vnodearray_get(sfs->sfs_vnodes, i);
00939                 struct sfs_vnode *sv2 = v2->vn_data;
00940                 if (sv2 == sv) {
00941                         ix = i;
00942                         break;
00943                 }
00944         }
00945         if (ix == num) {
00946                 panic("sfs: reclaim vnode %u not in vnode pool\n",
00947                       sv->sv_ino);
00948         }
00949         vnodearray_remove(sfs->sfs_vnodes, ix);
00950 
00951         VOP_CLEANUP(&sv->sv_v);
00952 
00953         vfs_biglock_release();
00954 
00955         /* Release the storage for the vnode structure itself. */
00956         kfree(sv);
00957 
00958         /* Done */
00959         return 0;
00960 }
00961 
00962 /*
00963  * Called for read(). sfs_io() does the work.
00964  */
00965 static
00966 int
00967 sfs_read(struct vnode *v, struct uio *uio)
00968 {
00969         struct sfs_vnode *sv = v->vn_data;
00970         int result;
00971 
00972         KASSERT(uio->uio_rw==UIO_READ);
00973 
00974         vfs_biglock_acquire();
00975         result = sfs_io(sv, uio);
00976         vfs_biglock_release();
00977 
00978         return result;
00979 }
00980 
00981 /*
00982  * Called for write(). sfs_io() does the work.
00983  */
00984 static
00985 int
00986 sfs_write(struct vnode *v, struct uio *uio)
00987 {
00988         struct sfs_vnode *sv = v->vn_data;
00989         int result;
00990 
00991         KASSERT(uio->uio_rw==UIO_WRITE);
00992 
00993         vfs_biglock_acquire();
00994         result = sfs_io(sv, uio);
00995         vfs_biglock_release();
00996 
00997         return result;
00998 }
00999 
01000 /*
01001  * Called for ioctl()
01002  */
01003 static
01004 int
01005 sfs_ioctl(struct vnode *v, int op, userptr_t data)
01006 {
01007         /*
01008          * No ioctls.
01009          */
01010 
01011         (void)v;
01012         (void)op;
01013         (void)data;
01014 
01015         return EINVAL;
01016 }
01017 
01018 /*
01019  * Called for stat/fstat/lstat.
01020  */
01021 static
01022 int
01023 sfs_stat(struct vnode *v, struct stat *statbuf)
01024 {
01025         struct sfs_vnode *sv = v->vn_data;
01026         int result;
01027 
01028         /* Fill in the stat structure */
01029         bzero(statbuf, sizeof(struct stat));
01030 
01031         result = VOP_GETTYPE(v, &statbuf->st_mode);
01032         if (result) {
01033                 return result;
01034         }
01035 
01036         statbuf->st_size = sv->sv_i.sfi_size;
01037 
01038         /* We don't support these yet; you get to implement them */
01039         statbuf->st_nlink = 0;
01040         statbuf->st_blocks = 0;
01041 
01042         /* Fill in other field as desired/possible... */
01043 
01044         return 0;
01045 }
01046 
01047 /*
01048  * Return the type of the file (types as per kern/stat.h)
01049  */
01050 static
01051 int
01052 sfs_gettype(struct vnode *v, uint32_t *ret)
01053 {
01054         struct sfs_vnode *sv = v->vn_data;
01055 
01056         vfs_biglock_acquire();
01057 
01058         switch (sv->sv_i.sfi_type) {
01059         case SFS_TYPE_FILE:
01060                 *ret = S_IFREG;
01061                 vfs_biglock_release();
01062                 return 0;
01063         case SFS_TYPE_DIR:
01064                 *ret = S_IFDIR;
01065                 vfs_biglock_release();
01066                 return 0;
01067         }
01068         panic("sfs: gettype: Invalid inode type (inode %u, type %u)\n",
01069               sv->sv_ino, sv->sv_i.sfi_type);
01070         return EINVAL;
01071 }
01072 
01073 /*
01074  * Check for legal seeks on files. Allow anything non-negative.
01075  * We could conceivably, here, prohibit seeking past the maximum
01076  * file size our inode structure can support, but we don't - few
01077  * people ever bother to check lseek() for failure and having 
01078  * read() or write() fail is sufficient.
01079  */
01080 static
01081 int
01082 sfs_tryseek(struct vnode *v, off_t pos)
01083 {
01084         if (pos<0) {
01085                 return EINVAL;
01086         }
01087 
01088         /* Allow anything else */
01089         (void)v;
01090 
01091         return 0;
01092 }
01093 
01094 /*
01095  * Called for fsync(), and also on filesystem unmount, global sync(),
01096  * and some other cases.
01097  */
01098 static
01099 int
01100 sfs_fsync(struct vnode *v)
01101 {
01102         struct sfs_vnode *sv = v->vn_data;
01103         int result;
01104 
01105         vfs_biglock_acquire();
01106         result = sfs_sync_inode(sv);
01107         vfs_biglock_release();
01108 
01109         return result;
01110 }
01111 
01112 /*
01113  * Called for mmap().
01114  */
01115 static
01116 int
01117 sfs_mmap(struct vnode *v   /* add stuff as needed */)
01118 {
01119         (void)v;
01120         return EUNIMP;
01121 }
01122 
01123 /*
01124  * Called for ftruncate() and from sfs_reclaim.
01125  */
01126 static
01127 int
01128 sfs_truncate(struct vnode *v, off_t len)
01129 {
01130         /*
01131          * I/O buffer for handling the indirect block.
01132          *
01133          * Note: in real life (and when you've done the fs assignment)
01134          * you would get space from the disk buffer cache for this,
01135          * not use a static area.
01136          */
01137         static uint32_t idbuf[SFS_DBPERIDB];
01138 
01139         struct sfs_vnode *sv = v->vn_data;
01140         struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
01141 
01142         /* Length in blocks (divide rounding up) */
01143         uint32_t blocklen = DIVROUNDUP(len, SFS_BLOCKSIZE);
01144 
01145         uint32_t i, j, block;
01146         uint32_t idblock, baseblock, highblock;
01147         int result;
01148         int hasnonzero, iddirty;
01149 
01150         KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
01151 
01152         vfs_biglock_acquire();
01153 
01154         /*
01155          * Go through the direct blocks. Discard any that are
01156          * past the limit we're truncating to.
01157          */
01158         for (i=0; i<SFS_NDIRECT; i++) {
01159                 block = sv->sv_i.sfi_direct[i];
01160                 if (i >= blocklen && block != 0) {
01161                         sfs_bfree(sfs, block);
01162                         sv->sv_i.sfi_direct[i] = 0;
01163                         sv->sv_dirty = true;
01164                 }
01165         }
01166 
01167         /* Indirect block number */
01168         idblock = sv->sv_i.sfi_indirect;
01169 
01170         /* The lowest block in the indirect block */
01171         baseblock = SFS_NDIRECT;
01172 
01173         /* The highest block in the indirect block */
01174         highblock = baseblock + SFS_DBPERIDB - 1;
01175 
01176         if (blocklen < highblock && idblock != 0) {
01177                 /* We're past the proposed EOF; may need to free stuff */
01178 
01179                 /* Read the indirect block */
01180                 result = sfs_rblock(sfs, idbuf, idblock);
01181                 if (result) {
01182                         vfs_biglock_release();
01183                         return result;
01184                 }
01185                 
01186                 hasnonzero = 0;
01187                 iddirty = 0;
01188                 for (j=0; j<SFS_DBPERIDB; j++) {
01189                         /* Discard any blocks that are past the new EOF */
01190                         if (blocklen < baseblock+j && idbuf[j] != 0) {
01191                                 sfs_bfree(sfs, idbuf[j]);
01192                                 idbuf[j] = 0;
01193                                 iddirty = 1;
01194                         }
01195                         /* Remember if we see any nonzero blocks in here */
01196                         if (idbuf[j]!=0) {
01197                                 hasnonzero=1;
01198                         }
01199                 }
01200 
01201                 if (!hasnonzero) {
01202                         /* The whole indirect block is empty now; free it */
01203                         sfs_bfree(sfs, idblock);
01204                         sv->sv_i.sfi_indirect = 0;
01205                         sv->sv_dirty = true;
01206                 }
01207                 else if (iddirty) {
01208                         /* The indirect block is dirty; write it back */
01209                         result = sfs_wblock(sfs, idbuf, idblock);
01210                         if (result) {
01211                                 vfs_biglock_release();
01212                                 return result;
01213                         }
01214                 }
01215         }
01216 
01217         /* Set the file size */
01218         sv->sv_i.sfi_size = len;
01219 
01220         /* Mark the inode dirty */
01221         sv->sv_dirty = true;
01222 
01223         vfs_biglock_release();
01224         return 0;
01225 }
01226 
01227 /*
01228  * Get the full pathname for a file. This only needs to work on directories.
01229  * Since we don't support subdirectories, assume it's the root directory
01230  * and hand back the empty string. (The VFS layer takes care of the
01231  * device name, leading slash, etc.)
01232  */
01233 static
01234 int
01235 sfs_namefile(struct vnode *vv, struct uio *uio)
01236 {
01237         struct sfs_vnode *sv = vv->vn_data;
01238         KASSERT(sv->sv_ino == SFS_ROOT_LOCATION);
01239 
01240         /* send back the empty string - just return */
01241 
01242         (void)uio;
01243 
01244         return 0;
01245 }
01246 
01247 /*
01248  * Create a file. If EXCL is set, insist that the filename not already
01249  * exist; otherwise, if it already exists, just open it.
01250  */
01251 static
01252 int
01253 sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
01254           struct vnode **ret)
01255 {
01256         struct sfs_fs *sfs = v->vn_fs->fs_data;
01257         struct sfs_vnode *sv = v->vn_data;
01258         struct sfs_vnode *newguy;
01259         uint32_t ino;
01260         int result;
01261 
01262         vfs_biglock_acquire();
01263 
01264         /* Look up the name */
01265         result = sfs_dir_findname(sv, name, &ino, NULL, NULL);
01266         if (result!=0 && result!=ENOENT) {
01267                 vfs_biglock_release();
01268                 return result;
01269         }
01270 
01271         /* If it exists and we didn't want it to, fail */
01272         if (result==0 && excl) {
01273                 vfs_biglock_release();
01274                 return EEXIST;
01275         }
01276 
01277         if (result==0) {
01278                 /* We got a file; load its vnode and return */
01279                 result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy);
01280                 if (result) {
01281                         vfs_biglock_release();
01282                         return result;
01283                 }
01284                 *ret = &newguy->sv_v;
01285                 vfs_biglock_release();
01286                 return 0;
01287         }
01288 
01289         /* Didn't exist - create it */
01290         result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy);
01291         if (result) {
01292                 vfs_biglock_release();
01293                 return result;
01294         }
01295 
01296         /* We don't currently support file permissions; ignore MODE */
01297         (void)mode;
01298 
01299         /* Link it into the directory */
01300         result = sfs_dir_link(sv, name, newguy->sv_ino, NULL);
01301         if (result) {
01302                 VOP_DECREF(&newguy->sv_v);
01303                 vfs_biglock_release();
01304                 return result;
01305         }
01306 
01307         /* Update the linkcount of the new file */
01308         newguy->sv_i.sfi_linkcount++;
01309 
01310         /* and consequently mark it dirty. */
01311         newguy->sv_dirty = true;
01312 
01313         *ret = &newguy->sv_v;
01314         
01315         vfs_biglock_release();
01316         return 0;
01317 }
01318 
01319 /*
01320  * Make a hard link to a file.
01321  * The VFS layer should prevent this being called unless both
01322  * vnodes are ours.
01323  */
01324 static
01325 int
01326 sfs_link(struct vnode *dir, const char *name, struct vnode *file)
01327 {
01328         struct sfs_vnode *sv = dir->vn_data;
01329         struct sfs_vnode *f = file->vn_data;
01330         int result;
01331 
01332         KASSERT(file->vn_fs == dir->vn_fs);
01333 
01334         vfs_biglock_acquire();
01335 
01336         /* Just create a link */
01337         result = sfs_dir_link(sv, name, f->sv_ino, NULL);
01338         if (result) {
01339                 vfs_biglock_release();
01340                 return result;
01341         }
01342 
01343         /* and update the link count, marking the inode dirty */
01344         f->sv_i.sfi_linkcount++;
01345         f->sv_dirty = true;
01346 
01347         vfs_biglock_release();
01348         return 0;
01349 }
01350 
01351 /*
01352  * Delete a file.
01353  */
01354 static
01355 int
01356 sfs_remove(struct vnode *dir, const char *name)
01357 {
01358         struct sfs_vnode *sv = dir->vn_data;
01359         struct sfs_vnode *victim;
01360         int slot;
01361         int result;
01362 
01363         vfs_biglock_acquire();
01364 
01365         /* Look for the file and fetch a vnode for it. */
01366         result = sfs_lookonce(sv, name, &victim, &slot);
01367         if (result) {
01368                 vfs_biglock_release();
01369                 return result;
01370         }
01371 
01372         /* Erase its directory entry. */
01373         result = sfs_dir_unlink(sv, slot);
01374         if (result==0) {
01375                 /* If we succeeded, decrement the link count. */
01376                 KASSERT(victim->sv_i.sfi_linkcount > 0);
01377                 victim->sv_i.sfi_linkcount--;
01378                 victim->sv_dirty = true;
01379         }
01380 
01381         /* Discard the reference that sfs_lookonce got us */
01382         VOP_DECREF(&victim->sv_v);
01383 
01384         vfs_biglock_release();
01385         return result;
01386 }
01387 
01388 /*
01389  * Rename a file.
01390  *
01391  * Since we don't support subdirectories, assumes that the two
01392  * directories passed are the same.
01393  */
01394 static
01395 int
01396 sfs_rename(struct vnode *d1, const char *n1, 
01397            struct vnode *d2, const char *n2)
01398 {
01399         struct sfs_vnode *sv = d1->vn_data;
01400         struct sfs_vnode *g1;
01401         int slot1, slot2;
01402         int result, result2;
01403 
01404         vfs_biglock_acquire();
01405 
01406         KASSERT(d1==d2);
01407         KASSERT(sv->sv_ino == SFS_ROOT_LOCATION);
01408 
01409         /* Look up the old name of the file and get its inode and slot number*/
01410         result = sfs_lookonce(sv, n1, &g1, &slot1);
01411         if (result) {
01412                 vfs_biglock_release();
01413                 return result;
01414         }
01415 
01416         /* We don't support subdirectories */
01417         KASSERT(g1->sv_i.sfi_type == SFS_TYPE_FILE);
01418 
01419         /*
01420          * Link it under the new name.
01421          *
01422          * We could theoretically just overwrite the original
01423          * directory entry, except that we need to check to make sure
01424          * the new name doesn't already exist; might as well use the
01425          * existing link routine.
01426          */
01427         result = sfs_dir_link(sv, n2, g1->sv_ino, &slot2);
01428         if (result) {
01429                 goto puke;
01430         }
01431         
01432         /* Increment the link count, and mark inode dirty */
01433         g1->sv_i.sfi_linkcount++;
01434         g1->sv_dirty = true;
01435 
01436         /* Unlink the old slot */
01437         result = sfs_dir_unlink(sv, slot1);
01438         if (result) {
01439                 goto puke_harder;
01440         }
01441 
01442         /*
01443          * Decrement the link count again, and mark the inode dirty again,
01444          * in case it's been synced behind our back.
01445          */
01446         KASSERT(g1->sv_i.sfi_linkcount>0);
01447         g1->sv_i.sfi_linkcount--;
01448         g1->sv_dirty = true;
01449 
01450         /* Let go of the reference to g1 */
01451         VOP_DECREF(&g1->sv_v);
01452 
01453         vfs_biglock_release();
01454         return 0;
01455 
01456  puke_harder:
01457         /*
01458          * Error recovery: try to undo what we already did
01459          */
01460         result2 = sfs_dir_unlink(sv, slot2);
01461         if (result2) {
01462                 kprintf("sfs: rename: %s\n", strerror(result));
01463                 kprintf("sfs: rename: while cleaning up: %s\n", 
01464                         strerror(result2));
01465                 panic("sfs: rename: Cannot recover\n");
01466         }
01467         g1->sv_i.sfi_linkcount--;
01468  puke:
01469         /* Let go of the reference to g1 */
01470         VOP_DECREF(&g1->sv_v);
01471         vfs_biglock_release();
01472         return result;
01473 }
01474 
01475 /*
01476  * lookparent returns the last path component as a string and the
01477  * directory it's in as a vnode.
01478  *
01479  * Since we don't support subdirectories, this is very easy - 
01480  * return the root dir and copy the path.
01481  */
01482 static
01483 int
01484 sfs_lookparent(struct vnode *v, char *path, struct vnode **ret,
01485                   char *buf, size_t buflen)
01486 {
01487         struct sfs_vnode *sv = v->vn_data;
01488 
01489         vfs_biglock_acquire();
01490 
01491         if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
01492                 vfs_biglock_release();
01493                 return ENOTDIR;
01494         }
01495 
01496         if (strlen(path)+1 > buflen) {
01497                 vfs_biglock_release();
01498                 return ENAMETOOLONG;
01499         }
01500         strcpy(buf, path);
01501 
01502         VOP_INCREF(&sv->sv_v);
01503         *ret = &sv->sv_v;
01504 
01505         vfs_biglock_release();
01506         return 0;
01507 }
01508 
01509 /*
01510  * Lookup gets a vnode for a pathname.
01511  *
01512  * Since we don't support subdirectories, it's easy - just look up the
01513  * name.
01514  */
01515 static
01516 int
01517 sfs_lookup(struct vnode *v, char *path, struct vnode **ret)
01518 {
01519         struct sfs_vnode *sv = v->vn_data;
01520         struct sfs_vnode *final;
01521         int result;
01522 
01523         vfs_biglock_acquire();
01524 
01525         if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
01526                 vfs_biglock_release();
01527                 return ENOTDIR;
01528         }
01529         
01530         result = sfs_lookonce(sv, path, &final, NULL);
01531         if (result) {
01532                 vfs_biglock_release();
01533                 return result;
01534         }
01535 
01536         *ret = &final->sv_v;
01537 
01538         vfs_biglock_release();
01539         return 0;
01540 }
01541 
01542 //////////////////////////////////////////////////
01543 
01544 static
01545 int
01546 sfs_notdir(void)
01547 {
01548         return ENOTDIR;
01549 }
01550 
01551 static
01552 int
01553 sfs_isdir(void)
01554 {
01555         return EISDIR;
01556 }
01557 
01558 static
01559 int
01560 sfs_unimp(void)
01561 {
01562         return EUNIMP;
01563 }
01564 
01565 /*
01566  * Casting through void * prevents warnings.
01567  * All of the vnode ops return int, and it's ok to cast functions that
01568  * take args to functions that take no args.
01569  */
01570 
01571 #define ISDIR ((void *)sfs_isdir)
01572 #define NOTDIR ((void *)sfs_notdir)
01573 #define UNIMP ((void *)sfs_unimp)
01574 
01575 /*
01576  * Function table for sfs files.
01577  */
01578 static const struct vnode_ops sfs_fileops = {
01579         VOP_MAGIC,      /* mark this a valid vnode ops table */
01580 
01581         sfs_open,
01582         sfs_close,
01583         sfs_reclaim,
01584 
01585         sfs_read,
01586         NOTDIR,  /* readlink */
01587         NOTDIR,  /* getdirentry */
01588         sfs_write,
01589         sfs_ioctl,
01590         sfs_stat,
01591         sfs_gettype,
01592         sfs_tryseek,
01593         sfs_fsync,
01594         sfs_mmap,
01595         sfs_truncate,
01596         NOTDIR,  /* namefile */
01597 
01598         NOTDIR,  /* creat */
01599         NOTDIR,  /* symlink */
01600         NOTDIR,  /* mkdir */
01601         NOTDIR,  /* link */
01602         NOTDIR,  /* remove */
01603         NOTDIR,  /* rmdir */
01604         NOTDIR,  /* rename */
01605 
01606         NOTDIR,  /* lookup */
01607         NOTDIR,  /* lookparent */
01608 };
01609 
01610 /*
01611  * Function table for the sfs directory.
01612  */
01613 static const struct vnode_ops sfs_dirops = {
01614         VOP_MAGIC,      /* mark this a valid vnode ops table */
01615 
01616         sfs_opendir,
01617         sfs_close,
01618         sfs_reclaim,
01619         
01620         ISDIR,   /* read */
01621         ISDIR,   /* readlink */
01622         UNIMP,   /* getdirentry */
01623         ISDIR,   /* write */
01624         sfs_ioctl,
01625         sfs_stat,
01626         sfs_gettype,
01627         UNIMP,   /* tryseek */
01628         sfs_fsync,
01629         ISDIR,   /* mmap */
01630         ISDIR,   /* truncate */
01631         sfs_namefile,
01632 
01633         sfs_creat,
01634         UNIMP,   /* symlink */
01635         UNIMP,   /* mkdir */
01636         sfs_link,
01637         sfs_remove,
01638         UNIMP,   /* rmdir */
01639         sfs_rename,
01640 
01641         sfs_lookup,
01642         sfs_lookparent,
01643 };
01644 
01645 /*
01646  * Function to load a inode into memory as a vnode, or dig up one
01647  * that's already resident.
01648  */
01649 static
01650 int
01651 sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int forcetype,
01652                  struct sfs_vnode **ret)
01653 {
01654         struct vnode *v;
01655         struct sfs_vnode *sv;
01656         const struct vnode_ops *ops = NULL;
01657         unsigned i, num;
01658         int result;
01659 
01660         /* Look in the vnodes table */
01661         num = vnodearray_num(sfs->sfs_vnodes);
01662 
01663         /* Linear search. Is this too slow? You decide. */
01664         for (i=0; i<num; i++) {
01665                 v = vnodearray_get(sfs->sfs_vnodes, i);
01666                 sv = v->vn_data;
01667 
01668                 /* Every inode in memory must be in an allocated block */
01669                 if (!sfs_bused(sfs, sv->sv_ino)) {
01670                         panic("sfs: Found inode %u in unallocated block\n",
01671                               sv->sv_ino);
01672                 }
01673 
01674                 if (sv->sv_ino==ino) {
01675                         /* Found */
01676 
01677                         /* May only be set when creating new objects */
01678                         KASSERT(forcetype==SFS_TYPE_INVAL);
01679 
01680                         VOP_INCREF(&sv->sv_v);
01681                         *ret = sv;
01682                         return 0;
01683                 }
01684         }
01685 
01686         /* Didn't have it loaded; load it */
01687 
01688         sv = kmalloc(sizeof(struct sfs_vnode));
01689         if (sv==NULL) {
01690                 return ENOMEM;
01691         }
01692 
01693         /* Must be in an allocated block */
01694         if (!sfs_bused(sfs, ino)) {
01695                 panic("sfs: Tried to load inode %u from unallocated block\n",
01696                       ino);
01697         }
01698 
01699         /* Read the block the inode is in */
01700         result = sfs_rblock(sfs, &sv->sv_i, ino);
01701         if (result) {
01702                 kfree(sv);
01703                 return result;
01704         }
01705 
01706         /* Not dirty yet */
01707         sv->sv_dirty = false;
01708 
01709         /*
01710          * FORCETYPE is set if we're creating a new file, because the
01711          * block on disk will have been zeroed out and thus the type
01712          * recorded there will be SFS_TYPE_INVAL.
01713          */
01714         if (forcetype != SFS_TYPE_INVAL) {
01715                 KASSERT(sv->sv_i.sfi_type == SFS_TYPE_INVAL);
01716                 sv->sv_i.sfi_type = forcetype;
01717                 sv->sv_dirty = true;
01718         }
01719 
01720         /*
01721          * Choose the function table based on the object type.
01722          */
01723         switch (sv->sv_i.sfi_type) {
01724             case SFS_TYPE_FILE:
01725                 ops = &sfs_fileops;
01726                 break;
01727             case SFS_TYPE_DIR:
01728                 ops = &sfs_dirops;
01729                 break;
01730             default: 
01731                 panic("sfs: loadvnode: Invalid inode type "
01732                       "(inode %u, type %u)\n",
01733                       ino, sv->sv_i.sfi_type);
01734         }
01735 
01736         /* Call the common vnode initializer */
01737         result = VOP_INIT(&sv->sv_v, ops, &sfs->sfs_absfs, sv);
01738         if (result) {
01739                 kfree(sv);
01740                 return result;
01741         }
01742 
01743         /* Set the other fields in our vnode structure */
01744         sv->sv_ino = ino;
01745 
01746         /* Add it to our table */
01747         result = vnodearray_add(sfs->sfs_vnodes, &sv->sv_v, NULL);
01748         if (result) {
01749                 VOP_CLEANUP(&sv->sv_v);
01750                 kfree(sv);
01751                 return result;
01752         }
01753 
01754         /* Hand it back */
01755         *ret = sv;
01756         return 0;
01757 }
01758 
01759 /*
01760  * Get vnode for the root of the filesystem.
01761  * The root vnode is always found in block 1 (SFS_ROOT_LOCATION).
01762  */
01763 struct vnode *
01764 sfs_getroot(struct fs *fs)
01765 {
01766         struct sfs_fs *sfs = fs->fs_data;
01767         struct sfs_vnode *sv;
01768         int result;
01769 
01770         vfs_biglock_acquire();
01771 
01772         result = sfs_loadvnode(sfs, SFS_ROOT_LOCATION, SFS_TYPE_INVAL, &sv);
01773         if (result) {
01774                 panic("sfs: getroot: Cannot load root vnode\n");
01775         }
01776 
01777         vfs_biglock_release();
01778 
01779         return &sv->sv_v;
01780 }
 All Data Structures