root/kern/fs/sfs/sfs_fs.c

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

DEFINITIONS

This source file includes following definitions.
  1. sfs_mapio
  2. sfs_sync
  3. sfs_getvolname
  4. sfs_unmount
  5. sfs_domount
  6. sfs_mount

   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  * Filesystem-level interface routines.
  34  */
  35 
  36 #include <types.h>
  37 #include <kern/errno.h>
  38 #include <lib.h>
  39 #include <array.h>
  40 #include <bitmap.h>
  41 #include <uio.h>
  42 #include <vfs.h>
  43 #include <device.h>
  44 #include <sfs.h>
  45 
  46 /* Shortcuts for the size macros in kern/sfs.h */
  47 #define SFS_FS_BITMAPSIZE(sfs)  SFS_BITMAPSIZE((sfs)->sfs_super.sp_nblocks)
  48 #define SFS_FS_BITBLOCKS(sfs)   SFS_BITBLOCKS((sfs)->sfs_super.sp_nblocks)
  49 
  50 /*
  51  * Routine for doing I/O (reads or writes) on the free block bitmap.
  52  * We always do the whole bitmap at once; writing individual sectors
  53  * might or might not be a worthwhile optimization.
  54  *
  55  * The free block bitmap consists of SFS_BITBLOCKS 512-byte sectors of
  56  * bits, one bit for each sector on the filesystem. The number of
  57  * blocks in the bitmap is thus rounded up to the nearest multiple of
  58  * 512*8 = 4096. (This rounded number is SFS_BITMAPSIZE.) This means
  59  * that the bitmap will (in general) contain space for some number of
  60  * invalid sectors that are actually beyond the end of the disk
  61  * device. This is ok. These sectors are supposed to be marked "in
  62  * use" by mksfs and never get marked "free".
  63  *
  64  * The sectors used by the superblock and the bitmap itself are
  65  * likewise marked in use by mksfs.
  66  */
  67 
  68 static
  69 int
  70 sfs_mapio(struct sfs_fs *sfs, enum uio_rw rw)
  71 {
  72         uint32_t j, mapsize;
  73         char *bitdata;
  74         int result;
  75 
  76         /* Number of blocks in the bitmap. */
  77         mapsize = SFS_FS_BITBLOCKS(sfs);
  78 
  79         /* Pointer to our bitmap data in memory. */
  80         bitdata = bitmap_getdata(sfs->sfs_freemap);
  81         
  82         /* For each sector in the bitmap... */
  83         for (j=0; j<mapsize; j++) {
  84 
  85                 /* Get a pointer to its data */
  86                 void *ptr = bitdata + j*SFS_BLOCKSIZE;
  87 
  88                 /* and read or write it. The bitmap starts at sector 2. */ 
  89                 if (rw == UIO_READ) {
  90                         result = sfs_rblock(sfs, ptr, SFS_MAP_LOCATION+j);
  91                 }
  92                 else {
  93                         result = sfs_wblock(sfs, ptr, SFS_MAP_LOCATION+j);
  94                 }
  95 
  96                 /* If we failed, stop. */
  97                 if (result) {
  98                         return result;
  99                 }
 100         }
 101         return 0;
 102 }
 103 
 104 /*
 105  * Sync routine. This is what gets invoked if you do FS_SYNC on the
 106  * sfs filesystem structure.
 107  */
 108 
 109 static
 110 int
 111 sfs_sync(struct fs *fs)
 112 {
 113         struct sfs_fs *sfs; 
 114         unsigned i, num;
 115         int result;
 116 
 117         vfs_biglock_acquire();
 118 
 119         /*
 120          * Get the sfs_fs from the generic abstract fs.
 121          *
 122          * Note that the abstract struct fs, which is all the VFS
 123          * layer knows about, is actually a member of struct sfs_fs.
 124          * The pointer in the struct fs points back to the top of the
 125          * struct sfs_fs - essentially the same object. This can be a
 126          * little confusing at first.
 127          *
 128          * The following diagram may help:
 129          *
 130          *     struct sfs_fs        <-------------\
 131          *           :                            |
 132          *           :   sfs_absfs (struct fs)    |   <------\
 133          *           :      :                     |          |
 134          *           :      :  various members    |          |
 135          *           :      :                     |          |
 136          *           :      :  fs_data  ----------/          |
 137          *           :      :                             ...|...
 138          *           :                                   .  VFS  .
 139          *           :                                   . layer . 
 140          *           :   other members                    .......
 141          *           :                                    
 142          *           :
 143          *
 144          * This construct is repeated with vnodes and devices and other
 145          * similar things all over the place in OS/161, so taking the
 146          * time to straighten it out in your mind is worthwhile.
 147          */
 148 
 149         sfs = fs->fs_data;
 150 
 151         /* Go over the array of loaded vnodes, syncing as we go. */
 152         num = vnodearray_num(sfs->sfs_vnodes);
 153         for (i=0; i<num; i++) {
 154                 struct vnode *v = vnodearray_get(sfs->sfs_vnodes, i);
 155                 VOP_FSYNC(v);
 156         }
 157 
 158         /* If the free block map needs to be written, write it. */
 159         if (sfs->sfs_freemapdirty) {
 160                 result = sfs_mapio(sfs, UIO_WRITE);
 161                 if (result) {
 162                         vfs_biglock_release();
 163                         return result;
 164                 }
 165                 sfs->sfs_freemapdirty = false;
 166         }
 167 
 168         /* If the superblock needs to be written, write it. */
 169         if (sfs->sfs_superdirty) {
 170                 result = sfs_wblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);
 171                 if (result) {
 172                         vfs_biglock_release();
 173                         return result;
 174                 }
 175                 sfs->sfs_superdirty = false;
 176         }
 177 
 178         vfs_biglock_release();
 179         return 0;
 180 }
 181 
 182 /*
 183  * Routine to retrieve the volume name. Filesystems can be referred
 184  * to by their volume name followed by a colon as well as the name
 185  * of the device they're mounted on.
 186  */
 187 static
 188 const char *
 189 sfs_getvolname(struct fs *fs)
 190 {
 191         struct sfs_fs *sfs = fs->fs_data;
 192         const char *ret;
 193 
 194         vfs_biglock_acquire();
 195         ret = sfs->sfs_super.sp_volname;
 196         vfs_biglock_release();
 197 
 198         return ret;
 199 }
 200 
 201 /*
 202  * Unmount code.
 203  *
 204  * VFS calls FS_SYNC on the filesystem prior to unmounting it.
 205  */
 206 static
 207 int
 208 sfs_unmount(struct fs *fs)
 209 {
 210         struct sfs_fs *sfs = fs->fs_data;
 211 
 212         vfs_biglock_acquire();
 213         
 214         /* Do we have any files open? If so, can't unmount. */
 215         if (vnodearray_num(sfs->sfs_vnodes) > 0) {
 216                 vfs_biglock_release();
 217                 return EBUSY;
 218         }
 219 
 220         /* We should have just had sfs_sync called. */
 221         KASSERT(sfs->sfs_superdirty == false);
 222         KASSERT(sfs->sfs_freemapdirty == false);
 223 
 224         /* Once we start nuking stuff we can't fail. */
 225         vnodearray_destroy(sfs->sfs_vnodes);
 226         bitmap_destroy(sfs->sfs_freemap);
 227         
 228         /* The vfs layer takes care of the device for us */
 229         (void)sfs->sfs_device;
 230 
 231         /* Destroy the fs object */
 232         kfree(sfs);
 233 
 234         /* nothing else to do */
 235         vfs_biglock_release();
 236         return 0;
 237 }
 238 
 239 /*
 240  * Mount routine.
 241  *
 242  * The way mount works is that you call vfs_mount and pass it a
 243  * filesystem-specific mount routine. Said routine takes a device and
 244  * hands back a pointer to an abstract filesystem. You can also pass
 245  * a void pointer through.
 246  *
 247  * This organization makes cleanup on error easier. Hint: it may also
 248  * be easier to synchronize correctly; it is important not to get two
 249  * filesystem with the same name mounted at once, or two filesystems
 250  * mounted on the same device at once.
 251  */
 252 
 253 static
 254 int
 255 sfs_domount(void *options, struct device *dev, struct fs **ret)
 256 {
 257         int result;
 258         struct sfs_fs *sfs;
 259 
 260         vfs_biglock_acquire();
 261 
 262         /* We don't pass any options through mount */
 263         (void)options;
 264 
 265         /*
 266          * Make sure our on-disk structures aren't messed up
 267          */
 268         KASSERT(sizeof(struct sfs_super)==SFS_BLOCKSIZE);
 269         KASSERT(sizeof(struct sfs_inode)==SFS_BLOCKSIZE);
 270         KASSERT(SFS_BLOCKSIZE % sizeof(struct sfs_dir) == 0);
 271 
 272         /*
 273          * We can't mount on devices with the wrong sector size.
 274          *
 275          * (Note: for all intents and purposes here, "sector" and
 276          * "block" are interchangeable terms. Technically a filesystem
 277          * block may be composed of several hardware sectors, but we
 278          * don't do that in sfs.)
 279          */
 280         if (dev->d_blocksize != SFS_BLOCKSIZE) {
 281                 vfs_biglock_release();
 282                 return ENXIO;
 283         }
 284 
 285         /* Allocate object */
 286         sfs = kmalloc(sizeof(struct sfs_fs));
 287         if (sfs==NULL) {
 288                 vfs_biglock_release();
 289                 return ENOMEM;
 290         }
 291 
 292         /* Allocate array */
 293         sfs->sfs_vnodes = vnodearray_create();
 294         if (sfs->sfs_vnodes == NULL) {
 295                 kfree(sfs);
 296                 vfs_biglock_release();
 297                 return ENOMEM;
 298         }
 299 
 300         /* Set the device so we can use sfs_rblock() */
 301         sfs->sfs_device = dev;
 302 
 303         /* Load superblock */
 304         result = sfs_rblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);
 305         if (result) {
 306                 vnodearray_destroy(sfs->sfs_vnodes);
 307                 kfree(sfs);
 308                 vfs_biglock_release();
 309                 return result;
 310         }
 311 
 312         /* Make some simple sanity checks */
 313 
 314         if (sfs->sfs_super.sp_magic != SFS_MAGIC) {
 315                 kprintf("sfs: Wrong magic number in superblock "
 316                         "(0x%x, should be 0x%x)\n", 
 317                         sfs->sfs_super.sp_magic,
 318                         SFS_MAGIC);
 319                 vnodearray_destroy(sfs->sfs_vnodes);
 320                 kfree(sfs);
 321                 vfs_biglock_release();
 322                 return EINVAL;
 323         }
 324         
 325         if (sfs->sfs_super.sp_nblocks > dev->d_blocks) {
 326                 kprintf("sfs: warning - fs has %u blocks, device has %u\n",
 327                         sfs->sfs_super.sp_nblocks, dev->d_blocks);
 328         }
 329 
 330         /* Ensure null termination of the volume name */
 331         sfs->sfs_super.sp_volname[sizeof(sfs->sfs_super.sp_volname)-1] = 0;
 332 
 333         /* Load free space bitmap */
 334         sfs->sfs_freemap = bitmap_create(SFS_FS_BITMAPSIZE(sfs));
 335         if (sfs->sfs_freemap == NULL) {
 336                 vnodearray_destroy(sfs->sfs_vnodes);
 337                 kfree(sfs);
 338                 vfs_biglock_release();
 339                 return ENOMEM;
 340         }
 341         result = sfs_mapio(sfs, UIO_READ);
 342         if (result) {
 343                 bitmap_destroy(sfs->sfs_freemap);
 344                 vnodearray_destroy(sfs->sfs_vnodes);
 345                 kfree(sfs);
 346                 vfs_biglock_release();
 347                 return result;
 348         }
 349 
 350         /* Set up abstract fs calls */
 351         sfs->sfs_absfs.fs_sync = sfs_sync;
 352         sfs->sfs_absfs.fs_getvolname = sfs_getvolname;
 353         sfs->sfs_absfs.fs_getroot = sfs_getroot;
 354         sfs->sfs_absfs.fs_unmount = sfs_unmount;
 355         sfs->sfs_absfs.fs_data = sfs;
 356 
 357         /* the other fields */
 358         sfs->sfs_superdirty = false;
 359         sfs->sfs_freemapdirty = false;
 360 
 361         /* Hand back the abstract fs */
 362         *ret = &sfs->sfs_absfs;
 363 
 364         vfs_biglock_release();
 365         return 0;
 366 }
 367 
 368 /*
 369  * Actual function called from high-level code to mount an sfs.
 370  */
 371 
 372 int
 373 sfs_mount(const char *device)
 374 {
 375         return vfs_mount(device, NULL, sfs_domount);
 376 }

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