xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_fem.c (revision 12890:16985853e3aa)
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 /*
22*12890SJoyce.McIntosh@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235331Samw  */
245331Samw 
2510966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
266600Sas200622 #include <smbsrv/smb_fsops.h>
275331Samw #include <sys/sdt.h>
286600Sas200622 #include <sys/fcntl.h>
295331Samw #include <sys/vfs.h>
305331Samw #include <sys/vfs_opreg.h>
315331Samw #include <sys/vnode.h>
325331Samw #include <sys/fem.h>
335331Samw 
346600Sas200622 extern caller_context_t	smb_ct;
356600Sas200622 
366600Sas200622 static boolean_t	smb_fem_initialized = B_FALSE;
376600Sas200622 static fem_t		*smb_fcn_ops = NULL;
386600Sas200622 static fem_t		*smb_oplock_ops = NULL;
396600Sas200622 
406600Sas200622 /*
416600Sas200622  * Declarations for FCN (file change notification) FEM monitors
426600Sas200622  */
436600Sas200622 
446600Sas200622 void smb_fem_fcn_install(smb_node_t *);
456600Sas200622 void smb_fem_fcn_uninstall(smb_node_t *);
466600Sas200622 
476600Sas200622 static int smb_fem_fcn_create(femarg_t *, char *, vattr_t *, vcexcl_t, int,
485331Samw     vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *);
496600Sas200622 static int smb_fem_fcn_remove(femarg_t *, char *, cred_t *,
505331Samw     caller_context_t *, int);
516600Sas200622 static int smb_fem_fcn_rename(femarg_t *, char *, vnode_t *, char *,
525331Samw     cred_t *, caller_context_t *, int);
536600Sas200622 static int smb_fem_fcn_mkdir(femarg_t *, char *, vattr_t *, vnode_t **,
545331Samw     cred_t *, caller_context_t *, int, vsecattr_t *);
556600Sas200622 static int smb_fem_fcn_rmdir(femarg_t *, char *, vnode_t *, cred_t *,
565331Samw     caller_context_t *, int);
576600Sas200622 static int smb_fem_fcn_link(femarg_t *, vnode_t *, char *, cred_t *,
585331Samw     caller_context_t *, int);
596600Sas200622 static int smb_fem_fcn_symlink(femarg_t *, char *, vattr_t *,
605331Samw     char *, cred_t *, caller_context_t *, int);
615331Samw 
625331Samw static const fs_operation_def_t smb_fcn_tmpl[] = {
635331Samw 	VOPNAME_CREATE, { .femop_create = smb_fem_fcn_create },
645331Samw 	VOPNAME_REMOVE, {.femop_remove = smb_fem_fcn_remove},
655331Samw 	VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename},
665331Samw 	VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir},
675331Samw 	VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir},
685331Samw 	VOPNAME_LINK, {.femop_link = smb_fem_fcn_link},
695331Samw 	VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink},
705331Samw 	NULL, NULL
715331Samw };
725331Samw 
736600Sas200622 /*
746600Sas200622  * Declarations for oplock FEM monitors
756600Sas200622  */
766600Sas200622 
776600Sas200622 int smb_fem_oplock_install(smb_node_t *);
78*12890SJoyce.McIntosh@Sun.COM int smb_fem_oplock_uninstall(smb_node_t *);
796600Sas200622 
806600Sas200622 static int smb_fem_oplock_open(femarg_t *, int, cred_t *,
816600Sas200622     struct caller_context *);
826600Sas200622 static int smb_fem_oplock_read(femarg_t *, uio_t *, int, cred_t *,
836600Sas200622     struct caller_context *);
846600Sas200622 static int smb_fem_oplock_write(femarg_t *, uio_t *, int, cred_t *,
856600Sas200622     struct caller_context *);
866600Sas200622 static int smb_fem_oplock_setattr(femarg_t *, vattr_t *, int, cred_t *,
876600Sas200622     caller_context_t *);
886600Sas200622 static int smb_fem_oplock_rwlock(femarg_t *, int, caller_context_t *);
896600Sas200622 static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int,
906600Sas200622     offset_t, cred_t *, caller_context_t *);
916600Sas200622 static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *,
926600Sas200622     caller_context_t *);
936600Sas200622 
946600Sas200622 static const fs_operation_def_t smb_oplock_tmpl[] = {
956600Sas200622 	VOPNAME_OPEN,	{ .femop_open = smb_fem_oplock_open },
966600Sas200622 	VOPNAME_READ,	{ .femop_read = smb_fem_oplock_read },
976600Sas200622 	VOPNAME_WRITE,	{ .femop_write = smb_fem_oplock_write },
986600Sas200622 	VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr },
996600Sas200622 	VOPNAME_RWLOCK, { .femop_rwlock = smb_fem_oplock_rwlock },
1006600Sas200622 	VOPNAME_SPACE,	{ .femop_space = smb_fem_oplock_space },
1016600Sas200622 	VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent },
1026600Sas200622 	NULL, NULL
1036600Sas200622 };
1046600Sas200622 
105*12890SJoyce.McIntosh@Sun.COM static int smb_fem_oplock_break(femarg_t *, caller_context_t *, uint32_t);
1068934SJose.Borrego@Sun.COM 
1076139Sjb150015 /*
1086139Sjb150015  * smb_fem_init
1096139Sjb150015  *
1106139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
1116139Sjb150015  * thread makes the call.
1126139Sjb150015  */
1135331Samw int
smb_fem_init(void)1146139Sjb150015 smb_fem_init(void)
1155331Samw {
1166139Sjb150015 	int	rc = 0;
1176139Sjb150015 
1186139Sjb150015 	if (smb_fem_initialized)
1196139Sjb150015 		return (0);
1206139Sjb150015 
1216139Sjb150015 	rc = fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops);
1226139Sjb150015 	if (rc)
1236139Sjb150015 		return (rc);
1246139Sjb150015 
1256600Sas200622 	rc = fem_create("smb_oplock_ops", smb_oplock_tmpl,
1266600Sas200622 	    &smb_oplock_ops);
1276600Sas200622 
1286600Sas200622 	if (rc) {
1296600Sas200622 		fem_free(smb_fcn_ops);
1306600Sas200622 		smb_fcn_ops = NULL;
1316600Sas200622 		return (rc);
1326600Sas200622 	}
1336600Sas200622 
1346139Sjb150015 	smb_fem_initialized = B_TRUE;
1356139Sjb150015 
1366139Sjb150015 	return (0);
1375331Samw }
1385331Samw 
1396139Sjb150015 /*
1406139Sjb150015  * smb_fem_fini
1416139Sjb150015  *
1426139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
1436139Sjb150015  * thread makes the call.
1446139Sjb150015  */
1455331Samw void
smb_fem_fini(void)1466139Sjb150015 smb_fem_fini(void)
1475331Samw {
1486139Sjb150015 	if (!smb_fem_initialized)
1496139Sjb150015 		return;
1506139Sjb150015 
1516139Sjb150015 	fem_free(smb_fcn_ops);
1526600Sas200622 	fem_free(smb_oplock_ops);
1536139Sjb150015 	smb_fcn_ops = NULL;
1546600Sas200622 	smb_oplock_ops = NULL;
1556139Sjb150015 	smb_fem_initialized = B_FALSE;
1565331Samw }
1575331Samw 
1585331Samw void
smb_fem_fcn_install(smb_node_t * node)1595331Samw smb_fem_fcn_install(smb_node_t *node)
1605331Samw {
1616600Sas200622 	(void) fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ,
1626600Sas200622 	    (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
1635331Samw }
1645331Samw 
1655331Samw void
smb_fem_fcn_uninstall(smb_node_t * node)1665331Samw smb_fem_fcn_uninstall(smb_node_t *node)
1675331Samw {
1685331Samw 	(void) fem_uninstall(node->vp, smb_fcn_ops, (void *)node);
1695331Samw }
1705331Samw 
1716600Sas200622 int
smb_fem_oplock_install(smb_node_t * node)1726600Sas200622 smb_fem_oplock_install(smb_node_t *node)
1736600Sas200622 {
1746600Sas200622 	return (fem_install(node->vp, smb_oplock_ops, (void *)node, OPARGUNIQ,
1756600Sas200622 	    (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release));
1766600Sas200622 }
1776600Sas200622 
178*12890SJoyce.McIntosh@Sun.COM int
smb_fem_oplock_uninstall(smb_node_t * node)1796600Sas200622 smb_fem_oplock_uninstall(smb_node_t *node)
1806600Sas200622 {
181*12890SJoyce.McIntosh@Sun.COM 	return (fem_uninstall(node->vp, smb_oplock_ops, (void *)node));
1826600Sas200622 }
1836600Sas200622 
1846600Sas200622 /*
1856600Sas200622  * FEM FCN monitors
1866600Sas200622  *
1876600Sas200622  * The FCN monitors intercept the respective VOP_* call regardless
1886600Sas200622  * of whether the call originates from CIFS, NFS, or a local process.
1896600Sas200622  */
1906600Sas200622 
1915331Samw /*
1925331Samw  * smb_fem_fcn_create()
1935331Samw  *
1945331Samw  * This monitor will catch only changes to VREG files and not to extended
1955331Samw  * attribute files.  This is fine because, for CIFS files, stream creates
1965331Samw  * should not trigger any file change notification on the VDIR directory
1975331Samw  * being monitored.  Creates of any other kind of extended attribute in
1985331Samw  * the directory will also not trigger any file change notification on the
1995331Samw  * VDIR directory being monitored.
2005331Samw  */
2015331Samw 
2026600Sas200622 static int
smb_fem_fcn_create(femarg_t * arg,char * name,vattr_t * vap,vcexcl_t excl,int mode,vnode_t ** vpp,cred_t * cr,int flag,caller_context_t * ct,vsecattr_t * vsecp)2035331Samw smb_fem_fcn_create(
2045331Samw     femarg_t *arg,
2055331Samw     char *name,
2065331Samw     vattr_t *vap,
2075331Samw     vcexcl_t excl,
2085331Samw     int mode,
2095331Samw     vnode_t **vpp,
2105331Samw     cred_t *cr,
2115331Samw     int flag,
2125331Samw     caller_context_t *ct,
2135331Samw     vsecattr_t *vsecp)
2145331Samw {
2155331Samw 	smb_node_t *dnode;
2165331Samw 	int error;
2175331Samw 
2185331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
2195331Samw 
2205331Samw 	ASSERT(dnode);
2215331Samw 
2225331Samw 	error = vnext_create(arg, name, vap, excl, mode, vpp, cr, flag,
2235331Samw 	    ct, vsecp);
2245331Samw 
2255331Samw 	if (error == 0)
22611963SAfshin.Ardakani@Sun.COM 		smb_node_notify_change(dnode);
2275331Samw 
2285331Samw 	return (error);
2295331Samw }
2305331Samw 
2315331Samw /*
2325331Samw  * smb_fem_fcn_remove()
2335331Samw  *
2345331Samw  * This monitor will catch only changes to VREG files and to not extended
2355331Samw  * attribute files.  This is fine because, for CIFS files, stream deletes
2365331Samw  * should not trigger any file change notification on the VDIR directory
2375331Samw  * being monitored.  Deletes of any other kind of extended attribute in
2385331Samw  * the directory will also not trigger any file change notification on the
2395331Samw  * VDIR directory being monitored.
2405331Samw  */
2415331Samw 
2426600Sas200622 static int
smb_fem_fcn_remove(femarg_t * arg,char * name,cred_t * cr,caller_context_t * ct,int flags)2435331Samw smb_fem_fcn_remove(
2445331Samw     femarg_t *arg,
2455331Samw     char *name,
2465331Samw     cred_t *cr,
2475331Samw     caller_context_t *ct,
2485331Samw     int flags)
2495331Samw {
2505331Samw 	smb_node_t *dnode;
2515331Samw 	int error;
2525331Samw 
2535331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
2545331Samw 
2555331Samw 	ASSERT(dnode);
2565331Samw 
2575331Samw 	error = vnext_remove(arg, name, cr, ct, flags);
2585331Samw 
2595331Samw 	if (error == 0)
26011963SAfshin.Ardakani@Sun.COM 		smb_node_notify_change(dnode);
2615331Samw 
2625331Samw 	return (error);
2635331Samw }
2645331Samw 
2656600Sas200622 static int
smb_fem_fcn_rename(femarg_t * arg,char * snm,vnode_t * tdvp,char * tnm,cred_t * cr,caller_context_t * ct,int flags)2665331Samw smb_fem_fcn_rename(
2675331Samw     femarg_t *arg,
2685331Samw     char *snm,
2695331Samw     vnode_t *tdvp,
2705331Samw     char *tnm,
2715331Samw     cred_t *cr,
2725331Samw     caller_context_t *ct,
2735331Samw     int flags)
2745331Samw {
2755331Samw 	smb_node_t *dnode;
2765331Samw 	int error;
2775331Samw 
2785331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
2795331Samw 
2805331Samw 	ASSERT(dnode);
2815331Samw 
2825331Samw 	error = vnext_rename(arg, snm, tdvp, tnm, cr, ct, flags);
2835331Samw 
2845331Samw 	if (error == 0)
28511963SAfshin.Ardakani@Sun.COM 		smb_node_notify_change(dnode);
2865331Samw 
2875331Samw 	return (error);
2885331Samw }
2895331Samw 
2906600Sas200622 static int
smb_fem_fcn_mkdir(femarg_t * arg,char * name,vattr_t * vap,vnode_t ** vpp,cred_t * cr,caller_context_t * ct,int flags,vsecattr_t * vsecp)2915331Samw smb_fem_fcn_mkdir(
2925331Samw     femarg_t *arg,
2935331Samw     char *name,
2945331Samw     vattr_t *vap,
2955331Samw     vnode_t **vpp,
2965331Samw     cred_t *cr,
2975331Samw     caller_context_t *ct,
2985331Samw     int flags,
2995331Samw     vsecattr_t *vsecp)
3005331Samw {
3015331Samw 	smb_node_t *dnode;
3025331Samw 	int error;
3035331Samw 
3045331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
3055331Samw 
3065331Samw 	ASSERT(dnode);
3075331Samw 
3085331Samw 	error = vnext_mkdir(arg, name, vap, vpp, cr, ct, flags, vsecp);
3095331Samw 
3105331Samw 	if (error == 0)
31111963SAfshin.Ardakani@Sun.COM 		smb_node_notify_change(dnode);
3125331Samw 
3135331Samw 	return (error);
3145331Samw }
3155331Samw 
3166600Sas200622 static int
smb_fem_fcn_rmdir(femarg_t * arg,char * name,vnode_t * cdir,cred_t * cr,caller_context_t * ct,int flags)3175331Samw smb_fem_fcn_rmdir(
3185331Samw     femarg_t *arg,
3195331Samw     char *name,
3205331Samw     vnode_t *cdir,
3215331Samw     cred_t *cr,
3225331Samw     caller_context_t *ct,
3235331Samw     int flags)
3245331Samw {
3255331Samw 	smb_node_t *dnode;
3265331Samw 	int error;
3275331Samw 
3285331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
3295331Samw 
3305331Samw 	ASSERT(dnode);
3315331Samw 
3325331Samw 	error = vnext_rmdir(arg, name, cdir, cr, ct, flags);
3335331Samw 
3345331Samw 	if (error == 0)
33511963SAfshin.Ardakani@Sun.COM 		smb_node_notify_change(dnode);
3365331Samw 
3375331Samw 	return (error);
3385331Samw }
3395331Samw 
3406600Sas200622 static int
smb_fem_fcn_link(femarg_t * arg,vnode_t * svp,char * tnm,cred_t * cr,caller_context_t * ct,int flags)3415331Samw smb_fem_fcn_link(
3425331Samw     femarg_t *arg,
3435331Samw     vnode_t *svp,
3445331Samw     char *tnm,
3455331Samw     cred_t *cr,
3465331Samw     caller_context_t *ct,
3475331Samw     int flags)
3485331Samw {
3495331Samw 	smb_node_t *dnode;
3505331Samw 	int error;
3515331Samw 
3525331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
3535331Samw 
3545331Samw 	ASSERT(dnode);
3555331Samw 
3565331Samw 	error = vnext_link(arg, svp, tnm, cr, ct, flags);
3575331Samw 
3585331Samw 	if (error == 0)
35911963SAfshin.Ardakani@Sun.COM 		smb_node_notify_change(dnode);
3605331Samw 
3615331Samw 	return (error);
3625331Samw }
3635331Samw 
3646600Sas200622 static int
smb_fem_fcn_symlink(femarg_t * arg,char * linkname,vattr_t * vap,char * target,cred_t * cr,caller_context_t * ct,int flags)3655331Samw smb_fem_fcn_symlink(
3665331Samw     femarg_t *arg,
3675331Samw     char *linkname,
3685331Samw     vattr_t *vap,
3695331Samw     char *target,
3705331Samw     cred_t *cr,
3715331Samw     caller_context_t *ct,
3725331Samw     int flags)
3735331Samw {
3745331Samw 	smb_node_t *dnode;
3755331Samw 	int error;
3765331Samw 
3775331Samw 	dnode = (smb_node_t *)arg->fa_fnode->fn_available;
3785331Samw 
3795331Samw 	ASSERT(dnode);
3805331Samw 
3815331Samw 	error = vnext_symlink(arg, linkname, vap, target, cr, ct, flags);
3825331Samw 
3835331Samw 	if (error == 0)
38411963SAfshin.Ardakani@Sun.COM 		smb_node_notify_change(dnode);
3855331Samw 
3865331Samw 	return (error);
3875331Samw }
3886600Sas200622 
3896600Sas200622 /*
3906600Sas200622  * FEM oplock monitors
3916600Sas200622  *
3926600Sas200622  * The monitors below are not intended to intercept CIFS calls.
3936600Sas200622  * CIFS higher-level routines will break oplocks as needed prior
3946600Sas200622  * to getting to the VFS layer.
3956600Sas200622  */
3966600Sas200622 static int
smb_fem_oplock_open(femarg_t * arg,int mode,cred_t * cr,caller_context_t * ct)3976600Sas200622 smb_fem_oplock_open(
3988934SJose.Borrego@Sun.COM     femarg_t		*arg,
3998934SJose.Borrego@Sun.COM     int			mode,
4008934SJose.Borrego@Sun.COM     cred_t		*cr,
4018934SJose.Borrego@Sun.COM     caller_context_t	*ct)
4026600Sas200622 {
403*12890SJoyce.McIntosh@Sun.COM 	int		rc;
404*12890SJoyce.McIntosh@Sun.COM 	uint32_t	flags;
4056600Sas200622 
406*12890SJoyce.McIntosh@Sun.COM 	if (mode & (FWRITE|FTRUNC))
407*12890SJoyce.McIntosh@Sun.COM 		flags = SMB_OPLOCK_BREAK_TO_NONE;
408*12890SJoyce.McIntosh@Sun.COM 	else
409*12890SJoyce.McIntosh@Sun.COM 		flags = SMB_OPLOCK_BREAK_TO_LEVEL_II;
410*12890SJoyce.McIntosh@Sun.COM 
411*12890SJoyce.McIntosh@Sun.COM 	rc = smb_fem_oplock_break(arg, ct, flags);
4128934SJose.Borrego@Sun.COM 	if (rc == 0)
4138934SJose.Borrego@Sun.COM 		rc = vnext_open(arg, mode, cr, ct);
4148934SJose.Borrego@Sun.COM 	return (rc);
4156600Sas200622 }
4166600Sas200622 
4176600Sas200622 /*
4186600Sas200622  * Should normally be hit only via NFSv2/v3.  All other accesses
4196600Sas200622  * (CIFS/NFS/local) should call VOP_OPEN first.
4206600Sas200622  */
4216600Sas200622 
4226600Sas200622 static int
smb_fem_oplock_read(femarg_t * arg,uio_t * uiop,int ioflag,cred_t * cr,caller_context_t * ct)4236600Sas200622 smb_fem_oplock_read(
4248934SJose.Borrego@Sun.COM     femarg_t		*arg,
4258934SJose.Borrego@Sun.COM     uio_t		*uiop,
4268934SJose.Borrego@Sun.COM     int			ioflag,
4278934SJose.Borrego@Sun.COM     cred_t		*cr,
4288934SJose.Borrego@Sun.COM     caller_context_t	*ct)
4296600Sas200622 {
4308934SJose.Borrego@Sun.COM 	int	rc;
4316600Sas200622 
432*12890SJoyce.McIntosh@Sun.COM 	rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_LEVEL_II);
4338934SJose.Borrego@Sun.COM 	if (rc == 0)
4348934SJose.Borrego@Sun.COM 		rc = vnext_read(arg, uiop, ioflag, cr, ct);
4358934SJose.Borrego@Sun.COM 	return (rc);
4366600Sas200622 }
4376600Sas200622 
4386600Sas200622 /*
4396600Sas200622  * Should normally be hit only via NFSv2/v3.  All other accesses
4406600Sas200622  * (CIFS/NFS/local) should call VOP_OPEN first.
4416600Sas200622  */
4426600Sas200622 
4436600Sas200622 static int
smb_fem_oplock_write(femarg_t * arg,uio_t * uiop,int ioflag,cred_t * cr,caller_context_t * ct)4446600Sas200622 smb_fem_oplock_write(
4458934SJose.Borrego@Sun.COM     femarg_t		*arg,
4468934SJose.Borrego@Sun.COM     uio_t		*uiop,
4478934SJose.Borrego@Sun.COM     int			ioflag,
4488934SJose.Borrego@Sun.COM     cred_t		*cr,
4498934SJose.Borrego@Sun.COM     caller_context_t	*ct)
4506600Sas200622 {
4518934SJose.Borrego@Sun.COM 	int	rc;
4526600Sas200622 
453*12890SJoyce.McIntosh@Sun.COM 	rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
4548934SJose.Borrego@Sun.COM 	if (rc == 0)
4558934SJose.Borrego@Sun.COM 		rc = vnext_write(arg, uiop, ioflag, cr, ct);
4568934SJose.Borrego@Sun.COM 	return (rc);
4576600Sas200622 }
4586600Sas200622 
4596600Sas200622 static int
smb_fem_oplock_setattr(femarg_t * arg,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)4606600Sas200622 smb_fem_oplock_setattr(
4618934SJose.Borrego@Sun.COM     femarg_t		*arg,
4628934SJose.Borrego@Sun.COM     vattr_t		*vap,
4638934SJose.Borrego@Sun.COM     int			flags,
4648934SJose.Borrego@Sun.COM     cred_t		*cr,
4658934SJose.Borrego@Sun.COM     caller_context_t	*ct)
4666600Sas200622 {
467*12890SJoyce.McIntosh@Sun.COM 	int	rc = 0;
4686600Sas200622 
469*12890SJoyce.McIntosh@Sun.COM 	if (vap->va_mask & AT_SIZE)
470*12890SJoyce.McIntosh@Sun.COM 		rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
4718934SJose.Borrego@Sun.COM 	if (rc == 0)
4728934SJose.Borrego@Sun.COM 		rc = vnext_setattr(arg, vap, flags, cr, ct);
4738934SJose.Borrego@Sun.COM 	return (rc);
4746600Sas200622 }
4756600Sas200622 
4766600Sas200622 static int
smb_fem_oplock_rwlock(femarg_t * arg,int write_lock,caller_context_t * ct)4776600Sas200622 smb_fem_oplock_rwlock(
4788934SJose.Borrego@Sun.COM     femarg_t		*arg,
4798934SJose.Borrego@Sun.COM     int			write_lock,
4808934SJose.Borrego@Sun.COM     caller_context_t	*ct)
4816600Sas200622 {
482*12890SJoyce.McIntosh@Sun.COM 	int		rc;
483*12890SJoyce.McIntosh@Sun.COM 	uint32_t	flags;
4848934SJose.Borrego@Sun.COM 
485*12890SJoyce.McIntosh@Sun.COM 	if (write_lock)
486*12890SJoyce.McIntosh@Sun.COM 		flags = SMB_OPLOCK_BREAK_TO_NONE;
487*12890SJoyce.McIntosh@Sun.COM 	else
488*12890SJoyce.McIntosh@Sun.COM 		flags = SMB_OPLOCK_BREAK_TO_LEVEL_II;
489*12890SJoyce.McIntosh@Sun.COM 
490*12890SJoyce.McIntosh@Sun.COM 	rc = smb_fem_oplock_break(arg, ct, flags);
491*12890SJoyce.McIntosh@Sun.COM 	if (rc == 0)
492*12890SJoyce.McIntosh@Sun.COM 		rc = vnext_rwlock(arg, write_lock, ct);
493*12890SJoyce.McIntosh@Sun.COM 
494*12890SJoyce.McIntosh@Sun.COM 	return (rc);
4956600Sas200622 }
4966600Sas200622 
4976600Sas200622 static int
smb_fem_oplock_space(femarg_t * arg,int cmd,flock64_t * bfp,int flag,offset_t offset,cred_t * cr,caller_context_t * ct)4986600Sas200622 smb_fem_oplock_space(
4998934SJose.Borrego@Sun.COM     femarg_t		*arg,
5008934SJose.Borrego@Sun.COM     int			cmd,
5018934SJose.Borrego@Sun.COM     flock64_t		*bfp,
5028934SJose.Borrego@Sun.COM     int			flag,
5038934SJose.Borrego@Sun.COM     offset_t		offset,
5048934SJose.Borrego@Sun.COM     cred_t		*cr,
5058934SJose.Borrego@Sun.COM     caller_context_t	*ct)
5066600Sas200622 {
5078934SJose.Borrego@Sun.COM 	int	rc;
5086600Sas200622 
509*12890SJoyce.McIntosh@Sun.COM 	rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
5108934SJose.Borrego@Sun.COM 	if (rc == 0)
5118934SJose.Borrego@Sun.COM 		rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct);
5128934SJose.Borrego@Sun.COM 	return (rc);
5136600Sas200622 }
5146600Sas200622 
5156600Sas200622 /*
5166600Sas200622  * smb_fem_oplock_vnevent()
5176600Sas200622  *
5186600Sas200622  * To intercept NFS and local renames and removes in order to break any
5196600Sas200622  * existing oplock prior to the operation.
5206600Sas200622  *
5216600Sas200622  * Note: Currently, this monitor is traversed only when an FS is mounted
5226600Sas200622  * non-nbmand.  (When the FS is mounted nbmand, share reservation checking
5236600Sas200622  * will detect a share violation and return an error prior to the VOP layer
5246600Sas200622  * being reached.)  Thus, for nbmand NFS and local renames and removes,
5256600Sas200622  * an existing oplock is never broken prior to share checking (contrary to
5266600Sas200622  * how it is with intra-CIFS remove and rename requests).
5276600Sas200622  */
5286600Sas200622 
5296600Sas200622 static int
smb_fem_oplock_vnevent(femarg_t * arg,vnevent_t vnevent,vnode_t * dvp,char * name,caller_context_t * ct)5306600Sas200622 smb_fem_oplock_vnevent(
5318934SJose.Borrego@Sun.COM     femarg_t		*arg,
5328934SJose.Borrego@Sun.COM     vnevent_t		vnevent,
5338934SJose.Borrego@Sun.COM     vnode_t		*dvp,
5348934SJose.Borrego@Sun.COM     char		*name,
5358934SJose.Borrego@Sun.COM     caller_context_t	*ct)
5366600Sas200622 {
537*12890SJoyce.McIntosh@Sun.COM 	int		rc;
538*12890SJoyce.McIntosh@Sun.COM 	uint32_t	flags;
5398934SJose.Borrego@Sun.COM 
5406600Sas200622 	switch (vnevent) {
5416600Sas200622 	case VE_REMOVE:
5426600Sas200622 	case VE_RENAME_DEST:
543*12890SJoyce.McIntosh@Sun.COM 		flags = SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH;
544*12890SJoyce.McIntosh@Sun.COM 		rc = smb_fem_oplock_break(arg, ct, flags);
545*12890SJoyce.McIntosh@Sun.COM 		break;
5466600Sas200622 	case VE_RENAME_SRC:
547*12890SJoyce.McIntosh@Sun.COM 		flags = SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH;
548*12890SJoyce.McIntosh@Sun.COM 		rc = smb_fem_oplock_break(arg, ct, flags);
5496600Sas200622 		break;
5506600Sas200622 	default:
551*12890SJoyce.McIntosh@Sun.COM 		rc = 0;
5526600Sas200622 		break;
5536600Sas200622 	}
554*12890SJoyce.McIntosh@Sun.COM 
555*12890SJoyce.McIntosh@Sun.COM 	if (rc != 0)
556*12890SJoyce.McIntosh@Sun.COM 		return (rc);
557*12890SJoyce.McIntosh@Sun.COM 
5586600Sas200622 	return (vnext_vnevent(arg, vnevent, dvp, name, ct));
5596600Sas200622 }
5608934SJose.Borrego@Sun.COM 
5618934SJose.Borrego@Sun.COM static int
smb_fem_oplock_break(femarg_t * arg,caller_context_t * ct,uint32_t flags)562*12890SJoyce.McIntosh@Sun.COM smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct, uint32_t flags)
5638934SJose.Borrego@Sun.COM {
5648934SJose.Borrego@Sun.COM 	smb_node_t	*node;
5658934SJose.Borrego@Sun.COM 	int		rc;
5668934SJose.Borrego@Sun.COM 
5678934SJose.Borrego@Sun.COM 	node = (smb_node_t *)((arg)->fa_fnode->fn_available);
5688934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
5698934SJose.Borrego@Sun.COM 
570*12890SJoyce.McIntosh@Sun.COM 	if (ct && (ct->cc_caller_id == smb_ct.cc_caller_id))
5718934SJose.Borrego@Sun.COM 		return (0);
5728934SJose.Borrego@Sun.COM 
573*12890SJoyce.McIntosh@Sun.COM 	if (ct && (ct->cc_flags & CC_DONTBLOCK)) {
574*12890SJoyce.McIntosh@Sun.COM 		flags |= SMB_OPLOCK_BREAK_NOWAIT;
575*12890SJoyce.McIntosh@Sun.COM 		rc = smb_oplock_break(NULL, node, flags);
576*12890SJoyce.McIntosh@Sun.COM 		if (rc == EAGAIN)
577*12890SJoyce.McIntosh@Sun.COM 			ct->cc_flags |= CC_WOULDBLOCK;
5788934SJose.Borrego@Sun.COM 	} else {
579*12890SJoyce.McIntosh@Sun.COM 		rc = smb_oplock_break(NULL, node, flags);
5808934SJose.Borrego@Sun.COM 	}
581*12890SJoyce.McIntosh@Sun.COM 
5828934SJose.Borrego@Sun.COM 	return (rc);
5838934SJose.Borrego@Sun.COM }
584