/* * s5_alloc_inode: * Creates a new inode from the free list and initializes its fields. * Uses S5_INODE_BLOCK to get the page from which to create the inode * * This function may block. * param *fs: the pointer to the file system * param type: the type of this new inode * param devid: device id * return: the inode number, or -1 for any errors */ int s5_alloc_inode(fs_t *fs, uint16_t type, devid_t devid) { s5fs_t *s5fs = FS_TO_S5FS(fs); pframe_t *inodep = NULL; s5_inode_t *inode = NULL; int ret = -1; KASSERT((S5_TYPE_DATA == type) || (S5_TYPE_DIR == type) || (S5_TYPE_CHR == type) || (S5_TYPE_BLK == type)); lock_s5(s5fs); if (s5fs->s5f_super->s5s_free_inode == (uint32_t) - 1) { unlock_s5(s5fs); return -ENOSPC; } pframe_get(&s5fs->s5f_bdev->bd_mmobj, S5_INODE_BLOCK(s5fs->s5f_super->s5s_free_inode), &inodep); KASSERT(inodep); inode = (s5_inode_t *)(inodep->pf_addr) + S5_INODE_OFFSET(s5fs->s5f_super->s5s_free_inode); KASSERT(inode->s5_number == s5fs->s5f_super->s5s_free_inode); ret = inode->s5_number; /* reset s5s_free_inode; remove the inode from the inode free list: */ s5fs->s5f_super->s5s_free_inode = inode->s5_next_free; pframe_pin(inodep); s5_dirty_super(s5fs); pframe_unpin(inodep); /* init the newly-allocated inode: */ inode->s5_size = 0; inode->s5_type = type; inode->s5_linkcount = 0; memset(inode->s5_direct_blocks, 0, S5_NDIRECT_BLOCKS * sizeof(int)); if ((S5_TYPE_CHR == type) || (S5_TYPE_BLK == type)) inode->s5_indirect_block = devid; else inode->s5_indirect_block = 0; s5_dirty_inode(s5fs, inode); unlock_s5(s5fs); return ret; }
/* * s5_alloc_block: * Allocate a new disk-block off the block free list and return it. * param *fs: the pointer to the file system object * return: the block number, or negative number if no space */ static int s5_alloc_block(s5fs_t *fs) { dbg(DBG_S5FS, "{\n"); KASSERT(fs != NULL); lock_s5(fs); s5_super_t* super = fs->s5f_super; pframe_t* next_free_block = NULL; int ret = 0; int block_number = 0; if (super->s5s_nfree == 0) /* no free pages */ { int ret = pframe_get( S5FS_TO_VMOBJ(fs), super->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1], &next_free_block); if (ret < 0 || next_free_block == NULL) { /* No more free blocks */ unlock_s5(fs); dbg(DBG_S5FS, "}(error code returned)\n"); return -ENOSPC; } else { block_number = super->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1]; /* copy the next free block into the super block */ memcpy((void*)(super->s5s_free_blocks), next_free_block->pf_addr, S5_NBLKS_PER_FNODE * sizeof(uint32_t)); memset(next_free_block->pf_addr, 0, S5_BLOCK_SIZE); pframe_dirty(next_free_block); pframe_clean(next_free_block); pframe_free(next_free_block); /* now full */ super->s5s_nfree = S5_NBLKS_PER_FNODE-1; s5_dirty_super(fs); unlock_s5(fs); dbg(DBG_S5FS, "}\n"); return block_number; } } else /* there is some free pages */ { block_number = super->s5s_free_blocks[super->s5s_nfree - 1]; super->s5s_nfree--; s5_dirty_super(fs); unlock_s5(fs); dbg(DBG_S5FS, "}\n"); return block_number; } }
/* * Allocate a new disk-block off the block free list and return it. If * there are no free blocks, return -ENOSPC. * * This will not initialize the contents of an allocated block; these * contents are undefined. * * If the super block's s5s_nfree is 0, you need to refill * s5s_free_blocks and reset s5s_nfree. You need to read the contents * of this page using the pframe system in order to obtain the next set of * free block numbers. * * Don't forget to dirty the appropriate blocks! * * You'll probably want to use lock_s5(), unlock_s5(), pframe_get(), * and s5_dirty_super() */ static int s5_alloc_block(s5fs_t *fs) { dbg_print("s5_alloc_block: Entering Function\n"); /* get the super block frame */ s5_super_t* superblock = fs->s5f_super; int block_return; lock_s5(fs); if(((int)superblock->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1] == -1) && (superblock->s5s_nfree == 0)) { dbg_print("s5_alloc_block: No free blocks, returning error"); unlock_s5(fs); return -ENOSPC; } if(superblock->s5s_nfree == 0) { dbg_print("s5_alloc_block: Out of free blocks, getting more!\n"); struct mmobj* fs_vmobj = S5FS_TO_VMOBJ(fs); int next_block = superblock->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1]; pframe_t* pf; pframe_get(fs_vmobj,next_block,&pf); pframe_pin(pf); memcpy(((char*)superblock->s5s_free_blocks),pf->pf_addr,S5_NBLKS_PER_FNODE * sizeof(uint32_t)); superblock->s5s_nfree = S5_NBLKS_PER_FNODE - 1; block_return = next_block; pframe_unpin(pf); } else { /* Frre blocks are available */ dbg_print("s5_alloc_block: Free block available\n"); superblock->s5s_nfree--; block_return = superblock->s5s_free_blocks[superblock->s5s_nfree]; } s5_dirty_super(fs); unlock_s5(fs); dbg_print("s5_alloc_block: Exiting Function\n"); return block_return; /* NOT_YET_IMPLEMENTED("S5FS: s5_alloc_block"); * return -1; */ }
/* * s5_free_block * Given a filesystem and a block number, frees the given block in the * filesystem. * * This function may potentially block. * param *fs: the pointer to the file system * param blockno: the block number */ static void s5_free_block(s5fs_t *fs, int blockno) { s5_super_t *s = fs->s5f_super; lock_s5(fs); KASSERT(S5_NBLKS_PER_FNODE > s->s5s_nfree); if ((S5_NBLKS_PER_FNODE - 1) == s->s5s_nfree) { /* get the pframe where we will store the free block nums */ pframe_t *prev_free_blocks = NULL; KASSERT(fs->s5f_bdev); pframe_get(&fs->s5f_bdev->bd_mmobj, blockno, &prev_free_blocks); KASSERT(prev_free_blocks->pf_addr); /* copy from the superblock to the new block on disk */ memcpy(prev_free_blocks->pf_addr, (void *)(s->s5s_free_blocks), S5_NBLKS_PER_FNODE * sizeof(int)); pframe_dirty(prev_free_blocks); /* reset s->s5s_nfree and s->s5s_free_blocks */ s->s5s_nfree = 0; s->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1] = blockno; } else { s->s5s_free_blocks[s->s5s_nfree++] = blockno; } s5_dirty_super(fs); unlock_s5(fs); }
/* * Allocate a new disk-block off the block free list and return it. If * there are no free blocks, return -ENOSPC. * * This will not initialize the contents of an allocated block; these * contents are undefined. * * If the super block's s5s_nfree is 0, you need to refill * s5s_free_blocks and reset s5s_nfree. You need to read the contents * of this page using the pframe system in order to obtain the next set of * free block numbers. * * Don't forget to dirty the appropriate blocks! * * You'll probably want to use lock_s5(), unlock_s5(), pframe_get(), * and s5_dirty_super() */ static int s5_alloc_block(s5fs_t *fs) { s5_super_t *s = fs->s5f_super; lock_s5(fs); KASSERT(S5_NBLKS_PER_FNODE > s->s5s_nfree); int free_block_num; if (s->s5s_nfree == 0){ free_block_num = s->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1]; if (free_block_num == -1){ unlock_s5(fs); return -ENOSPC; } /* get the pframe from which we'll replenish our list of free block nums */ pframe_t *next_free_blocks; KASSERT(fs->s5f_bdev); int get_res = pframe_get(&fs->s5f_bdev->bd_mmobj, free_block_num, &next_free_blocks); if (get_res < 0){ dbg(DBG_S5FS, "error in pframe_get\n"); unlock_s5(fs); return get_res; } memcpy((void *)(s->s5s_free_blocks), next_free_blocks->pf_addr, S5_NBLKS_PER_FNODE * sizeof(int)); s->s5s_nfree = S5_NBLKS_PER_FNODE - 1; } else { free_block_num = s->s5s_free_blocks[--s->s5s_nfree]; } s5_dirty_super(fs); unlock_s5(fs); return free_block_num; }
/* * s5_free_inode: * Free an inode by freeing its disk blocks and putting it back on the * inode free list. * param *vnode: the pointer to the vnode object */ void s5_free_inode(vnode_t *vnode) { uint32_t i = 0; s5_inode_t *inode = VNODE_TO_S5INODE(vnode); s5fs_t *fs = VNODE_TO_S5FS(vnode); KASSERT((S5_TYPE_DATA == inode->s5_type) || (S5_TYPE_DIR == inode->s5_type) || (S5_TYPE_CHR == inode->s5_type) || (S5_TYPE_BLK == inode->s5_type)); /* free any direct blocks */ for (i = 0; i < S5_NDIRECT_BLOCKS; ++i) { if (inode->s5_direct_blocks[i]) { dprintf("freeing block %d\n", inode->s5_direct_blocks[i]); s5_free_block(fs, inode->s5_direct_blocks[i]); s5_dirty_inode(fs, inode); inode->s5_direct_blocks[i] = 0; } } if (((S5_TYPE_DATA == inode->s5_type) || (S5_TYPE_DIR == inode->s5_type)) && inode->s5_indirect_block) { pframe_t *ibp; uint32_t *b; pframe_get(S5FS_TO_VMOBJ(fs), (unsigned)inode->s5_indirect_block, &ibp); KASSERT(ibp && "because never fails for block_device " "vm_objects"); pframe_pin(ibp); b = (uint32_t *)(ibp->pf_addr); for (i = 0; i < S5_NIDIRECT_BLOCKS; ++i) { KASSERT(b[i] != inode->s5_indirect_block); if (b[i]) s5_free_block(fs, b[i]); } pframe_unpin(ibp); s5_free_block(fs, inode->s5_indirect_block); } inode->s5_indirect_block = 0; inode->s5_type = S5_TYPE_FREE; s5_dirty_inode(fs, inode); lock_s5(fs); inode->s5_next_free = fs->s5f_super->s5s_free_inode; fs->s5f_super->s5s_free_inode = inode->s5_number; unlock_s5(fs); s5_dirty_inode(fs, inode); s5_dirty_super(fs); }