xref: /titanic_50/usr/src/uts/common/fs/smbsrv/smb_vfs.c (revision 8e7248e505faa19396d4e853604e3fa7cd2cb3b5)
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