xref: /titanic_52/usr/src/uts/common/fs/smbsrv/smb_vfs.c (revision 36e852a172cba914383d7341c988128b2c667fbd)
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