os161-1.99
 All Data Structures
sfs_fs.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  * Filesystem-level interface routines.
00034  */
00035 
00036 #include <types.h>
00037 #include <kern/errno.h>
00038 #include <lib.h>
00039 #include <array.h>
00040 #include <bitmap.h>
00041 #include <uio.h>
00042 #include <vfs.h>
00043 #include <device.h>
00044 #include <sfs.h>
00045 
00046 /* Shortcuts for the size macros in kern/sfs.h */
00047 #define SFS_FS_BITMAPSIZE(sfs)  SFS_BITMAPSIZE((sfs)->sfs_super.sp_nblocks)
00048 #define SFS_FS_BITBLOCKS(sfs)   SFS_BITBLOCKS((sfs)->sfs_super.sp_nblocks)
00049 
00050 /*
00051  * Routine for doing I/O (reads or writes) on the free block bitmap.
00052  * We always do the whole bitmap at once; writing individual sectors
00053  * might or might not be a worthwhile optimization.
00054  *
00055  * The free block bitmap consists of SFS_BITBLOCKS 512-byte sectors of
00056  * bits, one bit for each sector on the filesystem. The number of
00057  * blocks in the bitmap is thus rounded up to the nearest multiple of
00058  * 512*8 = 4096. (This rounded number is SFS_BITMAPSIZE.) This means
00059  * that the bitmap will (in general) contain space for some number of
00060  * invalid sectors that are actually beyond the end of the disk
00061  * device. This is ok. These sectors are supposed to be marked "in
00062  * use" by mksfs and never get marked "free".
00063  *
00064  * The sectors used by the superblock and the bitmap itself are
00065  * likewise marked in use by mksfs.
00066  */
00067 
00068 static
00069 int
00070 sfs_mapio(struct sfs_fs *sfs, enum uio_rw rw)
00071 {
00072         uint32_t j, mapsize;
00073         char *bitdata;
00074         int result;
00075 
00076         /* Number of blocks in the bitmap. */
00077         mapsize = SFS_FS_BITBLOCKS(sfs);
00078 
00079         /* Pointer to our bitmap data in memory. */
00080         bitdata = bitmap_getdata(sfs->sfs_freemap);
00081         
00082         /* For each sector in the bitmap... */
00083         for (j=0; j<mapsize; j++) {
00084 
00085                 /* Get a pointer to its data */
00086                 void *ptr = bitdata + j*SFS_BLOCKSIZE;
00087 
00088                 /* and read or write it. The bitmap starts at sector 2. */ 
00089                 if (rw == UIO_READ) {
00090                         result = sfs_rblock(sfs, ptr, SFS_MAP_LOCATION+j);
00091                 }
00092                 else {
00093                         result = sfs_wblock(sfs, ptr, SFS_MAP_LOCATION+j);
00094                 }
00095 
00096                 /* If we failed, stop. */
00097                 if (result) {
00098                         return result;
00099                 }
00100         }
00101         return 0;
00102 }
00103 
00104 /*
00105  * Sync routine. This is what gets invoked if you do FS_SYNC on the
00106  * sfs filesystem structure.
00107  */
00108 
00109 static
00110 int
00111 sfs_sync(struct fs *fs)
00112 {
00113         struct sfs_fs *sfs; 
00114         unsigned i, num;
00115         int result;
00116 
00117         vfs_biglock_acquire();
00118 
00119         /*
00120          * Get the sfs_fs from the generic abstract fs.
00121          *
00122          * Note that the abstract struct fs, which is all the VFS
00123          * layer knows about, is actually a member of struct sfs_fs.
00124          * The pointer in the struct fs points back to the top of the
00125          * struct sfs_fs - essentially the same object. This can be a
00126          * little confusing at first.
00127          *
00128          * The following diagram may help:
00129          *
00130          *     struct sfs_fs        <-------------\
00131          *           :                            |
00132          *           :   sfs_absfs (struct fs)    |   <------\
00133          *           :      :                     |          |
00134          *           :      :  various members    |          |
00135          *           :      :                     |          |
00136          *           :      :  fs_data  ----------/          |
00137          *           :      :                             ...|...
00138          *           :                                   .  VFS  .
00139          *           :                                   . layer . 
00140          *           :   other members                    .......
00141          *           :                                    
00142          *           :
00143          *
00144          * This construct is repeated with vnodes and devices and other
00145          * similar things all over the place in OS/161, so taking the
00146          * time to straighten it out in your mind is worthwhile.
00147          */
00148 
00149         sfs = fs->fs_data;
00150 
00151         /* Go over the array of loaded vnodes, syncing as we go. */
00152         num = vnodearray_num(sfs->sfs_vnodes);
00153         for (i=0; i<num; i++) {
00154                 struct vnode *v = vnodearray_get(sfs->sfs_vnodes, i);
00155                 VOP_FSYNC(v);
00156         }
00157 
00158         /* If the free block map needs to be written, write it. */
00159         if (sfs->sfs_freemapdirty) {
00160                 result = sfs_mapio(sfs, UIO_WRITE);
00161                 if (result) {
00162                         vfs_biglock_release();
00163                         return result;
00164                 }
00165                 sfs->sfs_freemapdirty = false;
00166         }
00167 
00168         /* If the superblock needs to be written, write it. */
00169         if (sfs->sfs_superdirty) {
00170                 result = sfs_wblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);
00171                 if (result) {
00172                         vfs_biglock_release();
00173                         return result;
00174                 }
00175                 sfs->sfs_superdirty = false;
00176         }
00177 
00178         vfs_biglock_release();
00179         return 0;
00180 }
00181 
00182 /*
00183  * Routine to retrieve the volume name. Filesystems can be referred
00184  * to by their volume name followed by a colon as well as the name
00185  * of the device they're mounted on.
00186  */
00187 static
00188 const char *
00189 sfs_getvolname(struct fs *fs)
00190 {
00191         struct sfs_fs *sfs = fs->fs_data;
00192         const char *ret;
00193 
00194         vfs_biglock_acquire();
00195         ret = sfs->sfs_super.sp_volname;
00196         vfs_biglock_release();
00197 
00198         return ret;
00199 }
00200 
00201 /*
00202  * Unmount code.
00203  *
00204  * VFS calls FS_SYNC on the filesystem prior to unmounting it.
00205  */
00206 static
00207 int
00208 sfs_unmount(struct fs *fs)
00209 {
00210         struct sfs_fs *sfs = fs->fs_data;
00211 
00212         vfs_biglock_acquire();
00213         
00214         /* Do we have any files open? If so, can't unmount. */
00215         if (vnodearray_num(sfs->sfs_vnodes) > 0) {
00216                 vfs_biglock_release();
00217                 return EBUSY;
00218         }
00219 
00220         /* We should have just had sfs_sync called. */
00221         KASSERT(sfs->sfs_superdirty == false);
00222         KASSERT(sfs->sfs_freemapdirty == false);
00223 
00224         /* Once we start nuking stuff we can't fail. */
00225         vnodearray_destroy(sfs->sfs_vnodes);
00226         bitmap_destroy(sfs->sfs_freemap);
00227         
00228         /* The vfs layer takes care of the device for us */
00229         (void)sfs->sfs_device;
00230 
00231         /* Destroy the fs object */
00232         kfree(sfs);
00233 
00234         /* nothing else to do */
00235         vfs_biglock_release();
00236         return 0;
00237 }
00238 
00239 /*
00240  * Mount routine.
00241  *
00242  * The way mount works is that you call vfs_mount and pass it a
00243  * filesystem-specific mount routine. Said routine takes a device and
00244  * hands back a pointer to an abstract filesystem. You can also pass
00245  * a void pointer through.
00246  *
00247  * This organization makes cleanup on error easier. Hint: it may also
00248  * be easier to synchronize correctly; it is important not to get two
00249  * filesystem with the same name mounted at once, or two filesystems
00250  * mounted on the same device at once.
00251  */
00252 
00253 static
00254 int
00255 sfs_domount(void *options, struct device *dev, struct fs **ret)
00256 {
00257         int result;
00258         struct sfs_fs *sfs;
00259 
00260         vfs_biglock_acquire();
00261 
00262         /* We don't pass any options through mount */
00263         (void)options;
00264 
00265         /*
00266          * Make sure our on-disk structures aren't messed up
00267          */
00268         KASSERT(sizeof(struct sfs_super)==SFS_BLOCKSIZE);
00269         KASSERT(sizeof(struct sfs_inode)==SFS_BLOCKSIZE);
00270         KASSERT(SFS_BLOCKSIZE % sizeof(struct sfs_dir) == 0);
00271 
00272         /*
00273          * We can't mount on devices with the wrong sector size.
00274          *
00275          * (Note: for all intents and purposes here, "sector" and
00276          * "block" are interchangeable terms. Technically a filesystem
00277          * block may be composed of several hardware sectors, but we
00278          * don't do that in sfs.)
00279          */
00280         if (dev->d_blocksize != SFS_BLOCKSIZE) {
00281                 vfs_biglock_release();
00282                 return ENXIO;
00283         }
00284 
00285         /* Allocate object */
00286         sfs = kmalloc(sizeof(struct sfs_fs));
00287         if (sfs==NULL) {
00288                 vfs_biglock_release();
00289                 return ENOMEM;
00290         }
00291 
00292         /* Allocate array */
00293         sfs->sfs_vnodes = vnodearray_create();
00294         if (sfs->sfs_vnodes == NULL) {
00295                 kfree(sfs);
00296                 vfs_biglock_release();
00297                 return ENOMEM;
00298         }
00299 
00300         /* Set the device so we can use sfs_rblock() */
00301         sfs->sfs_device = dev;
00302 
00303         /* Load superblock */
00304         result = sfs_rblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);
00305         if (result) {
00306                 vnodearray_destroy(sfs->sfs_vnodes);
00307                 kfree(sfs);
00308                 vfs_biglock_release();
00309                 return result;
00310         }
00311 
00312         /* Make some simple sanity checks */
00313 
00314         if (sfs->sfs_super.sp_magic != SFS_MAGIC) {
00315                 kprintf("sfs: Wrong magic number in superblock "
00316                         "(0x%x, should be 0x%x)\n", 
00317                         sfs->sfs_super.sp_magic,
00318                         SFS_MAGIC);
00319                 vnodearray_destroy(sfs->sfs_vnodes);
00320                 kfree(sfs);
00321                 vfs_biglock_release();
00322                 return EINVAL;
00323         }
00324         
00325         if (sfs->sfs_super.sp_nblocks > dev->d_blocks) {
00326                 kprintf("sfs: warning - fs has %u blocks, device has %u\n",
00327                         sfs->sfs_super.sp_nblocks, dev->d_blocks);
00328         }
00329 
00330         /* Ensure null termination of the volume name */
00331         sfs->sfs_super.sp_volname[sizeof(sfs->sfs_super.sp_volname)-1] = 0;
00332 
00333         /* Load free space bitmap */
00334         sfs->sfs_freemap = bitmap_create(SFS_FS_BITMAPSIZE(sfs));
00335         if (sfs->sfs_freemap == NULL) {
00336                 vnodearray_destroy(sfs->sfs_vnodes);
00337                 kfree(sfs);
00338                 vfs_biglock_release();
00339                 return ENOMEM;
00340         }
00341         result = sfs_mapio(sfs, UIO_READ);
00342         if (result) {
00343                 bitmap_destroy(sfs->sfs_freemap);
00344                 vnodearray_destroy(sfs->sfs_vnodes);
00345                 kfree(sfs);
00346                 vfs_biglock_release();
00347                 return result;
00348         }
00349 
00350         /* Set up abstract fs calls */
00351         sfs->sfs_absfs.fs_sync = sfs_sync;
00352         sfs->sfs_absfs.fs_getvolname = sfs_getvolname;
00353         sfs->sfs_absfs.fs_getroot = sfs_getroot;
00354         sfs->sfs_absfs.fs_unmount = sfs_unmount;
00355         sfs->sfs_absfs.fs_data = sfs;
00356 
00357         /* the other fields */
00358         sfs->sfs_superdirty = false;
00359         sfs->sfs_freemapdirty = false;
00360 
00361         /* Hand back the abstract fs */
00362         *ret = &sfs->sfs_absfs;
00363 
00364         vfs_biglock_release();
00365         return 0;
00366 }
00367 
00368 /*
00369  * Actual function called from high-level code to mount an sfs.
00370  */
00371 
00372 int
00373 sfs_mount(const char *device)
00374 {
00375         return vfs_mount(device, NULL, sfs_domount);
00376 }
 All Data Structures