1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 #include <sys/vfs.h> 27 #include <smbsrv/smb_ktypes.h> 28 #include <smbsrv/smb_kproto.h> 29 30 static smb_vfs_t *smb_vfs_find(smb_export_t *, vfs_t *); 31 static void smb_vfs_destroy(smb_vfs_t *); 32 33 /* 34 * If a hold on the specified VFS has already been taken 35 * then only increment the reference count of the corresponding 36 * smb_vfs_t structure. If no smb_vfs_t structure has been created 37 * yet for the specified VFS then create one and take a hold on 38 * the VFS. 39 */ 40 int 41 smb_vfs_hold(smb_export_t *se, vfs_t *vfsp) 42 { 43 smb_vfs_t *smb_vfs; 44 vnode_t *rootvp; 45 int rc; 46 47 if (se == NULL || vfsp == NULL) 48 return (EINVAL); 49 50 smb_llist_enter(&se->e_vfs_list, RW_WRITER); 51 52 if ((smb_vfs = smb_vfs_find(se, vfsp)) != NULL) { 53 smb_vfs->sv_refcnt++; 54 DTRACE_PROBE1(smb_vfs_hold_hit, smb_vfs_t *, smb_vfs); 55 smb_llist_exit(&se->e_vfs_list); 56 return (0); 57 } 58 59 if ((rc = VFS_ROOT(vfsp, &rootvp)) != 0) { 60 smb_llist_exit(&se->e_vfs_list); 61 return (rc); 62 } 63 64 smb_vfs = kmem_cache_alloc(smb_kshare_cache_vfs, KM_SLEEP); 65 66 bzero(smb_vfs, sizeof (smb_vfs_t)); 67 68 smb_vfs->sv_magic = SMB_VFS_MAGIC; 69 smb_vfs->sv_refcnt = 1; 70 smb_vfs->sv_vfsp = vfsp; 71 /* 72 * We have a hold on the root vnode of the file system 73 * from the VFS_ROOT call above. 74 */ 75 smb_vfs->sv_rootvp = rootvp; 76 77 smb_llist_insert_head(&se->e_vfs_list, smb_vfs); 78 DTRACE_PROBE1(smb_vfs_hold_miss, smb_vfs_t *, smb_vfs); 79 smb_llist_exit(&se->e_vfs_list); 80 81 return (0); 82 } 83 84 /* 85 * smb_vfs_rele 86 * 87 * Decrements the reference count of the fs passed in. If the reference count 88 * drops to zero the smb_vfs_t structure associated with the fs is freed. 89 */ 90 void 91 smb_vfs_rele(smb_export_t *se, vfs_t *vfsp) 92 { 93 smb_vfs_t *smb_vfs; 94 95 ASSERT(vfsp); 96 97 smb_llist_enter(&se->e_vfs_list, RW_WRITER); 98 smb_vfs = smb_vfs_find(se, vfsp); 99 DTRACE_PROBE1(smb_vfs_release, smb_vfs_t *, smb_vfs); 100 if (smb_vfs) { 101 ASSERT(smb_vfs->sv_refcnt); 102 if (--smb_vfs->sv_refcnt == 0) { 103 smb_llist_remove(&se->e_vfs_list, smb_vfs); 104 smb_llist_exit(&se->e_vfs_list); 105 smb_vfs_destroy(smb_vfs); 106 return; 107 } 108 } 109 smb_llist_exit(&se->e_vfs_list); 110 } 111 112 /* 113 * smb_vfs_rele_all() 114 * 115 * Release all holds on root vnodes of file systems which were taken 116 * due to the existence of at least one enabled share on the file system. 117 * Called at driver close time. 118 */ 119 void 120 smb_vfs_rele_all(smb_export_t *se) 121 { 122 smb_vfs_t *smb_vfs; 123 124 smb_llist_enter(&se->e_vfs_list, RW_WRITER); 125 while ((smb_vfs = smb_llist_head(&se->e_vfs_list)) != NULL) { 126 127 ASSERT(smb_vfs->sv_magic == SMB_VFS_MAGIC); 128 DTRACE_PROBE1(smb_vfs_rele_all_hit, smb_vfs_t *, smb_vfs); 129 smb_llist_remove(&se->e_vfs_list, smb_vfs); 130 smb_vfs_destroy(smb_vfs); 131 } 132 smb_llist_exit(&se->e_vfs_list); 133 } 134 135 /* 136 * Goes through the list of smb_vfs_t structure and returns the one matching 137 * the vnode passed in. If no match is found a NULL pointer is returned. 138 * 139 * The list of smb_vfs_t structures has to have been entered prior calling 140 * this function. 141 */ 142 static smb_vfs_t * 143 smb_vfs_find(smb_export_t *se, vfs_t *vfsp) 144 { 145 smb_vfs_t *smb_vfs; 146 147 smb_vfs = smb_llist_head(&se->e_vfs_list); 148 while (smb_vfs) { 149 ASSERT(smb_vfs->sv_magic == SMB_VFS_MAGIC); 150 if (smb_vfs->sv_vfsp == vfsp) 151 return (smb_vfs); 152 smb_vfs = smb_llist_next(&se->e_vfs_list, smb_vfs); 153 } 154 155 return (NULL); 156 } 157 158 static void 159 smb_vfs_destroy(smb_vfs_t *smb_vfs) 160 { 161 VN_RELE(smb_vfs->sv_rootvp); 162 smb_vfs->sv_magic = (uint32_t)~SMB_VFS_MAGIC; 163 kmem_cache_free(smb_kshare_cache_vfs, smb_vfs); 164 } 165