Beispiel #1
0
static
int
sfs_mapio(struct sfs_fs *sfs, enum uio_rw rw)
{
	uint32_t j, mapsize;
	char *bitdata;
	int result;

	/* Number of blocks in the bitmap. */
	mapsize = SFS_FS_BITBLOCKS(sfs);

	/* Pointer to our bitmap data in memory. */
	bitdata = bitmap_getdata(sfs->sfs_freemap);

	/* For each sector in the bitmap... */
	for (j=0; j<mapsize; j++) {

		/* Get a pointer to its data */
		void *ptr = bitdata + j*SFS_BLOCKSIZE;

		/* and read or write it. The bitmap starts at sector 2. */
		if (rw == UIO_READ) {
			result = sfs_rblock(sfs, ptr, SFS_MAP_LOCATION+j);
		}
		else {
			result = sfs_wblock(sfs, ptr, SFS_MAP_LOCATION+j);
		}

		/* If we failed, stop. */
		if (result) {
			return result;
		}
	}
	return 0;
}
Beispiel #2
0
/* Zero out a disk block. */
static
int
sfs_clearblock(struct sfs_fs *sfs, u_int32_t block)
{
	/* static -> automatically initialized to zero */
	static char zeros[SFS_BLOCKSIZE];
	return sfs_wblock(sfs, zeros, block);
}
Beispiel #3
0
/* Write an on-disk inode structure back out to disk. */
static
int
sfs_sync_inode(struct sfs_vnode *sv)
{
	if (sv->sv_dirty) {
		struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
		int result = sfs_wblock(sfs, &sv->sv_i, sv->sv_ino);
		if (result) {
			return result;
		}
		sv->sv_dirty = 0;
	}
	return 0;
}
Beispiel #4
0
/*
 * Do I/O to a block of a file that doesn't cover the whole block.  We
 * need to read in the original block first, even if we're writing, so
 * we don't clobber the portion of the block we're not intending to
 * write over.
 *
 * skipstart is the number of bytes to skip past at the beginning of
 * the sector; len is the number of bytes to actually read or write.
 * uio is the area to do the I/O into.
 */
static
int
sfs_partialio(struct sfs_vnode *sv, struct uio *uio,
	      u_int32_t skipstart, u_int32_t len)
{
	/*
	 * I/O buffer for handling partial sectors.
	 *
	 * Note: in real life (and when you've done the fs assignment)
	 * you would get space from the disk buffer cache for this,
	 * not use a static area.
	 */
	static char iobuf[SFS_BLOCKSIZE];

	struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
	u_int32_t diskblock;
	u_int32_t fileblock;
	int result;
	
	/* Allocate missing blocks if and only if we're writing */
	int doalloc = (uio->uio_rw==UIO_WRITE);

	assert(skipstart + len <= SFS_BLOCKSIZE);

	/* Compute the block offset of this block in the file */
	fileblock = uio->uio_offset / SFS_BLOCKSIZE;

	/* Get the disk block number */
	result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
	if (result) {
		return result;
	}

	/* f_test 3 debug */
	u_int32_t i;
	char ch;

	if (diskblock == 0) {
		/*
		 * There was no block mapped at this point in the file.
		 * Zero the buffer.
		 */
		assert(uio->uio_rw == UIO_READ);
		bzero(iobuf, sizeof(iobuf));
	}
	else {
		/*
		 * Read the block.
		 */
		result = sfs_rblock(sfs, iobuf, diskblock);
		if (result) {
			return result;
		}

		/* f_test 3 debug
		if(uio->uio_rw == UIO_READ && diskblock > 6){
                	for(i=0; i<len; i++){
                        	ch = (iobuf+skipstart)[i];
                        	if(ch != 'w' && ch != 'r') kprintf("Read Error on diskblock %d - iobuf[%d]: %c\n", diskblock, i, ch);
                	}       
        	}
		*/
	}

	/*
	 * Now perform the requested operation into/out of the buffer.
	 */
	result = uiomove(iobuf+skipstart, len, uio);
	if (result) {
		return result;
	}
	
	/*
	 * If it was a write, write back the modified block.
	 */
	if (uio->uio_rw == UIO_WRITE) {
		result = sfs_wblock(sfs, iobuf, diskblock);
		if (result) {
			return result;
		}
	}

	return 0;
}
Beispiel #5
0
/*
 * Look up the disk block number (from 0 up to the number of blocks on
 * the disk) given a file and the logical block number within that
 * file. If DOALLOC is set, and no such block exists, one will be
 * allocated.
 */
