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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/fsid.h> 28 #include <sys/vfs.h> 29 #include <sys/stat.h> 30 #include <smbsrv/smb_ktypes.h> 31 #include <smbsrv/smb_kproto.h> 32 33 static smb_vfs_t *smb_vfs_lookup(smb_server_t *, vnode_t *); 34 35 /* 36 * smb_vfs_hold 37 * 38 * Increments the reference count of the fs passed in. If no smb_vfs_t structure 39 * has been created yet for the fs passed in it is created. 40 */ 41 boolean_t 42 smb_vfs_hold(smb_server_t *sv, vfs_t *vfsp) 43 { 44 smb_vfs_t *smb_vfs; 45 vnode_t *rootvp; 46 47 if ((vfsp == NULL) || VFS_ROOT(vfsp, &rootvp)) 48 return (B_FALSE); 49 50 smb_llist_enter(&sv->sv_vfs_list, RW_WRITER); 51 smb_vfs = smb_vfs_lookup(sv, rootvp); 52 if (smb_vfs) { 53 DTRACE_PROBE1(smb_vfs_hold_hit, smb_vfs_t *, smb_vfs); 54 smb_llist_exit(&sv->sv_vfs_list); 55 VN_RELE(rootvp); 56 return (B_TRUE); 57 } 58 smb_vfs = kmem_cache_alloc(sv->si_cache_vfs, KM_SLEEP); 59 60 bzero(smb_vfs, sizeof (smb_vfs_t)); 61 62 smb_vfs->sv_magic = SMB_VFS_MAGIC; 63 smb_vfs->sv_refcnt = 1; 64 smb_vfs->sv_vfsp = vfsp; 65 /* 66 * We have a hold on the root vnode of the file system 67 * from the VFS_ROOT call above. 68 */ 69 smb_vfs->sv_rootvp = rootvp; 70 smb_llist_insert_head(&sv->sv_vfs_list, smb_vfs); 71 DTRACE_PROBE1(smb_vfs_hold_miss, smb_vfs_t *, smb_vfs); 72 smb_llist_exit(&sv->sv_vfs_list); 73 return (B_TRUE); 74 } 75 76 /* 77 * smb_vfs_rele 78 * 79 * Decrements the reference count of the fs passed in. If the reference count 80 * drops to zero the smb_vfs_t structure associated with the fs is freed. 81 */ 82 void 83 smb_vfs_rele(smb_server_t *sv, vfs_t *vfsp) 84 { 85 smb_vfs_t *smb_vfs; 86 vnode_t *rootvp; 87 88 ASSERT(vfsp); 89 90 if (VFS_ROOT(vfsp, &rootvp)) 91 return; 92 93 smb_llist_enter(&sv->sv_vfs_list, RW_WRITER); 94 smb_vfs = smb_vfs_lookup(sv, rootvp); 95 DTRACE_PROBE2(smb_vfs_release, smb_vfs_t *, smb_vfs, vnode_t *, rootvp); 96 VN_RELE(rootvp); 97 if (smb_vfs) { 98 --smb_vfs->sv_refcnt; 99 ASSERT(smb_vfs->sv_refcnt); 100 if (--smb_vfs->sv_refcnt == 0) { 101 smb_llist_remove(&sv->sv_vfs_list, smb_vfs); 102 smb_llist_exit(&sv->sv_vfs_list); 103 ASSERT(rootvp == smb_vfs->sv_rootvp); 104 VN_RELE(smb_vfs->sv_rootvp); 105 smb_vfs->sv_magic = (uint32_t)~SMB_VFS_MAGIC; 106 kmem_cache_free(sv->si_cache_vfs, smb_vfs); 107 return; 108 } 109 } 110 smb_llist_exit(&sv->sv_vfs_list); 111 } 112 113 /* 114 * smb_vfs_rele_all() 115 * 116 * Release all holds on root vnodes of file systems which were taken 117 * due to the existence of at least one enabled share on the file system. 118 * Called at driver close time. 119 */ 120 void 121 smb_vfs_rele_all(smb_server_t *sv) 122 { 123 smb_vfs_t *smb_vfs; 124 125 smb_llist_enter(&sv->sv_vfs_list, RW_WRITER); 126 while ((smb_vfs = smb_llist_head(&sv->sv_vfs_list)) != NULL) { 127 128 ASSERT(smb_vfs->sv_magic == SMB_VFS_MAGIC); 129 DTRACE_PROBE1(smb_vfs_rele_all_hit, smb_vfs_t *, smb_vfs); 130 smb_llist_remove(&sv->sv_vfs_list, smb_vfs); 131 VN_RELE(smb_vfs->sv_rootvp); 132 kmem_cache_free(sv->si_cache_vfs, smb_vfs); 133 } 134 smb_llist_exit(&sv->sv_vfs_list); 135 } 136 137 /* 138 * smb_vfs_lookup 139 * 140 * Goes through the list of smb_vfs_t structure and returns the one matching 141 * the vnode passed in. If no match is found a NULL pointer is returned. 142 * 143 * The list of smb_vfs_t structures has to have been entered prior calling 144 * this function. 145 */ 146 static smb_vfs_t * 147 smb_vfs_lookup(smb_server_t *sv, vnode_t *rootvp) 148 { 149 smb_vfs_t *smb_vfs; 150 151 smb_vfs = smb_llist_head(&sv->sv_vfs_list); 152 while (smb_vfs) { 153 ASSERT(smb_vfs->sv_magic == SMB_VFS_MAGIC); 154 if (smb_vfs->sv_rootvp == rootvp) { 155 smb_vfs->sv_refcnt++; 156 ASSERT(smb_vfs->sv_refcnt); 157 return (smb_vfs); 158 } 159 smb_vfs = smb_llist_next(&sv->sv_vfs_list, smb_vfs); 160 } 161 return (NULL); 162 } 163 164 /* 165 * Returns true if both VFS pointers represent the same mounted 166 * file system. Otherwise returns false. 167 */ 168 boolean_t 169 smb_vfs_cmp(vfs_t *vfsp1, vfs_t *vfsp2) 170 { 171 fsid_t *fsid1 = &vfsp1->vfs_fsid; 172 fsid_t *fsid2 = &vfsp2->vfs_fsid; 173 boolean_t result = B_FALSE; 174 175 if ((vfsp1 = getvfs(fsid1)) == NULL) 176 return (B_FALSE); 177 178 if ((vfsp2 = getvfs(fsid2)) == NULL) { 179 VFS_RELE(vfsp1); 180 return (B_FALSE); 181 } 182 183 if ((fsid1->val[0] == fsid2->val[0]) && 184 (fsid1->val[1] == fsid2->val[1])) { 185 result = B_TRUE; 186 } 187 188 VFS_RELE(vfsp2); 189 VFS_RELE(vfsp1); 190 return (result); 191 } 192 193 /* 194 * Check whether or not a file system is readonly. 195 */ 196 boolean_t 197 smb_vfs_is_readonly(vfs_t *vfsp) 198 { 199 boolean_t result; 200 201 if (getvfs(&vfsp->vfs_fsid) == NULL) 202 return (B_FALSE); 203 204 result = (vfsp->vfs_flag & VFS_RDONLY); 205 VFS_RELE(vfsp); 206 return (result); 207 } 208