xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_fem.c (revision 10966:37e5dcdf36d3)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
228934SJose.Borrego@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
26*10966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
276600Sas200622 #include <smbsrv/smb_fsops.h>
285331Samw #include <sys/sdt.h>
296600Sas200622 #include <sys/fcntl.h>
305331Samw #include <sys/vfs.h>
315331Samw #include <sys/vfs_opreg.h>
325331Samw #include <sys/vnode.h>
335331Samw #include <sys/fem.h>
345331Samw 
356600Sas200622 extern caller_context_t	smb_ct;
366600Sas200622 
376600Sas200622 static boolean_t	smb_fem_initialized = B_FALSE;
386600Sas200622 static fem_t		*smb_fcn_ops = NULL;
396600Sas200622 static fem_t		*smb_oplock_ops = NULL;
406600Sas200622 
416600Sas200622 /*
426600Sas200622  * Declarations for FCN (file change notification) FEM monitors
436600Sas200622  */
446600Sas200622 
456600Sas200622 void smb_fem_fcn_install(smb_node_t *);
466600Sas200622 void smb_fem_fcn_uninstall(smb_node_t *);
476600Sas200622 
486600Sas200622 static int smb_fem_fcn_create(femarg_t *, char *, vattr_t *, vcexcl_t, int,
495331Samw     vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *);
506600Sas200622 static int smb_fem_fcn_remove(femarg_t *, char *, cred_t *,
515331Samw     caller_context_t *, int);
526600Sas200622 static int smb_fem_fcn_rename(femarg_t *, char *, vnode_t *, char *,
535331Samw     cred_t *, caller_context_t *, int);
546600Sas200622 static int smb_fem_fcn_mkdir(femarg_t *, char *, vattr_t *, vnode_t **,
555331Samw     cred_t *, caller_context_t *, int, vsecattr_t *);
566600Sas200622 static int smb_fem_fcn_rmdir(femarg_t *, char *, vnode_t *, cred_t *,
575331Samw     caller_context_t *, int);
586600Sas200622 static int smb_fem_fcn_link(femarg_t *, vnode_t *, char *, cred_t *,
595331Samw     caller_context_t *, int);
606600Sas200622 static int smb_fem_fcn_symlink(femarg_t *, char *, vattr_t *,
615331Samw     char *, cred_t *, caller_context_t *, int);
625331Samw 
635331Samw static const fs_operation_def_t smb_fcn_tmpl[] = {
645331Samw 	VOPNAME_CREATE, { .femop_create = smb_fem_fcn_create },
655331Samw 	VOPNAME_REMOVE, {.femop_remove = smb_fem_fcn_remove},
665331Samw 	VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename},
675331Samw 	VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir},
685331Samw 	VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir},
695331Samw 	VOPNAME_LINK, {.femop_link = smb_fem_fcn_link},
705331Samw 	VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink},
715331Samw 	NULL, NULL
725331Samw };
735331Samw 
746600Sas200622 /*
756600Sas200622  * Declarations for oplock FEM monitors
766600Sas200622  */
776600Sas200622 
786600Sas200622 int smb_fem_oplock_install(smb_node_t *);
796600Sas200622 void smb_fem_oplock_uninstall(smb_node_t *);
806600Sas200622 
816600Sas200622 static int smb_fem_oplock_open(femarg_t *, int, cred_t *,
826600Sas200622     struct caller_context *);
836600Sas200622 static int smb_fem_oplock_read(femarg_t *, uio_t *, int, cred_t *,
846600Sas200622     struct caller_context *);
856600Sas200622 static int smb_fem_oplock_write(femarg_t *, uio_t *, int, cred_t *,
866600Sas200622     struct caller_context *);
876600Sas200622 static int smb_fem_oplock_setattr(femarg_t *, vattr_t *, int, cred_t *,
886600Sas200622     caller_context_t *);
896600Sas200622 static int smb_fem_oplock_rwlock(femarg_t *, int, caller_context_t *);
906600Sas200622 static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int,
916600Sas200622     offset_t, cred_t *, caller_context_t *);
926600Sas200622 static int smb_fem_oplock_setsecattr(femarg_t *, vsecattr_t *, int, cred_t *,
936600Sas200622     caller_context_t *);
946600Sas200622 static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *,
956600Sas200622     caller_context_t *);
966600Sas200622 
976600Sas200622 static const fs_operation_def_t smb_oplock_tmpl[] = {
986600Sas200622 	VOPNAME_OPEN,	{ .femop_open = smb_fem_oplock_open },
996600Sas200622 	VOPNAME_READ,	{ .femop_read = smb_fem_oplock_read },
1006600Sas200622 	VOPNAME_WRITE,	{ .femop_write = smb_fem_oplock_write },
1016600Sas200622 	VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr },
1026600Sas200622 	VOPNAME_RWLOCK, { .femop_rwlock = smb_fem_oplock_rwlock },
1036600Sas200622 	VOPNAME_SPACE,	{ .femop_space = smb_fem_oplock_space },
1046600Sas200622 	VOPNAME_SETSECATTR, { .femop_setsecattr = smb_fem_oplock_setsecattr },
1056600Sas200622 	VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent },
1066600Sas200622 	NULL, NULL
1076600Sas200622 };
1086600Sas200622 
1098934SJose.Borrego@Sun.COM static int smb_fem_oplock_break(femarg_t *, caller_context_t *);
1108934SJose.Borrego@Sun.COM 
1116139Sjb150015 /*
1126139Sjb150015  * smb_fem_init
1136139Sjb150015  *
1146139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
1156139Sjb150015  * thread makes the call.
1166139Sjb150015  */
1175331Samw int
1186139Sjb150015 smb_fem_init(void)
1195331Samw {
1206139Sjb150015 	int	rc = 0;
1216139Sjb150015 
1226139Sjb150015 	if (smb_fem_initialized)
1236139Sjb150015 		return (0);
1246139Sjb150015 
1256139Sjb150015 	rc = fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops);
1266139Sjb150015 	if (rc)
1276139Sjb150015 		return (rc);
1286139Sjb150015 
1296600Sas200622 	rc = fem_create("smb_oplock_ops", smb_oplock_tmpl,
1306600Sas200622 	    &smb_oplock_ops);
1316600Sas200622 
1326600Sas200622 	if (rc) {
1336600Sas200622 		fem_free(smb_fcn_ops);
1346600Sas200622 		smb_fcn_ops = NULL;
1356600Sas200622 		return (rc);
1366600Sas200622 	}
1376600Sas200622 
1386139Sjb150015 	smb_fem_initialized = B_TRUE;
1396139Sjb150015 
1406139Sjb150015 	return (0);
1415331Samw }
1425331Samw 
1436139Sjb150015 /*
1446139Sjb150015  * smb_fem_fini
1456139Sjb150015  *
1466139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
1476139Sjb150015  * thread makes the call.
1486139Sjb150015  */
1495331Samw void
1506139Sjb150015 smb_fem_fini(void)
1515331Samw {
1526139Sjb150015 	if (!smb_fem_initialized)
1536139Sjb150015 		return;
1546139Sjb150015 
1556139Sjb150015 	fem_free(smb_fcn_ops);
1566600Sas200622 	fem_free(smb_oplock_ops);
1576139Sjb150015 	smb_fcn_ops = NULL;
1586600Sas200622 	smb_oplock_ops = NULL;
1596139Sjb150015 	smb_fem_initialized = B_FALSE;
1605331Samw }
1615331Samw 
1625331Samw void
1635331Samw smb_fem_fcn_install(smb_node_t *node)
1645331Samw {
1656600Sas200622 	(void) fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ,
1666600Sas200622 	    (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
1675331Samw }
1685331Samw 
1695331Samw void
1705331Samw smb_fem_fcn_uninstall(smb_node_t *node)
1715331Samw {
1725331Samw 	(void) fem_uninstall(node->vp, smb_fcn_ops, (void *)node);
1735331Samw }
1745331Samw 
1756600Sas200622 int
1766600Sas200622 smb_fem_oplock_install(smb_node_t *node)
1776600Sas200622 {
1786600Sas200622 	return (fem_install(node->vp, smb_oplock_ops, (void *)node, OPARGUNIQ,
1796600Sas200622 	    (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release));
1806600Sas200622 }
1816600Sas200622 
1826600Sas200622 void
1836600Sas200622 smb_fem_oplock_uninstall(smb_node_t *node)
1846600Sas200622 {
1856600Sas200622 	(void) fem_uninstall(node->vp, smb_oplock_ops, (void *)node);
1866600Sas200622 }
1876600Sas200622 
1886600Sas200622 /*
1896600Sas200622  * FEM FCN monitors
1906600Sas200622  *
1916600Sas200622  * The FCN monitors intercept the respective VOP_* call regardless
1926600Sas200622  * of whether the call originates from CIFS, NFS, or a local process.
1936600Sas200622  */
1946600Sas200622 
1955331Samw /*
1965331Samw  * smb_fem_fcn_create()
1975331Samw  *
1985331Samw  * This monitor will catch only changes to VREG files and not to extended
1995331Samw  * attribute files.  This is fine because, for CIFS files, stream creates
2005331Samw  * should not trigger any file change notification on the VDIR directory
2015331Samw  * being monitored.  Creates of any other kind of extended attribute in
2025331Samw  * the directory will also not trigger any file change notification on the
2035331Samw  * VDIR directory being monitored.
2045331Samw  */
2055331Samw 
2066600Sas200622 static int
2075331Samw smb_fem_fcn_create(
2085331Samw     femarg_t *arg,
2095331Samw     char *name,
2105331Samw     vattr_t *vap,
2115331Samw     vcexcl_t excl,
2125331Samw     int mode,
2135331Samw     vnode_t **vpp,
2145331Samw     cred_t *cr,
2155331Samw     int flag,
2165331Samw     caller_context_t *ct,
2175331Samw     vsecattr_t *vsecp)
2185331Samw {
2195331Samw 	smb_node_t *dnode;
2205331Samw 	int error;
2215331Samw 
2225331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
2235331Samw 
2245331Samw 	ASSERT(dnode);
2255331Samw 
2265331Samw 	error = vnext_create(arg, name, vap, excl, mode, vpp, cr, flag,
2275331Samw 	    ct, vsecp);
2285331Samw 
2295331Samw 	if (error == 0)
2305331Samw 		smb_process_node_notify_change_queue(dnode);
2315331Samw 
2325331Samw 	return (error);
2335331Samw }
2345331Samw 
2355331Samw /*
2365331Samw  * smb_fem_fcn_remove()
2375331Samw  *
2385331Samw  * This monitor will catch only changes to VREG files and to not extended
2395331Samw  * attribute files.  This is fine because, for CIFS files, stream deletes
2405331Samw  * should not trigger any file change notification on the VDIR directory
2415331Samw  * being monitored.  Deletes of any other kind of extended attribute in
2425331Samw  * the directory will also not trigger any file change notification on the
2435331Samw  * VDIR directory being monitored.
2445331Samw  */
2455331Samw 
2466600Sas200622 static int
2475331Samw smb_fem_fcn_remove(
2485331Samw     femarg_t *arg,
2495331Samw     char *name,
2505331Samw     cred_t *cr,
2515331Samw     caller_context_t *ct,
2525331Samw     int flags)
2535331Samw {
2545331Samw 	smb_node_t *dnode;
2555331Samw 	int error;
2565331Samw 
2575331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
2585331Samw 
2595331Samw 	ASSERT(dnode);
2605331Samw 
2615331Samw 	error = vnext_remove(arg, name, cr, ct, flags);
2625331Samw 
2635331Samw 	if (error == 0)
2645331Samw 		smb_process_node_notify_change_queue(dnode);
2655331Samw 
2665331Samw 	return (error);
2675331Samw }
2685331Samw 
2696600Sas200622 static int
2705331Samw smb_fem_fcn_rename(
2715331Samw     femarg_t *arg,
2725331Samw     char *snm,
2735331Samw     vnode_t *tdvp,
2745331Samw     char *tnm,
2755331Samw     cred_t *cr,
2765331Samw     caller_context_t *ct,
2775331Samw     int flags)
2785331Samw {
2795331Samw 	smb_node_t *dnode;
2805331Samw 	int error;
2815331Samw 
2825331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
2835331Samw 
2845331Samw 	ASSERT(dnode);
2855331Samw 
2865331Samw 	error = vnext_rename(arg, snm, tdvp, tnm, cr, ct, flags);
2875331Samw 
2885331Samw 	if (error == 0)
2895331Samw 		smb_process_node_notify_change_queue(dnode);
2905331Samw 
2915331Samw 	return (error);
2925331Samw }
2935331Samw 
2946600Sas200622 static int
2955331Samw smb_fem_fcn_mkdir(
2965331Samw     femarg_t *arg,
2975331Samw     char *name,
2985331Samw     vattr_t *vap,
2995331Samw     vnode_t **vpp,
3005331Samw     cred_t *cr,
3015331Samw     caller_context_t *ct,
3025331Samw     int flags,
3035331Samw     vsecattr_t *vsecp)
3045331Samw {
3055331Samw 	smb_node_t *dnode;
3065331Samw 	int error;
3075331Samw 
3085331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
3095331Samw 
3105331Samw 	ASSERT(dnode);
3115331Samw 
3125331Samw 	error = vnext_mkdir(arg, name, vap, vpp, cr, ct, flags, vsecp);
3135331Samw 
3145331Samw 	if (error == 0)
3155331Samw 		smb_process_node_notify_change_queue(dnode);
3165331Samw 
3175331Samw 	return (error);
3185331Samw }
3195331Samw 
3206600Sas200622 static int
3215331Samw smb_fem_fcn_rmdir(
3225331Samw     femarg_t *arg,
3235331Samw     char *name,
3245331Samw     vnode_t *cdir,
3255331Samw     cred_t *cr,
3265331Samw     caller_context_t *ct,
3275331Samw     int flags)
3285331Samw {
3295331Samw 	smb_node_t *dnode;
3305331Samw 	int error;
3315331Samw 
3325331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
3335331Samw 
3345331Samw 	ASSERT(dnode);
3355331Samw 
3365331Samw 	error = vnext_rmdir(arg, name, cdir, cr, ct, flags);
3375331Samw 
3385331Samw 	if (error == 0)
3395331Samw 		smb_process_node_notify_change_queue(dnode);
3405331Samw 
3415331Samw 	return (error);
3425331Samw }
3435331Samw 
3446600Sas200622 static int
3455331Samw smb_fem_fcn_link(
3465331Samw     femarg_t *arg,
3475331Samw     vnode_t *svp,
3485331Samw     char *tnm,
3495331Samw     cred_t *cr,
3505331Samw     caller_context_t *ct,
3515331Samw     int flags)
3525331Samw {
3535331Samw 	smb_node_t *dnode;
3545331Samw 	int error;
3555331Samw 
3565331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
3575331Samw 
3585331Samw 	ASSERT(dnode);
3595331Samw 
3605331Samw 	error = vnext_link(arg, svp, tnm, cr, ct, flags);
3615331Samw 
3625331Samw 	if (error == 0)
3635331Samw 		smb_process_node_notify_change_queue(dnode);
3645331Samw 
3655331Samw 	return (error);
3665331Samw }
3675331Samw 
3686600Sas200622 static int
3695331Samw smb_fem_fcn_symlink(
3705331Samw     femarg_t *arg,
3715331Samw     char *linkname,
3725331Samw     vattr_t *vap,
3735331Samw     char *target,
3745331Samw     cred_t *cr,
3755331Samw     caller_context_t *ct,
3765331Samw     int flags)
3775331Samw {
3785331Samw 	smb_node_t *dnode;
3795331Samw 	int error;
3805331Samw 
3815331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
3825331Samw 
3835331Samw 	ASSERT(dnode);
3845331Samw 
3855331Samw 	error = vnext_symlink(arg, linkname, vap, target, cr, ct, flags);
3865331Samw 
3875331Samw 	if (error == 0)
3885331Samw 		smb_process_node_notify_change_queue(dnode);
3895331Samw 
3905331Samw 	return (error);
3915331Samw }
3926600Sas200622 
3936600Sas200622 /*
3946600Sas200622  * FEM oplock monitors
3956600Sas200622  *
3966600Sas200622  * The monitors below are not intended to intercept CIFS calls.
3976600Sas200622  * CIFS higher-level routines will break oplocks as needed prior
3986600Sas200622  * to getting to the VFS layer.
3996600Sas200622  */
4006600Sas200622 static int
4016600Sas200622 smb_fem_oplock_open(
4028934SJose.Borrego@Sun.COM     femarg_t		*arg,
4038934SJose.Borrego@Sun.COM     int			mode,
4048934SJose.Borrego@Sun.COM     cred_t		*cr,
4058934SJose.Borrego@Sun.COM     caller_context_t	*ct)
4066600Sas200622 {
4078934SJose.Borrego@Sun.COM 	int	rc;
4086600Sas200622 
4098934SJose.Borrego@Sun.COM 	rc = smb_fem_oplock_break(arg, ct);
4108934SJose.Borrego@Sun.COM 	if (rc == 0)
4118934SJose.Borrego@Sun.COM 		rc = vnext_open(arg, mode, cr, ct);
4128934SJose.Borrego@Sun.COM 	return (rc);
4136600Sas200622 }
4146600Sas200622 
4156600Sas200622 /*
4166600Sas200622  * Should normally be hit only via NFSv2/v3.  All other accesses
4176600Sas200622  * (CIFS/NFS/local) should call VOP_OPEN first.
4186600Sas200622  */
4196600Sas200622 
4206600Sas200622 static int
4216600Sas200622 smb_fem_oplock_read(
4228934SJose.Borrego@Sun.COM     femarg_t		*arg,
4238934SJose.Borrego@Sun.COM     uio_t		*uiop,
4248934SJose.Borrego@Sun.COM     int			ioflag,
4258934SJose.Borrego@Sun.COM     cred_t		*cr,
4268934SJose.Borrego@Sun.COM     caller_context_t	*ct)
4276600Sas200622 {
4288934SJose.Borrego@Sun.COM 	int	rc;
4296600Sas200622 
4308934SJose.Borrego@Sun.COM 	rc = smb_fem_oplock_break(arg, ct);
4318934SJose.Borrego@Sun.COM 	if (rc == 0)
4328934SJose.Borrego@Sun.COM 		rc = vnext_read(arg, uiop, ioflag, cr, ct);
4338934SJose.Borrego@Sun.COM 	return (rc);
4346600Sas200622 }
4356600Sas200622 
4366600Sas200622 /*
4376600Sas200622  * Should normally be hit only via NFSv2/v3.  All other accesses
4386600Sas200622  * (CIFS/NFS/local) should call VOP_OPEN first.
4396600Sas200622  */
4406600Sas200622 
4416600Sas200622 static int
4426600Sas200622 smb_fem_oplock_write(
4438934SJose.Borrego@Sun.COM     femarg_t		*arg,
4448934SJose.Borrego@Sun.COM     uio_t		*uiop,
4458934SJose.Borrego@Sun.COM     int			ioflag,
4468934SJose.Borrego@Sun.COM     cred_t		*cr,
4478934SJose.Borrego@Sun.COM     caller_context_t	*ct)
4486600Sas200622 {
4498934SJose.Borrego@Sun.COM 	int	rc;
4506600Sas200622 
4518934SJose.Borrego@Sun.COM 	rc = smb_fem_oplock_break(arg, ct);
4528934SJose.Borrego@Sun.COM 	if (rc == 0)
4538934SJose.Borrego@Sun.COM 		rc = vnext_write(arg, uiop, ioflag, cr, ct);
4548934SJose.Borrego@Sun.COM 	return (rc);
4556600Sas200622 }
4566600Sas200622 
4576600Sas200622 static int
4586600Sas200622 smb_fem_oplock_setattr(
4598934SJose.Borrego@Sun.COM     femarg_t		*arg,
4608934SJose.Borrego@Sun.COM     vattr_t		*vap,
4618934SJose.Borrego@Sun.COM     int			flags,
4628934SJose.Borrego@Sun.COM     cred_t		*cr,
4638934SJose.Borrego@Sun.COM     caller_context_t	*ct)
4646600Sas200622 {
4658934SJose.Borrego@Sun.COM 	int	rc;
4666600Sas200622 
4678934SJose.Borrego@Sun.COM 	rc = smb_fem_oplock_break(arg, ct);
4688934SJose.Borrego@Sun.COM 	if (rc == 0)
4698934SJose.Borrego@Sun.COM 		rc = vnext_setattr(arg, vap, flags, cr, ct);
4708934SJose.Borrego@Sun.COM 	return (rc);
4716600Sas200622 }
4726600Sas200622 
4736600Sas200622 static int
4746600Sas200622 smb_fem_oplock_rwlock(
4758934SJose.Borrego@Sun.COM     femarg_t		*arg,
4768934SJose.Borrego@Sun.COM     int			write_lock,
4778934SJose.Borrego@Sun.COM     caller_context_t	*ct)
4786600Sas200622 {
4796600Sas200622 	if (write_lock) {
4808934SJose.Borrego@Sun.COM 		int	rc;
4818934SJose.Borrego@Sun.COM 
4828934SJose.Borrego@Sun.COM 		rc = smb_fem_oplock_break(arg, ct);
4838934SJose.Borrego@Sun.COM 		if (rc != 0)
4848934SJose.Borrego@Sun.COM 			return (rc);
4856600Sas200622 	}
4866600Sas200622 	return (vnext_rwlock(arg, write_lock, ct));
4876600Sas200622 }
4886600Sas200622 
4896600Sas200622 static int
4906600Sas200622 smb_fem_oplock_space(
4918934SJose.Borrego@Sun.COM     femarg_t		*arg,
4928934SJose.Borrego@Sun.COM     int			cmd,
4938934SJose.Borrego@Sun.COM     flock64_t		*bfp,
4948934SJose.Borrego@Sun.COM     int			flag,
4958934SJose.Borrego@Sun.COM     offset_t		offset,
4968934SJose.Borrego@Sun.COM     cred_t		*cr,
4978934SJose.Borrego@Sun.COM     caller_context_t	*ct)
4986600Sas200622 {
4998934SJose.Borrego@Sun.COM 	int	rc;
5006600Sas200622 
5018934SJose.Borrego@Sun.COM 	rc = smb_fem_oplock_break(arg, ct);
5028934SJose.Borrego@Sun.COM 	if (rc == 0)
5038934SJose.Borrego@Sun.COM 		rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct);
5048934SJose.Borrego@Sun.COM 	return (rc);
5056600Sas200622 }
5066600Sas200622 
5076600Sas200622 static int
5086600Sas200622 smb_fem_oplock_setsecattr(
5098934SJose.Borrego@Sun.COM     femarg_t		*arg,
5108934SJose.Borrego@Sun.COM     vsecattr_t		*vsap,
5118934SJose.Borrego@Sun.COM     int			flag,
5128934SJose.Borrego@Sun.COM     cred_t		*cr,
5138934SJose.Borrego@Sun.COM     caller_context_t	*ct)
5146600Sas200622 {
5158934SJose.Borrego@Sun.COM 	int	rc;
5166600Sas200622 
5178934SJose.Borrego@Sun.COM 	rc = smb_fem_oplock_break(arg, ct);
5188934SJose.Borrego@Sun.COM 	if (rc == 0)
5198934SJose.Borrego@Sun.COM 		rc = vnext_setsecattr(arg, vsap, flag, cr, ct);
5208934SJose.Borrego@Sun.COM 	return (rc);
5216600Sas200622 }
5226600Sas200622 
5236600Sas200622 /*
5246600Sas200622  * smb_fem_oplock_vnevent()
5256600Sas200622  *
5266600Sas200622  * To intercept NFS and local renames and removes in order to break any
5276600Sas200622  * existing oplock prior to the operation.
5286600Sas200622  *
5296600Sas200622  * Note: Currently, this monitor is traversed only when an FS is mounted
5306600Sas200622  * non-nbmand.  (When the FS is mounted nbmand, share reservation checking
5316600Sas200622  * will detect a share violation and return an error prior to the VOP layer
5326600Sas200622  * being reached.)  Thus, for nbmand NFS and local renames and removes,
5336600Sas200622  * an existing oplock is never broken prior to share checking (contrary to
5346600Sas200622  * how it is with intra-CIFS remove and rename requests).
5356600Sas200622  */
5366600Sas200622 
5376600Sas200622 static int
5386600Sas200622 smb_fem_oplock_vnevent(
5398934SJose.Borrego@Sun.COM     femarg_t		*arg,
5408934SJose.Borrego@Sun.COM     vnevent_t		vnevent,
5418934SJose.Borrego@Sun.COM     vnode_t		*dvp,
5428934SJose.Borrego@Sun.COM     char		*name,
5438934SJose.Borrego@Sun.COM     caller_context_t	*ct)
5446600Sas200622 {
5458934SJose.Borrego@Sun.COM 	int	rc;
5468934SJose.Borrego@Sun.COM 
5476600Sas200622 	switch (vnevent) {
5486600Sas200622 	case VE_REMOVE:
5496600Sas200622 	case VE_RENAME_DEST:
5506600Sas200622 	case VE_RENAME_SRC:
5518934SJose.Borrego@Sun.COM 		rc = smb_fem_oplock_break(arg, ct);
5528934SJose.Borrego@Sun.COM 		if (rc != 0)
5538934SJose.Borrego@Sun.COM 			return (rc);
5546600Sas200622 		break;
5556600Sas200622 
5566600Sas200622 	default:
5576600Sas200622 		break;
5586600Sas200622 	}
5596600Sas200622 	return (vnext_vnevent(arg, vnevent, dvp, name, ct));
5606600Sas200622 }
5618934SJose.Borrego@Sun.COM 
5628934SJose.Borrego@Sun.COM static int
5638934SJose.Borrego@Sun.COM smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct)
5648934SJose.Borrego@Sun.COM {
5658934SJose.Borrego@Sun.COM 	smb_node_t	*node;
5668934SJose.Borrego@Sun.COM 	int		rc;
5678934SJose.Borrego@Sun.COM 
5688934SJose.Borrego@Sun.COM 	node = (smb_node_t *)((arg)->fa_fnode->fn_available);
5698934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
5708934SJose.Borrego@Sun.COM 
5718934SJose.Borrego@Sun.COM 	if (ct == NULL) {
5729021Samw@Sun.COM 		(void) smb_oplock_break(node, NULL, B_FALSE);
5738934SJose.Borrego@Sun.COM 		return (0);
5748934SJose.Borrego@Sun.COM 	}
5758934SJose.Borrego@Sun.COM 
5768934SJose.Borrego@Sun.COM 	if (ct->cc_caller_id == smb_ct.cc_caller_id)
5778934SJose.Borrego@Sun.COM 		return (0);
5788934SJose.Borrego@Sun.COM 
5798934SJose.Borrego@Sun.COM 	if (ct->cc_flags & CC_DONTBLOCK) {
5809021Samw@Sun.COM 		if (smb_oplock_break(node, NULL, B_TRUE))
5818934SJose.Borrego@Sun.COM 			return (0);
5828934SJose.Borrego@Sun.COM 		ct->cc_flags |= CC_WOULDBLOCK;
5838934SJose.Borrego@Sun.COM 		rc = EAGAIN;
5848934SJose.Borrego@Sun.COM 	} else {
5859021Samw@Sun.COM 		(void) smb_oplock_break(node, NULL, B_FALSE);
5868934SJose.Borrego@Sun.COM 		rc = 0;
5878934SJose.Borrego@Sun.COM 	}
5888934SJose.Borrego@Sun.COM 	return (rc);
5898934SJose.Borrego@Sun.COM }
590