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