/* * Create a new filesystem object and hand back its vnode. */ static int sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret) { u_int32_t ino; int result; /* * First, get an inode. (Each inode is a block, and the inode * number is the block number, so just get a block.) */ result = sfs_balloc(sfs, &ino); if (result) { return result; } /* * Now load a vnode for it. */ return sfs_loadvnode(sfs, ino, type, ret); }
/* * 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; }
/* * 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; }