xref: /titanic_50/usr/src/uts/common/fs/smbsrv/smb_vfs.c (revision 3fbbb872ea33adea240e8fd8c692f6d3131cc69b)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <smbsrv/smb_incl.h>
29 #include <smbsrv/smb_fsops.h>
30 #include <sys/vfs.h>
31 
32 static smb_vfs_t *smb_vfs_lookup(vnode_t *);
33 
34 /*
35  * smb_vfs_hold
36  *
37  * Increments the reference count of the fs passed in. If no smb_vfs_t structure
38  * has been created yet for the fs passed in it is created.
39  */
40 boolean_t
41 smb_vfs_hold(vfs_t *vfsp)
42 {
43 	smb_vfs_t	*smb_vfs;
44 	vnode_t 	*rootvp;
45 
46 	if ((vfsp == NULL) || VFS_ROOT(vfsp, &rootvp))
47 		return (B_FALSE);
48 
49 	smb_llist_enter(&smb_info.si_vfs_list, RW_WRITER);
50 	smb_vfs = smb_vfs_lookup(rootvp);
51 	if (smb_vfs) {
52 		DTRACE_PROBE1(smb_vfs_hold_hit, smb_vfs_t *, smb_vfs);
53 		smb_llist_exit(&smb_info.si_vfs_list);
54 		VN_RELE(rootvp);
55 		return (B_TRUE);
56 	}
57 	smb_vfs = kmem_cache_alloc(smb_info.si_cache_vfs, KM_SLEEP);
58 
59 	bzero(smb_vfs, sizeof (smb_vfs_t));
60 
61 	smb_vfs->sv_magic = SMB_VFS_MAGIC;
62 	smb_vfs->sv_refcnt = 1;
63 	smb_vfs->sv_vfsp = vfsp;
64 	/*
65 	 * We have a hold on the root vnode of the file system
66 	 * from the VFS_ROOT call above.
67 	 */
68 	smb_vfs->sv_rootvp = rootvp;
69 	smb_llist_insert_head(&smb_info.si_vfs_list, smb_vfs);
70 	DTRACE_PROBE1(smb_vfs_hold_miss, smb_vfs_t *, smb_vfs);
71 	smb_llist_exit(&smb_info.si_vfs_list);
72 	return (B_TRUE);
73 }
74 
75 /*
76  * smb_vfs_rele
77  *
78  * Decrements the reference count of the fs passed in. If the reference count
79  * drops to zero the smb_vfs_t structure associated with the fs is freed.
80  */
81 void
82 smb_vfs_rele(vfs_t *vfsp)
83 {
84 	smb_vfs_t	*smb_vfs;
85 	vnode_t		*rootvp;
86 
87 	ASSERT(vfsp);
88 
89 	if (VFS_ROOT(vfsp, &rootvp))
90 		return;
91 
92 	smb_llist_enter(&smb_info.si_vfs_list, RW_WRITER);
93 	smb_vfs = smb_vfs_lookup(rootvp);
94 	DTRACE_PROBE2(smb_vfs_release, smb_vfs_t *, smb_vfs, vnode_t *, rootvp);
95 	VN_RELE(rootvp);
96 	if (smb_vfs) {
97 		--smb_vfs->sv_refcnt;
98 		ASSERT(smb_vfs->sv_refcnt);
99 		if (--smb_vfs->sv_refcnt == 0) {
100 			smb_llist_remove(&smb_info.si_vfs_list, smb_vfs);
101 			smb_llist_exit(&smb_info.si_vfs_list);
102 			ASSERT(rootvp == smb_vfs->sv_rootvp);
103 			VN_RELE(smb_vfs->sv_rootvp);
104 			smb_vfs->sv_magic = (uint32_t)~SMB_VFS_MAGIC;
105 			kmem_cache_free(smb_info.si_cache_vfs, smb_vfs);
106 			return;
107 		}
108 	}
109 	smb_llist_exit(&smb_info.si_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()
121 {
122 	smb_vfs_t	*smb_vfs;
123 
124 	smb_llist_enter(&smb_info.si_vfs_list, RW_WRITER);
125 	while ((smb_vfs = smb_llist_head(&smb_info.si_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(&smb_info.si_vfs_list, smb_vfs);
130 		VN_RELE(smb_vfs->sv_rootvp);
131 		kmem_cache_free(smb_info.si_cache_vfs, smb_vfs);
132 	}
133 	smb_llist_exit(&smb_info.si_vfs_list);
134 }
135 
136 /*
137  * smb_vfs_lookup
138  *
139  * Goes through the list of smb_vfs_t structure and returns the one matching
140  * the vnode passed in. If no match is found a NULL pointer is returned.
141  *
142  * The list of smb_vfs_t structures has to have been entered prior calling
143  * this function.
144  */
145 static smb_vfs_t *
146 smb_vfs_lookup(vnode_t *rootvp)
147 {
148 	smb_vfs_t	*smb_vfs;
149 
150 	smb_vfs = smb_llist_head(&smb_info.si_vfs_list);
151 	while (smb_vfs) {
152 		ASSERT(smb_vfs->sv_magic == SMB_VFS_MAGIC);
153 		if (smb_vfs->sv_rootvp == rootvp) {
154 			smb_vfs->sv_refcnt++;
155 			ASSERT(smb_vfs->sv_refcnt);
156 			return (smb_vfs);
157 		}
158 		smb_vfs = smb_llist_next(&smb_info.si_vfs_list, smb_vfs);
159 	}
160 	return (NULL);
161 }
162