static int sfs_reclaim(struct inode *node) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); lock_sfs_fs(sfs); int ret = -E_BUSY; assert(sin->reclaim_count > 0); if ((-- sin->reclaim_count) != 0) { goto failed_unlock; } assert(inode_ref_count(node) == 0 && inode_open_count(node) == 0); if (sin->din->nlinks == 0) { uint32_t nblks; for (nblks = sin->din->blocks; nblks != 0; nblks --) { sfs_bmap_truncate_nolock(sfs, sin); } } else if (sin->dirty) { if ((ret = vop_fsync(node)) != 0) { goto failed_unlock; } } sfs_remove_links(sin); unlock_sfs_fs(sfs); if (sin->din->nlinks == 0) { sfs_block_free(sfs, sin->ino); uint32_t ent; if ((ent = sin->din->indirect) != 0) { sfs_block_free(sfs, ent); } if ((ent = sin->din->db_indirect) != 0) { int i; for (i = 0; i < SFS_BLK_NENTRY; i ++) { sfs_bmap_free_sub_nolock(sfs, ent, i); } sfs_block_free(sfs, ent); } } kfree(sin->din); vop_kill(node); return 0; failed_unlock: unlock_sfs_fs(sfs); return ret; }
/* * sfs_bmap_free_nolock - free a block with logical index in inode and reset the inode's fields */ static int sfs_bmap_free_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, uint32_t index) { struct sfs_disk_inode *din = sin->din; int ret; uint32_t ent, ino; if (index < SFS_NDIRECT) { if ((ino = din->direct[index]) != 0) { // free the block sfs_block_free(sfs, ino); din->direct[index] = 0; sin->dirty = 1; } return 0; } index -= SFS_NDIRECT; if (index < SFS_BLK_NENTRY) { if ((ent = din->indirect) != 0) { // set the entry item to 0 in the indirect block if ((ret = sfs_bmap_free_sub_nolock(sfs, ent, index)) != 0) { return ret; } } return 0; } return 0; }
static int sfs_dirent_create_inode(struct sfs_fs *sfs, uint16_t type, struct inode **node_store) { struct sfs_disk_inode *din; if ((din = kmalloc(sizeof(struct sfs_disk_inode))) == NULL) { return -E_NO_MEM; } memset(din, 0, sizeof(struct sfs_disk_inode)); din->type = type; int ret; uint32_t ino; if ((ret = sfs_block_alloc(sfs, &ino)) != 0) { goto failed_cleanup_din; } struct inode *node; if ((ret = sfs_create_inode(sfs, din, ino, &node)) != 0) { goto failed_cleanup_ino; } lock_sfs_fs(sfs); { sfs_set_links(sfs, vop_info(node, sfs_inode)); } unlock_sfs_fs(sfs); *node_store = node; return 0; failed_cleanup_ino: sfs_block_free(sfs, ino); failed_cleanup_din: kfree(din); return ret; }
/* * sfs_bmap_get_sub_nolock - according entry pointer entp and index, find the index of indrect disk block * return the index of indrect disk block to ino_store. no lock protect * @sfs: sfs file system * @entp: the pointer of index of entry disk block * @index: the index of block in indrect block * @create: BOOL, if the block isn't allocated, if create = 1 the alloc a block, otherwise just do nothing * @ino_store: 0 OR the index of already inused block or new allocated block. */ static int sfs_bmap_get_sub_nolock(struct sfs_fs *sfs, uint32_t *entp, uint32_t index, bool create, uint32_t *ino_store) { assert(index < SFS_BLK_NENTRY); int ret; uint32_t ent, ino = 0; off_t offset = index * sizeof(uint32_t); // the offset of entry in entry block // if entry block is existd, read the content of entry block into sfs->sfs_buffer if ((ent = *entp) != 0) { if ((ret = sfs_rbuf(sfs, &ino, sizeof(uint32_t), ent, offset)) != 0) { return ret; } if (ino != 0 || !create) { goto out; } } else { if (!create) { goto out; } //if entry block isn't existd, allocated a entry block (for indrect block) if ((ret = sfs_block_alloc(sfs, &ent)) != 0) { return ret; } } if ((ret = sfs_block_alloc(sfs, &ino)) != 0) { goto failed_cleanup; } if ((ret = sfs_wbuf(sfs, &ino, sizeof(uint32_t), ent, offset)) != 0) { sfs_block_free(sfs, ino); goto failed_cleanup; } out: if (ent != *entp) { *entp = ent; } *ino_store = ino; return 0; failed_cleanup: if (ent != *entp) { sfs_block_free(sfs, ent); } return ret; }
static int sfs_bmap_get_sub_nolock(struct sfs_fs *sfs, uint32_t *entp, uint32_t index, bool create, uint32_t *ino_store) { assert(index < SFS_BLK_NENTRY); int ret; uint32_t ent, ino = 0; off_t offset = index * sizeof(uint32_t); if ((ent = *entp) != 0) { if ((ret = sfs_rbuf(sfs, &ino, sizeof(uint32_t), ent, offset)) != 0) { return ret; } if (ino != 0 || !create) { goto out; } } else { if (!create) { goto out; } if ((ret = sfs_block_alloc(sfs, &ent)) != 0) { return ret; } } if ((ret = sfs_block_alloc(sfs, &ino)) != 0) { goto failed_cleanup; } if ((ret = sfs_wbuf(sfs, &ino, sizeof(uint32_t), ent, offset)) != 0) { sfs_block_free(sfs, ino); goto failed_cleanup; } out: if (ent != *entp) { *entp = ent; } *ino_store = ino; return 0; failed_cleanup: if (ent != *entp) { sfs_block_free(sfs, ent); } return ret; }
/* * sfs_reclaim - Free all resources inode occupied . Called when inode is no longer in use. */ static int sfs_reclaim(struct inode *node) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); int ret = -E_BUSY; uint32_t ent; lock_sfs_fs(sfs); assert(sin->reclaim_count > 0); if ((-- sin->reclaim_count) != 0 || inode_ref_count(node) != 0) { goto failed_unlock; } if (sin->din->nlinks == 0) { if ((ret = vop_truncate(node, 0)) != 0) { goto failed_unlock; } } if (sin->dirty) { if ((ret = vop_fsync(node)) != 0) { goto failed_unlock; } } sfs_remove_links(sin); unlock_sfs_fs(sfs); if (sin->din->nlinks == 0) { sfs_block_free(sfs, sin->ino); if ((ent = sin->din->indirect) != 0) { sfs_block_free(sfs, ent); } } kfree(sin->din); vop_kill(node); return 0; failed_unlock: unlock_sfs_fs(sfs); return ret; }
/* * sfs_bmap_free_sub_nolock - set the entry item to 0 (free) in the indirect block */ static int sfs_bmap_free_sub_nolock(struct sfs_fs *sfs, uint32_t ent, uint32_t index) { assert(sfs_block_inuse(sfs, ent) && index < SFS_BLK_NENTRY); int ret; uint32_t ino, zero = 0; off_t offset = index * sizeof(uint32_t); if ((ret = sfs_rbuf(sfs, &ino, sizeof(uint32_t), ent, offset)) != 0) { return ret; } if (ino != 0) { if ((ret = sfs_wbuf(sfs, &zero, sizeof(uint32_t), ent, offset)) != 0) { return ret; } sfs_block_free(sfs, ino); } return 0; }
static int sfs_bmap_free_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, uint32_t index) { struct sfs_disk_inode *din = sin->din; int ret; uint32_t ent, ino; if (index < SFS_NDIRECT) { if ((ino = din->direct[index]) != 0) { sfs_block_free(sfs, ino); din->direct[index] = 0; sin->dirty = 1; } return 0; } index -= SFS_NDIRECT; if (index < SFS_BLK_NENTRY) { if ((ent = din->indirect) != 0) { if ((ret = sfs_bmap_free_sub_nolock(sfs, ent, index)) != 0) { return ret; } } return 0; } index -= SFS_BLK_NENTRY; if ((ent = din->db_indirect) != 0) { if ((ret = sfs_bmap_get_sub_nolock(sfs, &ent, index / SFS_BLK_NENTRY, 0, &ino)) != 0) { return ret; } if ((ent = ino) != 0) { if ((ret = sfs_bmap_free_sub_nolock(sfs, ent, index % SFS_BLK_NENTRY)) != 0) { return ret; } } } return 0; }