Home | History | Annotate | Download | only in smbsrv
      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