static
int
sfs_bmap(struct sfs_vnode *sv, u_int32_t fileblock, int doalloc,
	    u_int32_t *diskblock)
{
	/*
	 * I/O buffer for handling indirect blocks.
	 *
	 * Note: in real life (and when you've done the fs assignment)
	 * you would get space from the disk buffer cache for this,
	 * not use a static area.
	 */
	static u_int32_t idbuf[SFS_DBPERIDB];

	struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
	u_int32_t block;
	u_int32_t idblock;
	u_int32_t idnum, idoff;
	int result;

	assert(sizeof(idbuf)==SFS_BLOCKSIZE);

	/*
	 * If the block we want is one of the direct blocks...
	 */
	if (fileblock < SFS_NDIRECT) {
		/*
		 * Get the block number
		 */
		block = sv->sv_i.sfi_direct[fileblock];

		/*
		 * Do we need to allocate?
		 */
		if (block==0 && doalloc) {
			result = sfs_balloc(sfs, &block);
			if (result) {
				return result;
			}

			/* Remember what we allocated; mark inode dirty */
			sv->sv_i.sfi_direct[fileblock] = block;
			sv->sv_dirty = 1;
		}

		/*
		 * Hand back the block
		 */
		if (block != 0 && !sfs_bused(sfs, block)) {
			panic("sfs: Data block %u (block %u of file %u) "
			      "marked free\n", block, fileblock, sv->sv_ino);
		}
		*diskblock = block;
		return 0;
	}

	/*
	 * It's not a direct block; it must be in the indirect block.
	 * Subtract off the number of direct blocks, so FILEBLOCK is
	 * now the offset into the indirect block space.
	 */

	fileblock -= SFS_NDIRECT;

	/* Get the indirect block number and offset w/i that indirect block */
	idnum = fileblock / SFS_DBPERIDB;
	idoff = fileblock % SFS_DBPERIDB;

	/*
	 * We only have one indirect block. If the offset we were asked for
	 * is too large, we can't handle it, so fail.
	 */
	if (idnum > 0) {
		return EINVAL;
	}

	/* 
	 * Probably need to synchronize the stuff below. Maybe not though
	 * since no two threads can be writing to the same file at the same
	 * time (this is protected with file locks in the VFS layer).
	 */

	/* Get the disk block number of the indirect block. */
	idblock = sv->sv_i.sfi_indirect;

	if (idblock==0 && !doalloc) {
		/*
		 * There's no indirect block allocated. We weren't
		 * asked to allocate anything, so pretend the indirect
		 * block was filled with all zeros.
		 */
		*diskblock = 0;
		return 0;
	}
	else if (idblock==0) {
		/*
		 * There's no indirect block allocated, but we need to
		 * allocate a block whose number needs to be stored in
		 * the indirect block. Thus, we need to allocate an
		 * indirect block.
		 */
		result = sfs_balloc(sfs, &idblock);
		if (result) {
			return result;
		}

		/* Remember the block we just allocated */
		sv->sv_i.sfi_indirect = idblock;

		/* Mark the inode dirty */
		sv->sv_dirty = 1;

		/* Clear the indirect block buffer */
		bzero(idbuf, sizeof(idbuf));
	}
	else {
		/*
		 * We already have an indirect block allocated; load it.
		 */
		result = sfs_rblock(sfs, idbuf, idblock);
		if (result) {
			return result;
		}
	}

	/* Get the block out of the indirect block buffer */
	block = idbuf[idoff];

	/* If there's no block there, allocate one */
	if (block==0 && doalloc) {
		result = sfs_balloc(sfs, &block);
		if (result) {
			return result;
		}

		/* Remember the block we allocated */
		idbuf[idoff] = block;

		/* The indirect block is now dirty; write it back */
		result = sfs_wblock(sfs, idbuf, idblock);
		if (result) {
			return result;
		}
	}

	/* Hand back the result and return. */
	if (block != 0 && !sfs_bused(sfs, block)) {
		panic("sfs: Data block %u (block %u of file %u) marked free\n",
		      block, fileblock, sv->sv_ino);
	}
	*diskblock = block;
	return 0;
}
Beispiel #6
0
/*
 * Called for ftruncate() and from sfs_reclaim.
 */
