static int sfs_mkdir_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name) { int ret, slot; if ((ret = sfs_dirent_search_nolock(sfs, sin, name, NULL, NULL, &slot)) != -E_NOENT) { return (ret != 0) ? ret : -E_EXISTS; } struct inode *link_node; if ((ret = sfs_dirent_create_inode(sfs, SFS_TYPE_DIR, &link_node)) != 0) { return ret; } struct sfs_inode *lnksin = vop_info(link_node, sfs_inode); if ((ret = sfs_dirent_link_nolock(sfs, sin, slot, lnksin, name)) != 0) { assert(lnksin->din->nlinks == 0); assert(inode_ref_count(link_node) == 1 && inode_open_count(link_node) == 0); goto out; } /* set parent */ sfs_dirinfo_set_parent(lnksin, sin); /* add '.' link to itself */ sfs_nlinks_inc_nolock(lnksin); /* add '..' link to parent */ sfs_nlinks_inc_nolock(sin); out: vop_ref_dec(link_node); return ret; }
/* * * inode_check - check the various things being valid * called before all vop_* calls * */ void inode_check(struct inode *node, const char *opstr) { assert(node != NULL && node->in_ops != NULL); assert(node->in_ops->vop_magic == VOP_MAGIC); int ref_count = inode_ref_count(node), open_count = inode_open_count(node); assert(ref_count >= open_count && open_count >= 0); assert(ref_count < MAX_INODE_COUNT && open_count < MAX_INODE_COUNT); }
/* * * inode_ref_dec - decrement ref_count * invoked by vop_ref_dec * calls vop_reclaim if the ref_count hits zero * */ int inode_ref_dec(struct inode *node) { assert(inode_ref_count(node) > 0); int ref_count, ret; if ((ref_count = atomic_sub_return(&(node->ref_count), 1)) == 0) { if ((ret = vop_reclaim(node)) != 0 && ret != -E_BUSY) { kprintf("vfs: warning: vop_reclaim: %e.\n", ret); } } return ref_count; }
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; }
static int pipe_inode_reclaim(struct inode *node) { struct pipe_inode *pin = vop_info(node, pipe_inode); if (pin->name != NULL) { struct pipe_fs *pipe = fsop_info(vop_fs(node), pipe); lock_pipe(pipe); assert(pin->reclaim_count > 0); if ((--pin->reclaim_count) != 0 || inode_ref_count(node) != 0) { unlock_pipe(pipe); return -E_BUSY; } list_del(&(pin->pipe_link)); unlock_pipe(pipe); kfree(pin->name); } pipe_state_release(pin->state); vop_kill(node); return 0; }
/* * 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; }
/* * * inode_kill - kill a inode structure * invoked by vop_kill * */ void inode_kill(struct inode *node) { assert(inode_ref_count(node) == 0); assert(inode_open_count(node) == 0); kfree(node); }