/* * Deallocate a tree: release all resources associated with a tree and * remove the tree from the user's tree list. * * The tree being destroyed must be in the "destroying" state and the * reference count must be zero. This function assumes it's single threaded * i.e. only one thread will attempt to destroy a specific tree, which * should be the case if the tree is in disconnected and has a reference * count of zero. */ static void smb_tree_dealloc(smb_tree_t *tree) { ASSERT(tree); ASSERT(tree->t_magic == SMB_TREE_MAGIC); ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); ASSERT(tree->t_refcnt == 0); /* * Remove the tree from the user's tree list. This must be done * before any resources associated with the tree are released. */ smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER); smb_llist_remove(&tree->t_user->u_tree_list, tree); smb_llist_exit(&tree->t_user->u_tree_list); tree->t_magic = (uint32_t)~SMB_TREE_MAGIC; smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid); atomic_dec_32(&tree->t_session->s_tree_cnt); if (tree->t_snode) smb_node_release(tree->t_snode); mutex_destroy(&tree->t_mutex); /* * The list of open files and open directories should be empty. */ smb_llist_destructor(&tree->t_ofile_list); smb_llist_destructor(&tree->t_odir_list); smb_idpool_destructor(&tree->t_fid_pool); smb_idpool_destructor(&tree->t_odid_pool); kmem_cache_free(tree->t_server->si_cache_tree, tree); }
/* * Delete an odir. * * Remove the odir from the tree list before freeing resources * associated with the odir. */ void smb_odir_delete(void *arg) { smb_tree_t *tree; smb_odir_t *od = (smb_odir_t *)arg; SMB_ODIR_VALID(od); ASSERT(od->d_refcnt == 0); ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED); tree = od->d_tree; smb_llist_enter(&tree->t_odir_list, RW_WRITER); smb_llist_remove(&tree->t_odir_list, od); smb_idpool_free(&tree->t_odid_pool, od->d_odid); atomic_dec_32(&tree->t_session->s_dir_cnt); smb_llist_exit(&tree->t_odir_list); mutex_enter(&od->d_mutex); mutex_exit(&od->d_mutex); od->d_magic = 0; smb_node_release(od->d_dnode); smb_user_release(od->d_user); mutex_destroy(&od->d_mutex); kmem_cache_free(smb_cache_odir, od); }
/* * smb_vfs_rele_all() * * Release all holds on root vnodes of file systems which were taken * due to the existence of at least one enabled share on the file system. * Called at driver close time. */ void smb_vfs_rele_all(smb_export_t *se) { smb_vfs_t *smb_vfs; smb_llist_enter(&se->e_vfs_list, RW_WRITER); while ((smb_vfs = smb_llist_head(&se->e_vfs_list)) != NULL) { ASSERT(smb_vfs->sv_magic == SMB_VFS_MAGIC); DTRACE_PROBE1(smb_vfs_rele_all_hit, smb_vfs_t *, smb_vfs); smb_llist_remove(&se->e_vfs_list, smb_vfs); smb_vfs_destroy(smb_vfs); } smb_llist_exit(&se->e_vfs_list); }
/* * Delete an ofile. * * Remove the ofile from the tree list before freeing resources * associated with the ofile. */ void smb_ofile_delete(void *arg) { smb_tree_t *tree; smb_ofile_t *of = (smb_ofile_t *)arg; SMB_OFILE_VALID(of); ASSERT(of->f_refcnt == 0); ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED); ASSERT(!SMB_OFILE_OPLOCK_GRANTED(of)); tree = of->f_tree; smb_llist_enter(&tree->t_ofile_list, RW_WRITER); smb_llist_remove(&tree->t_ofile_list, of); smb_idpool_free(&tree->t_fid_pool, of->f_fid); atomic_dec_32(&tree->t_session->s_file_cnt); smb_llist_exit(&tree->t_ofile_list); mutex_enter(&of->f_mutex); mutex_exit(&of->f_mutex); switch (of->f_ftype) { case SMB_FTYPE_BYTE_PIPE: case SMB_FTYPE_MESG_PIPE: smb_opipe_dealloc(of->f_pipe); of->f_pipe = NULL; break; case SMB_FTYPE_DISK: if (of->f_odir != NULL) smb_odir_release(of->f_odir); smb_node_rem_ofile(of->f_node, of); smb_node_release(of->f_node); break; default: ASSERT(!"f_ftype"); break; } of->f_magic = (uint32_t)~SMB_OFILE_MAGIC; mutex_destroy(&of->f_mutex); crfree(of->f_cr); smb_user_release(of->f_user); kmem_cache_free(smb_cache_ofile, of); }
/* * smb_vfs_rele * * Decrements the reference count of the fs passed in. If the reference count * drops to zero the smb_vfs_t structure associated with the fs is freed. */ void smb_vfs_rele(smb_export_t *se, vfs_t *vfsp) { smb_vfs_t *smb_vfs; ASSERT(vfsp); smb_llist_enter(&se->e_vfs_list, RW_WRITER); smb_vfs = smb_vfs_find(se, vfsp); DTRACE_PROBE1(smb_vfs_release, smb_vfs_t *, smb_vfs); if (smb_vfs) { ASSERT(smb_vfs->sv_refcnt); if (--smb_vfs->sv_refcnt == 0) { smb_llist_remove(&se->e_vfs_list, smb_vfs); smb_llist_exit(&se->e_vfs_list); smb_vfs_destroy(smb_vfs); return; } } smb_llist_exit(&se->e_vfs_list); }