static
int
sfs_truncate(struct vnode *v, off_t len)
{
	/*
	 * I/O buffer for handling the indirect block.
	 *
	 * Note: in real life (and when you've done the fs assignment)
	 * you would get space from the disk buffer cache for this,
	 * not use a static area.
	 */
	static u_int32_t idbuf[SFS_DBPERIDB];

	struct sfs_vnode *sv = v->vn_data;
	struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;

	/* Length in blocks (divide rounding up) */
	u_int32_t blocklen = DIVROUNDUP(len, SFS_BLOCKSIZE);

	u_int32_t i, j, block;
	u_int32_t idblock, baseblock, highblock;
	int result;
	int hasnonzero, iddirty;

	assert(sizeof(idbuf)==SFS_BLOCKSIZE);

	/*
	 * Go through the direct blocks. Discard any that are
	 * past the limit we're truncating to.
	 */
	for (i=0; i<SFS_NDIRECT; i++) {
		block = sv->sv_i.sfi_direct[i];
		if (i >= blocklen && block != 0) {
			sfs_bfree(sfs, block);
			sv->sv_i.sfi_direct[i] = 0;
			sv->sv_dirty = 1;
		}
	}

	/* Indirect block number */
	idblock = sv->sv_i.sfi_indirect;

	/* The lowest block in the indirect block */
	baseblock = SFS_NDIRECT;

	/* The highest block in the indirect block */
	highblock = baseblock + SFS_DBPERIDB - 1;

	if (blocklen < highblock && idblock != 0) {
		/* We're past the proposed EOF; may need to free stuff */

		/* Read the indirect block */
		result = sfs_rblock(sfs, idbuf, idblock);
		if (result) {
			return result;
		}
		
		hasnonzero = 0;
		iddirty = 0;
		for (j=0; j<SFS_DBPERIDB; j++) {
			/* Discard any blocks that are past the new EOF */
			if (blocklen < baseblock+j && idbuf[j] != 0) {
				sfs_bfree(sfs, idbuf[j]);
				idbuf[j] = 0;
				iddirty = 1;
			}
			/* Remember if we see any nonzero blocks in here */
			if (idbuf[j]!=0) {
				hasnonzero=1;
			}
		}

		if (!hasnonzero) {
			/* The whole indirect block is empty now; free it */
			sfs_bfree(sfs, idblock);
			sv->sv_i.sfi_indirect = 0;
			sv->sv_dirty = 1;
		}
		else if (iddirty) {
			/* The indirect block is dirty; write it back */
			result = sfs_wblock(sfs, idbuf, idblock);
			if (result) {
				return result;
			}
		}
	}

	/* Set the file size */
	sv->sv_i.sfi_size = len;

	/* Mark the inode dirty */
	sv->sv_dirty = 1;
	
	return 0;
}
Beispiel #7
0
static
int
sfs_sync(struct fs *fs)
{
	struct sfs_fs *sfs;
	unsigned i, num;
	int result;

	vfs_biglock_acquire();

	/*
	 * Get the sfs_fs from the generic abstract fs.
	 *
	 * Note that the abstract struct fs, which is all the VFS
	 * layer knows about, is actually a member of struct sfs_fs.
	 * The pointer in the struct fs points back to the top of the
	 * struct sfs_fs - essentially the same object. This can be a
	 * little confusing at first.
	 *
	 * The following diagram may help:
	 *
	 *     struct sfs_fs        <-------------\
     *           :                            |
     *           :   sfs_absfs (struct fs)    |   <------\
     *           :      :                     |          |
     *           :      :  various members    |          |
     *           :      :                     |          |
     *           :      :  fs_data  ----------/          |
     *           :      :                             ...|...
     *           :                                   .  VFS  .
     *           :                                   . layer .
     *           :   other members                    .......
     *           :
     *           :
	 *
	 * This construct is repeated with vnodes and devices and other
	 * similar things all over the place in OS/161, so taking the
	 * time to straighten it out in your mind is worthwhile.
	 */

	sfs = fs->fs_data;

	/* Go over the array of loaded vnodes, syncing as we go. */
	num = vnodearray_num(sfs->sfs_vnodes);
	for (i=0; i<num; i++) {
		struct vnode *v = vnodearray_get(sfs->sfs_vnodes, i);
		VOP_FSYNC(v);
	}

	/* If the free block map needs to be written, write it. */
	if (sfs->sfs_freemapdirty) {
		result = sfs_mapio(sfs, UIO_WRITE);
		if (result) {
			vfs_biglock_release();
			return result;
		}
		sfs->sfs_freemapdirty = false;
	}

	/* If the superblock needs to be written, write it. */
	if (sfs->sfs_superdirty) {
		result = sfs_wblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);
		if (result) {
			vfs_biglock_release();
			return result;
		}
		sfs->sfs_superdirty = false;
	}

	vfs_biglock_release();
	return 0;
}
Beispiel #8
0
static
int
sfs_sync(struct fs *fs)
{
    struct sfs_fs *sfs;
    int i, num, result;
    struct array *tmp;

    /*
     * Get the sfs_fs from the generic abstract fs.
     *
     * Note that the abstract struct fs, which is all the VFS
     * layer knows about, is actually a member of struct sfs_fs.
     * The pointer in the struct fs points back to the top of the
     * struct sfs_fs - essentially the same object. This can be a
     * little confusing at first.
     *
     * The following diagram may help:
     *
     *     struct sfs_fs        <-------------\
         *           :                            |
         *           :   sfs_absfs (struct fs)    |   <------\
         *           :      :                     |          |
         *           :      :  various members    |          |
         *           :      :                     |          |
         *           :      :  fs_data  ----------/          |
         *           :      :                             ...|...
         *           :                                   .  VFS  .
         *           :                                   . layer .
         *           :   other members                    .......
         *           :
         *           :
     *
     * This construct is repeated with vnodes and devices and other
     * similar things all over the place in OS/161, so taking the
     * time to straighten it out in your mind is worthwhile.
     */

    sfs = fs->fs_data;


    /*
     * This is kind of a hack. We can't acquire vnode locks while
     * holding sfs_vnlock, because that violates the ordering
     * constraints (see sfs_vnode.c) - so we *copy* the array of
     * loaded vnodes into a temporary array and sync those.
     */

    tmp = array_create();
    if (tmp == NULL) {
        return ENOMEM;
    }
    lock_acquire(sfs->sfs_vnlock);

    /* Go over the array of loaded vnodes. */
    num = array_getnum(sfs->sfs_vnodes);
    for (i=0; i<num; i++) {
        struct sfs_vnode *sv = array_getguy(sfs->sfs_vnodes, i);
        VOP_INCREF(&sv->sv_v);
        if (array_add(tmp, sv) != 0) {
            // XXX
            panic("sfs_sync: array_add failed\n");
        }
    }

    lock_release(sfs->sfs_vnlock);

    /* Now sync. */
    num = array_getnum(tmp);
    for (i=0; i<num; i++) {
        struct sfs_vnode *sv = array_getguy(tmp, i);
        result = VOP_FSYNC(&sv->sv_v);
        if (result) {
            kprintf("SFS: Warning: syncing inode %d: %s\n",
                    sv->sv_ino, strerror(result));
        }
        VOP_DECREF(&sv->sv_v);
    }
    array_destroy(tmp);

    lock_acquire(sfs->sfs_bitlock);

    /* If the free block map needs to be written, write it. */
    if (sfs->sfs_freemapdirty) {
        result = sfs_mapio(sfs, UIO_WRITE);
        if (result) {
            kprintf("SFS: Warning: syncing bitmap: %s\n",
                    strerror(result));
        }
        else {
            /* Only clear the dirty bit if we succeeded */
            sfs->sfs_freemapdirty = 0;
        }
    }

    /* If the superblock needs to be written, write it. */
    if (sfs->sfs_superdirty) {
        result = sfs_wblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);
        if (result) {
            kprintf("SFS: Warning: syncing superblock: %s\n",
                    strerror(result));
        }
        else {
            /* Only clear the dirty bit if we succeeded */
            sfs->sfs_superdirty = 0;
        }
    }

    lock_release(sfs->sfs_bitlock);

    return 0;
}
Beispiel #9
0
/*
 * Look up the disk block number (from 0 up to the number of blocks on
 * the disk) given a file and the logical block number within that
 * file. If DOALLOC is set, and no such block exists, one will be
 * allocated.
 */
