xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_fem.c (revision ca9327a6de44d69ddab3668cc1e143ce781387a3)
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	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <smbsrv/smb_incl.h>
29 #include <sys/sdt.h>
30 #include <sys/vfs.h>
31 #include <sys/vfs_opreg.h>
32 #include <sys/vnode.h>
33 #include <sys/fem.h>
34 
35 int smb_fem_fcn_create(femarg_t *, char *, vattr_t *, vcexcl_t, int,
36     vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *);
37 int smb_fem_fcn_remove(femarg_t *, char *, cred_t *,
38     caller_context_t *, int);
39 int smb_fem_fcn_rename(femarg_t *, char *, vnode_t *, char *,
40     cred_t *, caller_context_t *, int);
41 int smb_fem_fcn_mkdir(femarg_t *, char *, vattr_t *, vnode_t **,
42     cred_t *, caller_context_t *, int, vsecattr_t *);
43 int smb_fem_fcn_rmdir(femarg_t *, char *, vnode_t *, cred_t *,
44     caller_context_t *, int);
45 int smb_fem_fcn_link(femarg_t *, vnode_t *, char *, cred_t *,
46     caller_context_t *, int);
47 int smb_fem_fcn_symlink(femarg_t *, char *, vattr_t *,
48     char *, cred_t *, caller_context_t *, int);
49 
50 static const fs_operation_def_t smb_fcn_tmpl[] = {
51 	VOPNAME_CREATE, { .femop_create = smb_fem_fcn_create },
52 	VOPNAME_REMOVE, {.femop_remove = smb_fem_fcn_remove},
53 	VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename},
54 	VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir},
55 	VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir},
56 	VOPNAME_LINK, {.femop_link = smb_fem_fcn_link},
57 	VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink},
58 	NULL, NULL
59 };
60 
61 static boolean_t	smb_fem_initialized = B_FALSE;
62 static fem_t		*smb_fcn_ops = NULL;
63 /*
64  * smb_fem_init
65  *
66  * This function is not multi-thread safe. The caller must make sure only one
67  * thread makes the call.
68  */
69 int
70 smb_fem_init(void)
71 {
72 	int	rc = 0;
73 
74 	if (smb_fem_initialized)
75 		return (0);
76 
77 	rc = fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops);
78 	if (rc)
79 		return (rc);
80 
81 	smb_fem_initialized = B_TRUE;
82 
83 	return (0);
84 }
85 
86 /*
87  * smb_fem_fini
88  *
89  * This function is not multi-thread safe. The caller must make sure only one
90  * thread makes the call.
91  */
92 void
93 smb_fem_fini(void)
94 {
95 	if (!smb_fem_initialized)
96 		return;
97 
98 	fem_free(smb_fcn_ops);
99 	smb_fcn_ops = NULL;
100 	smb_fem_initialized = B_FALSE;
101 }
102 
103 void
104 smb_fem_fcn_install(smb_node_t *node)
105 {
106 	(void) fem_install(node->vp, smb_fcn_ops, (void *)node,
107 	    OPARGUNIQ, (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
108 }
109 
110 void
111 smb_fem_fcn_uninstall(smb_node_t *node)
112 {
113 	(void) fem_uninstall(node->vp, smb_fcn_ops, (void *)node);
114 }
115 
116 /*
117  * smb_fem_fcn_create()
118  *
119  * This monitor will catch only changes to VREG files and not to extended
120  * attribute files.  This is fine because, for CIFS files, stream creates
121  * should not trigger any file change notification on the VDIR directory
122  * being monitored.  Creates of any other kind of extended attribute in
123  * the directory will also not trigger any file change notification on the
124  * VDIR directory being monitored.
125  */
126 
127 int
128 smb_fem_fcn_create(
129     femarg_t *arg,
130     char *name,
131     vattr_t *vap,
132     vcexcl_t excl,
133     int mode,
134     vnode_t **vpp,
135     cred_t *cr,
136     int flag,
137     caller_context_t *ct,
138     vsecattr_t *vsecp)
139 {
140 	smb_node_t *dnode;
141 	int error;
142 
143 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
144 
145 	ASSERT(dnode);
146 
147 	error = vnext_create(arg, name, vap, excl, mode, vpp, cr, flag,
148 	    ct, vsecp);
149 
150 	if (error == 0)
151 		smb_process_node_notify_change_queue(dnode);
152 
153 	return (error);
154 }
155 
156 /*
157  * smb_fem_fcn_remove()
158  *
159  * This monitor will catch only changes to VREG files and to not extended
160  * attribute files.  This is fine because, for CIFS files, stream deletes
161  * should not trigger any file change notification on the VDIR directory
162  * being monitored.  Deletes of any other kind of extended attribute in
163  * the directory will also not trigger any file change notification on the
164  * VDIR directory being monitored.
165  */
166 
167 int
168 smb_fem_fcn_remove(
169     femarg_t *arg,
170     char *name,
171     cred_t *cr,
172     caller_context_t *ct,
173     int flags)
174 {
175 	smb_node_t *dnode;
176 	int error;
177 
178 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
179 
180 	ASSERT(dnode);
181 
182 	error = vnext_remove(arg, name, cr, ct, flags);
183 
184 	if (error == 0)
185 		smb_process_node_notify_change_queue(dnode);
186 
187 	return (error);
188 }
189 
190 int
191 smb_fem_fcn_rename(
192     femarg_t *arg,
193     char *snm,
194     vnode_t *tdvp,
195     char *tnm,
196     cred_t *cr,
197     caller_context_t *ct,
198     int flags)
199 {
200 	smb_node_t *dnode;
201 	int error;
202 
203 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
204 
205 	ASSERT(dnode);
206 
207 	error = vnext_rename(arg, snm, tdvp, tnm, cr, ct, flags);
208 
209 	if (error == 0)
210 		smb_process_node_notify_change_queue(dnode);
211 
212 	return (error);
213 }
214 
215 int
216 smb_fem_fcn_mkdir(
217     femarg_t *arg,
218     char *name,
219     vattr_t *vap,
220     vnode_t **vpp,
221     cred_t *cr,
222     caller_context_t *ct,
223     int flags,
224     vsecattr_t *vsecp)
225 {
226 	smb_node_t *dnode;
227 	int error;
228 
229 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
230 
231 	ASSERT(dnode);
232 
233 	error = vnext_mkdir(arg, name, vap, vpp, cr, ct, flags, vsecp);
234 
235 	if (error == 0)
236 		smb_process_node_notify_change_queue(dnode);
237 
238 	return (error);
239 }
240 
241 int
242 smb_fem_fcn_rmdir(
243     femarg_t *arg,
244     char *name,
245     vnode_t *cdir,
246     cred_t *cr,
247     caller_context_t *ct,
248     int flags)
249 {
250 	smb_node_t *dnode;
251 	int error;
252 
253 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
254 
255 	ASSERT(dnode);
256 
257 	error = vnext_rmdir(arg, name, cdir, cr, ct, flags);
258 
259 	if (error == 0)
260 		smb_process_node_notify_change_queue(dnode);
261 
262 	return (error);
263 }
264 
265 int
266 smb_fem_fcn_link(
267     femarg_t *arg,
268     vnode_t *svp,
269     char *tnm,
270     cred_t *cr,
271     caller_context_t *ct,
272     int flags)
273 {
274 	smb_node_t *dnode;
275 	int error;
276 
277 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
278 
279 	ASSERT(dnode);
280 
281 	error = vnext_link(arg, svp, tnm, cr, ct, flags);
282 
283 	if (error == 0)
284 		smb_process_node_notify_change_queue(dnode);
285 
286 	return (error);
287 }
288 
289 int
290 smb_fem_fcn_symlink(
291     femarg_t *arg,
292     char *linkname,
293     vattr_t *vap,
294     char *target,
295     cred_t *cr,
296     caller_context_t *ct,
297     int flags)
298 {
299 	smb_node_t *dnode;
300 	int error;
301 
302 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
303 
304 	ASSERT(dnode);
305 
306 	error = vnext_symlink(arg, linkname, vap, target, cr, ct, flags);
307 
308 	if (error == 0)
309 		smb_process_node_notify_change_queue(dnode);
310 
311 	return (error);
312 }
313