/*1* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 20092* The President and Fellows of Harvard College.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. Neither the name of the University nor the names of its contributors13* may be used to endorse or promote products derived from this software14* without specific prior written permission.15*16* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829/*30* SFS filesystem31*32* Filesystem-level interface routines.33*/3435#include <types.h>36#include <kern/errno.h>37#include <lib.h>38#include <array.h>39#include <bitmap.h>40#include <uio.h>41#include <vfs.h>42#include <device.h>43#include <sfs.h>4445/* Shortcuts for the size macros in kern/sfs.h */46#define SFS_FS_BITMAPSIZE(sfs) SFS_BITMAPSIZE((sfs)->sfs_super.sp_nblocks)47#define SFS_FS_BITBLOCKS(sfs) SFS_BITBLOCKS((sfs)->sfs_super.sp_nblocks)4849/*50* Routine for doing I/O (reads or writes) on the free block bitmap.51* We always do the whole bitmap at once; writing individual sectors52* might or might not be a worthwhile optimization.53*54* The free block bitmap consists of SFS_BITBLOCKS 512-byte sectors of55* bits, one bit for each sector on the filesystem. The number of56* blocks in the bitmap is thus rounded up to the nearest multiple of57* 512*8 = 4096. (This rounded number is SFS_BITMAPSIZE.) This means58* that the bitmap will (in general) contain space for some number of59* invalid sectors that are actually beyond the end of the disk60* device. This is ok. These sectors are supposed to be marked "in61* use" by mksfs and never get marked "free".62*63* The sectors used by the superblock and the bitmap itself are64* likewise marked in use by mksfs.65*/6667static68int69sfs_mapio(struct sfs_fs *sfs, enum uio_rw rw)70{71uint32_t j, mapsize;72char *bitdata;73int result;7475/* Number of blocks in the bitmap. */76mapsize = SFS_FS_BITBLOCKS(sfs);7778/* Pointer to our bitmap data in memory. */79bitdata = bitmap_getdata(sfs->sfs_freemap);8081/* For each sector in the bitmap... */82for (j=0; j<mapsize; j++) {8384/* Get a pointer to its data */85void *ptr = bitdata + j*SFS_BLOCKSIZE;8687/* and read or write it. The bitmap starts at sector 2. */88if (rw == UIO_READ) {89result = sfs_rblock(sfs, ptr, SFS_MAP_LOCATION+j);90}91else {92result = sfs_wblock(sfs, ptr, SFS_MAP_LOCATION+j);93}9495/* If we failed, stop. */96if (result) {97return result;98}99}100return 0;101}102103/*104* Sync routine. This is what gets invoked if you do FS_SYNC on the105* sfs filesystem structure.106*/107108static109int110sfs_sync(struct fs *fs)111{112struct sfs_fs *sfs;113unsigned i, num;114int result;115116vfs_biglock_acquire();117118/*119* Get the sfs_fs from the generic abstract fs.120*121* Note that the abstract struct fs, which is all the VFS122* layer knows about, is actually a member of struct sfs_fs.123* The pointer in the struct fs points back to the top of the124* struct sfs_fs - essentially the same object. This can be a125* little confusing at first.126*127* The following diagram may help:128*129* struct sfs_fs <-------------\130* : |131* : sfs_absfs (struct fs) | <------\132* : : | |133* : : various members | |134* : : | |135* : : fs_data ----------/ |136* : : ...|...137* : . VFS .138* : . layer .139* : other members .......140* :141* :142*143* This construct is repeated with vnodes and devices and other144* similar things all over the place in OS/161, so taking the145* time to straighten it out in your mind is worthwhile.146*/147148sfs = fs->fs_data;149150/* Go over the array of loaded vnodes, syncing as we go. */151num = vnodearray_num(sfs->sfs_vnodes);152for (i=0; i<num; i++) {153struct vnode *v = vnodearray_get(sfs->sfs_vnodes, i);154VOP_FSYNC(v);155}156157/* If the free block map needs to be written, write it. */158if (sfs->sfs_freemapdirty) {159result = sfs_mapio(sfs, UIO_WRITE);160if (result) {161vfs_biglock_release();162return result;163}164sfs->sfs_freemapdirty = false;165}166167/* If the superblock needs to be written, write it. */168if (sfs->sfs_superdirty) {169result = sfs_wblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);170if (result) {171vfs_biglock_release();172return result;173}174sfs->sfs_superdirty = false;175}176177vfs_biglock_release();178return 0;179}180181/*182* Routine to retrieve the volume name. Filesystems can be referred183* to by their volume name followed by a colon as well as the name184* of the device they're mounted on.185*/186static187const char *188sfs_getvolname(struct fs *fs)189{190struct sfs_fs *sfs = fs->fs_data;191const char *ret;192193vfs_biglock_acquire();194ret = sfs->sfs_super.sp_volname;195vfs_biglock_release();196197return ret;198}199200/*201* Unmount code.202*203* VFS calls FS_SYNC on the filesystem prior to unmounting it.204*/205static206int207sfs_unmount(struct fs *fs)208{209struct sfs_fs *sfs = fs->fs_data;210211vfs_biglock_acquire();212213/* Do we have any files open? If so, can't unmount. */214if (vnodearray_num(sfs->sfs_vnodes) > 0) {215vfs_biglock_release();216return EBUSY;217}218219/* We should have just had sfs_sync called. */220KASSERT(sfs->sfs_superdirty == false);221KASSERT(sfs->sfs_freemapdirty == false);222223/* Once we start nuking stuff we can't fail. */224vnodearray_destroy(sfs->sfs_vnodes);225bitmap_destroy(sfs->sfs_freemap);226227/* The vfs layer takes care of the device for us */228(void)sfs->sfs_device;229230/* Destroy the fs object */231kfree(sfs);232233/* nothing else to do */234vfs_biglock_release();235return 0;236}237238/*239* Mount routine.240*241* The way mount works is that you call vfs_mount and pass it a242* filesystem-specific mount routine. Said routine takes a device and243* hands back a pointer to an abstract filesystem. You can also pass244* a void pointer through.245*246* This organization makes cleanup on error easier. Hint: it may also247* be easier to synchronize correctly; it is important not to get two248* filesystem with the same name mounted at once, or two filesystems249* mounted on the same device at once.250*/251252static253int254sfs_domount(void *options, struct device *dev, struct fs **ret)255{256int result;257struct sfs_fs *sfs;258259vfs_biglock_acquire();260261/* We don't pass any options through mount */262(void)options;263264/*265* Make sure our on-disk structures aren't messed up266*/267KASSERT(sizeof(struct sfs_super)==SFS_BLOCKSIZE);268KASSERT(sizeof(struct sfs_inode)==SFS_BLOCKSIZE);269KASSERT(SFS_BLOCKSIZE % sizeof(struct sfs_dir) == 0);270271/*272* We can't mount on devices with the wrong sector size.273*274* (Note: for all intents and purposes here, "sector" and275* "block" are interchangeable terms. Technically a filesystem276* block may be composed of several hardware sectors, but we277* don't do that in sfs.)278*/279if (dev->d_blocksize != SFS_BLOCKSIZE) {280vfs_biglock_release();281return ENXIO;282}283284/* Allocate object */285sfs = kmalloc(sizeof(struct sfs_fs));286if (sfs==NULL) {287vfs_biglock_release();288return ENOMEM;289}290291/* Allocate array */292sfs->sfs_vnodes = vnodearray_create();293if (sfs->sfs_vnodes == NULL) {294kfree(sfs);295vfs_biglock_release();296return ENOMEM;297}298299/* Set the device so we can use sfs_rblock() */300sfs->sfs_device = dev;301302/* Load superblock */303result = sfs_rblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);304if (result) {305vnodearray_destroy(sfs->sfs_vnodes);306kfree(sfs);307vfs_biglock_release();308return result;309}310311/* Make some simple sanity checks */312313if (sfs->sfs_super.sp_magic != SFS_MAGIC) {314kprintf("sfs: Wrong magic number in superblock "315"(0x%x, should be 0x%x)\n",316sfs->sfs_super.sp_magic,317SFS_MAGIC);318vnodearray_destroy(sfs->sfs_vnodes);319kfree(sfs);320vfs_biglock_release();321return EINVAL;322}323324if (sfs->sfs_super.sp_nblocks > dev->d_blocks) {325kprintf("sfs: warning - fs has %u blocks, device has %u\n",326sfs->sfs_super.sp_nblocks, dev->d_blocks);327}328329/* Ensure null termination of the volume name */330sfs->sfs_super.sp_volname[sizeof(sfs->sfs_super.sp_volname)-1] = 0;331332/* Load free space bitmap */333sfs->sfs_freemap = bitmap_create(SFS_FS_BITMAPSIZE(sfs));334if (sfs->sfs_freemap == NULL) {335vnodearray_destroy(sfs->sfs_vnodes);336kfree(sfs);337vfs_biglock_release();338return ENOMEM;339}340result = sfs_mapio(sfs, UIO_READ);341if (result) {342bitmap_destroy(sfs->sfs_freemap);343vnodearray_destroy(sfs->sfs_vnodes);344kfree(sfs);345vfs_biglock_release();346return result;347}348349/* Set up abstract fs calls */350sfs->sfs_absfs.fs_sync = sfs_sync;351sfs->sfs_absfs.fs_getvolname = sfs_getvolname;352sfs->sfs_absfs.fs_getroot = sfs_getroot;353sfs->sfs_absfs.fs_unmount = sfs_unmount;354sfs->sfs_absfs.fs_data = sfs;355356/* the other fields */357sfs->sfs_superdirty = false;358sfs->sfs_freemapdirty = false;359360/* Hand back the abstract fs */361*ret = &sfs->sfs_absfs;362363vfs_biglock_release();364return 0;365}366367/*368* Actual function called from high-level code to mount an sfs.369*/370371int372sfs_mount(const char *device)373{374return vfs_mount(device, NULL, sfs_domount);375}376377378