static
int
sfs_bmap(struct sfs_vnode *sv, u_int32_t fileblock, int doalloc,
	    u_int32_t *diskblock)
{
	/*
	 * I/O buffer for handling indirect blocks.
	 *
	 * Note: in real life (and when you've done the fs assignment)
	 * you would get space from the disk buffer cache for this,
	 * not use a static area.
	 */
	static u_int32_t blockbuf[SFS_DBPERIDB];		// I/O blockbuffer
	struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
	u_int32_t block;								// used to store datablock
	u_int32_t idblock;								// stores indirect/double id/triple id blocks (not datablocks)
	u_int32_t idnum;
	int result;
	u_int32_t idblevel = 0;							// indirect block level (1=indirect,2=double,3=triple)
	u_int32_t blockno;								// the blocknumber to load (offset into indirect space)


	/*
	 * **********************************************************************
	 * Two helpfunctions for assignment 3 goes here. I keep this internal
	 * to keep things a bit simpler for this assignment. Otherwise I would
	 * have made this as external functions equal to bfree, balloc etc...
	 * **********************************************************************
	 */


	/*
	 * loadbuffer: load "block" into the block buffer "blockbuf"
	 * if level == 0 we also update inode indirect/doub.ind./trip.ind pointers
	 * This function should only be called if "doalloc" is set
	 */
	int loadbuffer(u_int32_t block, u_int32_t level){
		if (block==0) {
			/*
			 * There's no indirect block allocated, but we need to
			 * allocate a block whose number needs to be stored in
			 * the indirect block. Thus, we need to allocate an
			 * indirect block.
			 */
			result = sfs_balloc(sfs, &block);
			if (result)
				return result;

			/* keep track of the number of blocks */
			sv->sv_i.sfi_blocks++;
			
			/* Remember the block we just allocated */
			if (level == 0){
				if (idblevel==1)
					sv->sv_i.sfi_indirect = block;
				else if (idblevel==2)
					sv->sv_i.sfi_doubleindirect = block;
				else if (idblevel==3)
					sv->sv_i.sfi_tripleindirect = block;
			}
			/* update global idblock */
			idblock = block;
			
			/* Mark the inode dirty */
			sv->sv_dirty = 1;
	
			/* Clear the block buffer */
			bzero(blockbuf, sizeof(blockbuf));
		}
		else {
			/*
			 * We already have an indirect block allocated; load it.
			 */
			result = sfs_rblock(sfs, blockbuf, block);
			if (result)
				return result;
		}
		return 0;
	}

	/*
	 * get_block: the function fetches a block out of
	 * the buffer and into "block", it might allocate a new
	 * if block is empty
	 */
	int get_block(u_int32_t blockno){

		/* get block from buffer */
		block = blockbuf[blockno];

		/* If there's no block there, allocate one */
		if (block==0 && doalloc) {

			result = sfs_balloc(sfs, &block);
			if (result) {
				return result;
			}
	
			/* increase blockcounter */
			sv->sv_i.sfi_blocks++;
	
			/* Remember the block we allocated */
			blockbuf[blockno] = block;

			/* The indirect block is now dirty; write it back */
			result = sfs_wblock(sfs, blockbuf, idblock);
			if (result)
				return result;
		}
		return 0;
	}