1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22cb174861Sjoyce mcintosh * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23*b819cea2SGordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 24da6c28aaSamw */ 25da6c28aaSamw 26bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h> 278c10a865Sas200622 #include <smbsrv/smb_fsops.h> 28da6c28aaSamw #include <sys/sdt.h> 298c10a865Sas200622 #include <sys/fcntl.h> 30da6c28aaSamw #include <sys/vfs.h> 31da6c28aaSamw #include <sys/vfs_opreg.h> 32da6c28aaSamw #include <sys/vnode.h> 33da6c28aaSamw #include <sys/fem.h> 34da6c28aaSamw 358c10a865Sas200622 extern caller_context_t smb_ct; 368c10a865Sas200622 378c10a865Sas200622 static boolean_t smb_fem_initialized = B_FALSE; 388c10a865Sas200622 static fem_t *smb_fcn_ops = NULL; 398c10a865Sas200622 static fem_t *smb_oplock_ops = NULL; 408c10a865Sas200622 418c10a865Sas200622 /* 428c10a865Sas200622 * Declarations for FCN (file change notification) FEM monitors 438c10a865Sas200622 */ 448c10a865Sas200622 458c10a865Sas200622 static int smb_fem_fcn_create(femarg_t *, char *, vattr_t *, vcexcl_t, int, 46da6c28aaSamw vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *); 478c10a865Sas200622 static int smb_fem_fcn_remove(femarg_t *, char *, cred_t *, 48da6c28aaSamw caller_context_t *, int); 498c10a865Sas200622 static int smb_fem_fcn_rename(femarg_t *, char *, vnode_t *, char *, 50da6c28aaSamw cred_t *, caller_context_t *, int); 518c10a865Sas200622 static int smb_fem_fcn_mkdir(femarg_t *, char *, vattr_t *, vnode_t **, 52da6c28aaSamw cred_t *, caller_context_t *, int, vsecattr_t *); 538c10a865Sas200622 static int smb_fem_fcn_rmdir(femarg_t *, char *, vnode_t *, cred_t *, 54da6c28aaSamw caller_context_t *, int); 558c10a865Sas200622 static int smb_fem_fcn_link(femarg_t *, vnode_t *, char *, cred_t *, 56da6c28aaSamw caller_context_t *, int); 578c10a865Sas200622 static int smb_fem_fcn_symlink(femarg_t *, char *, vattr_t *, 58da6c28aaSamw char *, cred_t *, caller_context_t *, int); 59da6c28aaSamw 60da6c28aaSamw static const fs_operation_def_t smb_fcn_tmpl[] = { 61da6c28aaSamw VOPNAME_CREATE, { .femop_create = smb_fem_fcn_create }, 62da6c28aaSamw VOPNAME_REMOVE, {.femop_remove = smb_fem_fcn_remove}, 63da6c28aaSamw VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename}, 64da6c28aaSamw VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir}, 65da6c28aaSamw VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir}, 66da6c28aaSamw VOPNAME_LINK, {.femop_link = smb_fem_fcn_link}, 67da6c28aaSamw VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink}, 68da6c28aaSamw NULL, NULL 69da6c28aaSamw }; 70da6c28aaSamw 718c10a865Sas200622 /* 728c10a865Sas200622 * Declarations for oplock FEM monitors 738c10a865Sas200622 */ 748c10a865Sas200622 758c10a865Sas200622 static int smb_fem_oplock_open(femarg_t *, int, cred_t *, 768c10a865Sas200622 struct caller_context *); 778c10a865Sas200622 static int smb_fem_oplock_read(femarg_t *, uio_t *, int, cred_t *, 788c10a865Sas200622 struct caller_context *); 798c10a865Sas200622 static int smb_fem_oplock_write(femarg_t *, uio_t *, int, cred_t *, 808c10a865Sas200622 struct caller_context *); 818c10a865Sas200622 static int smb_fem_oplock_setattr(femarg_t *, vattr_t *, int, cred_t *, 828c10a865Sas200622 caller_context_t *); 838c10a865Sas200622 static int smb_fem_oplock_rwlock(femarg_t *, int, caller_context_t *); 848c10a865Sas200622 static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int, 858c10a865Sas200622 offset_t, cred_t *, caller_context_t *); 868c10a865Sas200622 static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *, 878c10a865Sas200622 caller_context_t *); 888c10a865Sas200622 898c10a865Sas200622 static const fs_operation_def_t smb_oplock_tmpl[] = { 908c10a865Sas200622 VOPNAME_OPEN, { .femop_open = smb_fem_oplock_open }, 918c10a865Sas200622 VOPNAME_READ, { .femop_read = smb_fem_oplock_read }, 928c10a865Sas200622 VOPNAME_WRITE, { .femop_write = smb_fem_oplock_write }, 938c10a865Sas200622 VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr }, 948c10a865Sas200622 VOPNAME_RWLOCK, { .femop_rwlock = smb_fem_oplock_rwlock }, 958c10a865Sas200622 VOPNAME_SPACE, { .femop_space = smb_fem_oplock_space }, 968c10a865Sas200622 VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent }, 978c10a865Sas200622 NULL, NULL 988c10a865Sas200622 }; 998c10a865Sas200622 100cb174861Sjoyce mcintosh static int smb_fem_oplock_break(femarg_t *, caller_context_t *, uint32_t); 1012c2961f8Sjose borrego 102faa1795aSjb150015 /* 103faa1795aSjb150015 * smb_fem_init 104faa1795aSjb150015 * 105faa1795aSjb150015 * This function is not multi-thread safe. The caller must make sure only one 106faa1795aSjb150015 * thread makes the call. 107faa1795aSjb150015 */ 108da6c28aaSamw int 109faa1795aSjb150015 smb_fem_init(void) 110da6c28aaSamw { 111faa1795aSjb150015 int rc = 0; 112faa1795aSjb150015 113faa1795aSjb150015 if (smb_fem_initialized) 114faa1795aSjb150015 return (0); 115faa1795aSjb150015 116faa1795aSjb150015 rc = fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops); 117faa1795aSjb150015 if (rc) 118faa1795aSjb150015 return (rc); 119faa1795aSjb150015 1208c10a865Sas200622 rc = fem_create("smb_oplock_ops", smb_oplock_tmpl, 1218c10a865Sas200622 &smb_oplock_ops); 1228c10a865Sas200622 1238c10a865Sas200622 if (rc) { 1248c10a865Sas200622 fem_free(smb_fcn_ops); 1258c10a865Sas200622 smb_fcn_ops = NULL; 1268c10a865Sas200622 return (rc); 1278c10a865Sas200622 } 1288c10a865Sas200622 129faa1795aSjb150015 smb_fem_initialized = B_TRUE; 130faa1795aSjb150015 131faa1795aSjb150015 return (0); 132da6c28aaSamw } 133da6c28aaSamw 134faa1795aSjb150015 /* 135faa1795aSjb150015 * smb_fem_fini 136faa1795aSjb150015 * 137faa1795aSjb150015 * This function is not multi-thread safe. The caller must make sure only one 138faa1795aSjb150015 * thread makes the call. 139faa1795aSjb150015 */ 140da6c28aaSamw void 141faa1795aSjb150015 smb_fem_fini(void) 142da6c28aaSamw { 143faa1795aSjb150015 if (!smb_fem_initialized) 144faa1795aSjb150015 return; 145faa1795aSjb150015 1468622ec45SGordon Ross if (smb_fcn_ops != NULL) { 147da6c28aaSamw fem_free(smb_fcn_ops); 148faa1795aSjb150015 smb_fcn_ops = NULL; 1498622ec45SGordon Ross } 1508622ec45SGordon Ross if (smb_oplock_ops != NULL) { 1518622ec45SGordon Ross fem_free(smb_oplock_ops); 1528c10a865Sas200622 smb_oplock_ops = NULL; 1538622ec45SGordon Ross } 154faa1795aSjb150015 smb_fem_initialized = B_FALSE; 155da6c28aaSamw } 156da6c28aaSamw 1578622ec45SGordon Ross int 158da6c28aaSamw smb_fem_fcn_install(smb_node_t *node) 159da6c28aaSamw { 1608622ec45SGordon Ross int rc; 1618622ec45SGordon Ross 1628622ec45SGordon Ross if (smb_fcn_ops == NULL) 1638622ec45SGordon Ross return (ENOSYS); 1648622ec45SGordon Ross rc = fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ, 1658c10a865Sas200622 (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release); 1668622ec45SGordon Ross return (rc); 167da6c28aaSamw } 168da6c28aaSamw 169da6c28aaSamw void 170da6c28aaSamw smb_fem_fcn_uninstall(smb_node_t *node) 171da6c28aaSamw { 1728622ec45SGordon Ross if (smb_fcn_ops == NULL) 1738622ec45SGordon Ross return; 1748622ec45SGordon Ross VERIFY0(fem_uninstall(node->vp, smb_fcn_ops, (void *)node)); 175da6c28aaSamw } 176da6c28aaSamw 1778c10a865Sas200622 int 1788c10a865Sas200622 smb_fem_oplock_install(smb_node_t *node) 1798c10a865Sas200622 { 1808622ec45SGordon Ross int rc; 1818622ec45SGordon Ross 1828622ec45SGordon Ross if (smb_oplock_ops == NULL) 1838622ec45SGordon Ross return (ENOSYS); 1848622ec45SGordon Ross rc = fem_install(node->vp, smb_oplock_ops, (void *)node, OPARGUNIQ, 1858622ec45SGordon Ross (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release); 1868622ec45SGordon Ross return (rc); 1878c10a865Sas200622 } 1888c10a865Sas200622 1898622ec45SGordon Ross void 1908c10a865Sas200622 smb_fem_oplock_uninstall(smb_node_t *node) 1918c10a865Sas200622 { 1928622ec45SGordon Ross if (smb_oplock_ops == NULL) 1938622ec45SGordon Ross return; 1948622ec45SGordon Ross VERIFY0(fem_uninstall(node->vp, smb_oplock_ops, (void *)node)); 1958c10a865Sas200622 } 1968c10a865Sas200622 1978c10a865Sas200622 /* 1988c10a865Sas200622 * FEM FCN monitors 1998c10a865Sas200622 * 2008c10a865Sas200622 * The FCN monitors intercept the respective VOP_* call regardless 2018c10a865Sas200622 * of whether the call originates from CIFS, NFS, or a local process. 2028c10a865Sas200622 */ 2038c10a865Sas200622 204da6c28aaSamw /* 205da6c28aaSamw * smb_fem_fcn_create() 206da6c28aaSamw * 207da6c28aaSamw * This monitor will catch only changes to VREG files and not to extended 208da6c28aaSamw * attribute files. This is fine because, for CIFS files, stream creates 209da6c28aaSamw * should not trigger any file change notification on the VDIR directory 210da6c28aaSamw * being monitored. Creates of any other kind of extended attribute in 211da6c28aaSamw * the directory will also not trigger any file change notification on the 212da6c28aaSamw * VDIR directory being monitored. 213da6c28aaSamw */ 214da6c28aaSamw 2158c10a865Sas200622 static int 216da6c28aaSamw smb_fem_fcn_create( 217da6c28aaSamw femarg_t *arg, 218da6c28aaSamw char *name, 219da6c28aaSamw vattr_t *vap, 220da6c28aaSamw vcexcl_t excl, 221da6c28aaSamw int mode, 222da6c28aaSamw vnode_t **vpp, 223da6c28aaSamw cred_t *cr, 224da6c28aaSamw int flag, 225da6c28aaSamw caller_context_t *ct, 226da6c28aaSamw vsecattr_t *vsecp) 227da6c28aaSamw { 228da6c28aaSamw smb_node_t *dnode; 229da6c28aaSamw int error; 230da6c28aaSamw 231da6c28aaSamw dnode = (smb_node_t *)arg->fa_fnode->fn_available; 232da6c28aaSamw 233da6c28aaSamw ASSERT(dnode); 234da6c28aaSamw 235da6c28aaSamw error = vnext_create(arg, name, vap, excl, mode, vpp, cr, flag, 236da6c28aaSamw ct, vsecp); 237da6c28aaSamw 238*b819cea2SGordon Ross if (error == 0 && ct != &smb_ct) 239ccc71be5SGordon Ross smb_node_notify_change(dnode, FILE_ACTION_ADDED, name); 240da6c28aaSamw 241da6c28aaSamw return (error); 242da6c28aaSamw } 243da6c28aaSamw 244da6c28aaSamw /* 245da6c28aaSamw * smb_fem_fcn_remove() 246da6c28aaSamw * 247da6c28aaSamw * This monitor will catch only changes to VREG files and to not extended 248da6c28aaSamw * attribute files. This is fine because, for CIFS files, stream deletes 249da6c28aaSamw * should not trigger any file change notification on the VDIR directory 250da6c28aaSamw * being monitored. Deletes of any other kind of extended attribute in 251da6c28aaSamw * the directory will also not trigger any file change notification on the 252da6c28aaSamw * VDIR directory being monitored. 253da6c28aaSamw */ 254da6c28aaSamw 2558c10a865Sas200622 static int 256da6c28aaSamw smb_fem_fcn_remove( 257da6c28aaSamw femarg_t *arg, 258da6c28aaSamw char *name, 259da6c28aaSamw cred_t *cr, 260da6c28aaSamw caller_context_t *ct, 261da6c28aaSamw int flags) 262da6c28aaSamw { 263da6c28aaSamw smb_node_t *dnode; 264da6c28aaSamw int error; 265da6c28aaSamw 266da6c28aaSamw dnode = (smb_node_t *)arg->fa_fnode->fn_available; 267da6c28aaSamw 268da6c28aaSamw ASSERT(dnode); 269da6c28aaSamw 270da6c28aaSamw error = vnext_remove(arg, name, cr, ct, flags); 271da6c28aaSamw 272*b819cea2SGordon Ross if (error == 0 && ct != &smb_ct) 273ccc71be5SGordon Ross smb_node_notify_change(dnode, FILE_ACTION_REMOVED, name); 274da6c28aaSamw 275da6c28aaSamw return (error); 276da6c28aaSamw } 277da6c28aaSamw 2788c10a865Sas200622 static int 279da6c28aaSamw smb_fem_fcn_rename( 280da6c28aaSamw femarg_t *arg, 281da6c28aaSamw char *snm, 282da6c28aaSamw vnode_t *tdvp, 283da6c28aaSamw char *tnm, 284da6c28aaSamw cred_t *cr, 285da6c28aaSamw caller_context_t *ct, 286da6c28aaSamw int flags) 287da6c28aaSamw { 288da6c28aaSamw smb_node_t *dnode; 289da6c28aaSamw int error; 290da6c28aaSamw 291da6c28aaSamw dnode = (smb_node_t *)arg->fa_fnode->fn_available; 292da6c28aaSamw 293da6c28aaSamw ASSERT(dnode); 294da6c28aaSamw 295da6c28aaSamw error = vnext_rename(arg, snm, tdvp, tnm, cr, ct, flags); 296da6c28aaSamw 297*b819cea2SGordon Ross if (error == 0 && ct != &smb_ct) { 298ccc71be5SGordon Ross /* 299ccc71be5SGordon Ross * Note that renames in the same directory are normally 300ccc71be5SGordon Ross * delivered in {old,new} pairs, and clients expect them 301ccc71be5SGordon Ross * in that order, if both events are delivered. 302ccc71be5SGordon Ross */ 303*b819cea2SGordon Ross smb_node_notify_change(dnode, 304*b819cea2SGordon Ross FILE_ACTION_RENAMED_OLD_NAME, snm); 305*b819cea2SGordon Ross smb_node_notify_change(dnode, 306*b819cea2SGordon Ross FILE_ACTION_RENAMED_NEW_NAME, tnm); 307*b819cea2SGordon Ross } 308ccc71be5SGordon Ross 309*b819cea2SGordon Ross return (error); 310da6c28aaSamw } 311da6c28aaSamw 3128c10a865Sas200622 static int 313da6c28aaSamw smb_fem_fcn_mkdir( 314da6c28aaSamw femarg_t *arg, 315da6c28aaSamw char *name, 316da6c28aaSamw vattr_t *vap, 317da6c28aaSamw vnode_t **vpp, 318da6c28aaSamw cred_t *cr, 319da6c28aaSamw caller_context_t *ct, 320da6c28aaSamw int flags, 321da6c28aaSamw vsecattr_t *vsecp) 322da6c28aaSamw { 323da6c28aaSamw smb_node_t *dnode; 324da6c28aaSamw int error; 325da6c28aaSamw 326da6c28aaSamw dnode = (smb_node_t *)arg->fa_fnode->fn_available; 327da6c28aaSamw 328da6c28aaSamw ASSERT(dnode); 329da6c28aaSamw 330da6c28aaSamw error = vnext_mkdir(arg, name, vap, vpp, cr, ct, flags, vsecp); 331da6c28aaSamw 332*b819cea2SGordon Ross if (error == 0 && ct != &smb_ct) 333ccc71be5SGordon Ross smb_node_notify_change(dnode, FILE_ACTION_ADDED, name); 334da6c28aaSamw 335da6c28aaSamw return (error); 336da6c28aaSamw } 337da6c28aaSamw 3388c10a865Sas200622 static int 339da6c28aaSamw smb_fem_fcn_rmdir( 340da6c28aaSamw femarg_t *arg, 341da6c28aaSamw char *name, 342da6c28aaSamw vnode_t *cdir, 343da6c28aaSamw cred_t *cr, 344da6c28aaSamw caller_context_t *ct, 345da6c28aaSamw int flags) 346da6c28aaSamw { 347da6c28aaSamw smb_node_t *dnode; 348da6c28aaSamw int error; 349da6c28aaSamw 350da6c28aaSamw dnode = (smb_node_t *)arg->fa_fnode->fn_available; 351da6c28aaSamw 352da6c28aaSamw ASSERT(dnode); 353da6c28aaSamw 354da6c28aaSamw error = vnext_rmdir(arg, name, cdir, cr, ct, flags); 355da6c28aaSamw 356*b819cea2SGordon Ross if (error == 0 && ct != &smb_ct) 357ccc71be5SGordon Ross smb_node_notify_change(dnode, FILE_ACTION_REMOVED, name); 358da6c28aaSamw 359da6c28aaSamw return (error); 360da6c28aaSamw } 361da6c28aaSamw 3628c10a865Sas200622 static int 363da6c28aaSamw smb_fem_fcn_link( 364da6c28aaSamw femarg_t *arg, 365da6c28aaSamw vnode_t *svp, 366da6c28aaSamw char *tnm, 367da6c28aaSamw cred_t *cr, 368da6c28aaSamw caller_context_t *ct, 369da6c28aaSamw int flags) 370da6c28aaSamw { 371da6c28aaSamw smb_node_t *dnode; 372da6c28aaSamw int error; 373da6c28aaSamw 374da6c28aaSamw dnode = (smb_node_t *)arg->fa_fnode->fn_available; 375da6c28aaSamw 376da6c28aaSamw ASSERT(dnode); 377da6c28aaSamw 378da6c28aaSamw error = vnext_link(arg, svp, tnm, cr, ct, flags); 379da6c28aaSamw 380*b819cea2SGordon Ross if (error == 0 && ct != &smb_ct) 381ccc71be5SGordon Ross smb_node_notify_change(dnode, FILE_ACTION_ADDED, tnm); 382da6c28aaSamw 383da6c28aaSamw return (error); 384da6c28aaSamw } 385da6c28aaSamw 3868c10a865Sas200622 static int 387da6c28aaSamw smb_fem_fcn_symlink( 388da6c28aaSamw femarg_t *arg, 389da6c28aaSamw char *linkname, 390da6c28aaSamw vattr_t *vap, 391da6c28aaSamw char *target, 392da6c28aaSamw cred_t *cr, 393da6c28aaSamw caller_context_t *ct, 394da6c28aaSamw int flags) 395da6c28aaSamw { 396da6c28aaSamw smb_node_t *dnode; 397da6c28aaSamw int error; 398da6c28aaSamw 399da6c28aaSamw dnode = (smb_node_t *)arg->fa_fnode->fn_available; 400da6c28aaSamw 401da6c28aaSamw ASSERT(dnode); 402da6c28aaSamw 403da6c28aaSamw error = vnext_symlink(arg, linkname, vap, target, cr, ct, flags); 404da6c28aaSamw 405*b819cea2SGordon Ross if (error == 0 && ct != &smb_ct) 406ccc71be5SGordon Ross smb_node_notify_change(dnode, FILE_ACTION_ADDED, linkname); 407da6c28aaSamw 408da6c28aaSamw return (error); 409da6c28aaSamw } 4108c10a865Sas200622 4118c10a865Sas200622 /* 4128c10a865Sas200622 * FEM oplock monitors 4138c10a865Sas200622 * 4148c10a865Sas200622 * The monitors below are not intended to intercept CIFS calls. 4158c10a865Sas200622 * CIFS higher-level routines will break oplocks as needed prior 4168c10a865Sas200622 * to getting to the VFS layer. 4178c10a865Sas200622 */ 4188c10a865Sas200622 static int 4198c10a865Sas200622 smb_fem_oplock_open( 4208c10a865Sas200622 femarg_t *arg, 4218c10a865Sas200622 int mode, 4228c10a865Sas200622 cred_t *cr, 4232c2961f8Sjose borrego caller_context_t *ct) 4248c10a865Sas200622 { 425cb174861Sjoyce mcintosh uint32_t flags; 426*b819cea2SGordon Ross int rc = 0; 4278c10a865Sas200622 428*b819cea2SGordon Ross if (ct != &smb_ct) { 429cb174861Sjoyce mcintosh if (mode & (FWRITE|FTRUNC)) 430cb174861Sjoyce mcintosh flags = SMB_OPLOCK_BREAK_TO_NONE; 431cb174861Sjoyce mcintosh else 432cb174861Sjoyce mcintosh flags = SMB_OPLOCK_BREAK_TO_LEVEL_II; 433cb174861Sjoyce mcintosh rc = smb_fem_oplock_break(arg, ct, flags); 434*b819cea2SGordon Ross } 4352c2961f8Sjose borrego if (rc == 0) 4362c2961f8Sjose borrego rc = vnext_open(arg, mode, cr, ct); 437*b819cea2SGordon Ross 4382c2961f8Sjose borrego return (rc); 4398c10a865Sas200622 } 4408c10a865Sas200622 4418c10a865Sas200622 /* 4428c10a865Sas200622 * Should normally be hit only via NFSv2/v3. All other accesses 4438c10a865Sas200622 * (CIFS/NFS/local) should call VOP_OPEN first. 4448c10a865Sas200622 */ 4458c10a865Sas200622 4468c10a865Sas200622 static int 4478c10a865Sas200622 smb_fem_oplock_read( 4488c10a865Sas200622 femarg_t *arg, 4498c10a865Sas200622 uio_t *uiop, 4508c10a865Sas200622 int ioflag, 4518c10a865Sas200622 cred_t *cr, 4522c2961f8Sjose borrego caller_context_t *ct) 4538c10a865Sas200622 { 454*b819cea2SGordon Ross int rc = 0; 4558c10a865Sas200622 456*b819cea2SGordon Ross if (ct != &smb_ct) { 457*b819cea2SGordon Ross rc = smb_fem_oplock_break(arg, ct, 458*b819cea2SGordon Ross SMB_OPLOCK_BREAK_TO_LEVEL_II); 459*b819cea2SGordon Ross } 4602c2961f8Sjose borrego if (rc == 0) 4612c2961f8Sjose borrego rc = vnext_read(arg, uiop, ioflag, cr, ct); 462*b819cea2SGordon Ross 4632c2961f8Sjose borrego return (rc); 4648c10a865Sas200622 } 4658c10a865Sas200622 4668c10a865Sas200622 /* 4678c10a865Sas200622 * Should normally be hit only via NFSv2/v3. All other accesses 4688c10a865Sas200622 * (CIFS/NFS/local) should call VOP_OPEN first. 4698c10a865Sas200622 */ 4708c10a865Sas200622 4718c10a865Sas200622 static int 4728c10a865Sas200622 smb_fem_oplock_write( 4738c10a865Sas200622 femarg_t *arg, 4748c10a865Sas200622 uio_t *uiop, 4758c10a865Sas200622 int ioflag, 4768c10a865Sas200622 cred_t *cr, 4772c2961f8Sjose borrego caller_context_t *ct) 4788c10a865Sas200622 { 479*b819cea2SGordon Ross int rc = 0; 4808c10a865Sas200622 481*b819cea2SGordon Ross if (ct != &smb_ct) 482cb174861Sjoyce mcintosh rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE); 4832c2961f8Sjose borrego if (rc == 0) 4842c2961f8Sjose borrego rc = vnext_write(arg, uiop, ioflag, cr, ct); 485*b819cea2SGordon Ross 4862c2961f8Sjose borrego return (rc); 4878c10a865Sas200622 } 4888c10a865Sas200622 4898c10a865Sas200622 static int 4908c10a865Sas200622 smb_fem_oplock_setattr( 4918c10a865Sas200622 femarg_t *arg, 4928c10a865Sas200622 vattr_t *vap, 4938c10a865Sas200622 int flags, 4948c10a865Sas200622 cred_t *cr, 4958c10a865Sas200622 caller_context_t *ct) 4968c10a865Sas200622 { 497cb174861Sjoyce mcintosh int rc = 0; 4988c10a865Sas200622 499*b819cea2SGordon Ross if (ct != &smb_ct && (vap->va_mask & AT_SIZE) != 0) 500cb174861Sjoyce mcintosh rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE); 5012c2961f8Sjose borrego if (rc == 0) 5022c2961f8Sjose borrego rc = vnext_setattr(arg, vap, flags, cr, ct); 5032c2961f8Sjose borrego return (rc); 5048c10a865Sas200622 } 5058c10a865Sas200622 5068c10a865Sas200622 static int 5078c10a865Sas200622 smb_fem_oplock_rwlock( 5088c10a865Sas200622 femarg_t *arg, 5098c10a865Sas200622 int write_lock, 5108c10a865Sas200622 caller_context_t *ct) 5118c10a865Sas200622 { 512cb174861Sjoyce mcintosh uint32_t flags; 513*b819cea2SGordon Ross int rc = 0; 5148c10a865Sas200622 515*b819cea2SGordon Ross if (ct != &smb_ct) { 516cb174861Sjoyce mcintosh if (write_lock) 517cb174861Sjoyce mcintosh flags = SMB_OPLOCK_BREAK_TO_NONE; 518cb174861Sjoyce mcintosh else 519cb174861Sjoyce mcintosh flags = SMB_OPLOCK_BREAK_TO_LEVEL_II; 520cb174861Sjoyce mcintosh rc = smb_fem_oplock_break(arg, ct, flags); 521*b819cea2SGordon Ross } 522cb174861Sjoyce mcintosh if (rc == 0) 523cb174861Sjoyce mcintosh rc = vnext_rwlock(arg, write_lock, ct); 524cb174861Sjoyce mcintosh 5252c2961f8Sjose borrego return (rc); 5262c2961f8Sjose borrego } 5278c10a865Sas200622 5288c10a865Sas200622 static int 5298c10a865Sas200622 smb_fem_oplock_space( 5308c10a865Sas200622 femarg_t *arg, 5318c10a865Sas200622 int cmd, 5328c10a865Sas200622 flock64_t *bfp, 5338c10a865Sas200622 int flag, 5348c10a865Sas200622 offset_t offset, 5358c10a865Sas200622 cred_t *cr, 5368c10a865Sas200622 caller_context_t *ct) 5378c10a865Sas200622 { 538*b819cea2SGordon Ross int rc = 0; 5398c10a865Sas200622 540*b819cea2SGordon Ross if (ct != &smb_ct) 541cb174861Sjoyce mcintosh rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE); 5422c2961f8Sjose borrego if (rc == 0) 5432c2961f8Sjose borrego rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct); 5442c2961f8Sjose borrego return (rc); 5458c10a865Sas200622 } 5468c10a865Sas200622 5478c10a865Sas200622 /* 5488c10a865Sas200622 * smb_fem_oplock_vnevent() 5498c10a865Sas200622 * 5508c10a865Sas200622 * To intercept NFS and local renames and removes in order to break any 5518c10a865Sas200622 * existing oplock prior to the operation. 5528c10a865Sas200622 * 5538c10a865Sas200622 * Note: Currently, this monitor is traversed only when an FS is mounted 5548c10a865Sas200622 * non-nbmand. (When the FS is mounted nbmand, share reservation checking 5558c10a865Sas200622 * will detect a share violation and return an error prior to the VOP layer 5568c10a865Sas200622 * being reached.) Thus, for nbmand NFS and local renames and removes, 5578c10a865Sas200622 * an existing oplock is never broken prior to share checking (contrary to 5588c10a865Sas200622 * how it is with intra-CIFS remove and rename requests). 5598c10a865Sas200622 */ 5608c10a865Sas200622 5618c10a865Sas200622 static int 5628c10a865Sas200622 smb_fem_oplock_vnevent( 5638c10a865Sas200622 femarg_t *arg, 5648c10a865Sas200622 vnevent_t vnevent, 5658c10a865Sas200622 vnode_t *dvp, 5668c10a865Sas200622 char *name, 5678c10a865Sas200622 caller_context_t *ct) 5688c10a865Sas200622 { 569cb174861Sjoyce mcintosh uint32_t flags; 570*b819cea2SGordon Ross int rc = 0; 5712c2961f8Sjose borrego 572*b819cea2SGordon Ross if (ct != &smb_ct) { 5738c10a865Sas200622 switch (vnevent) { 5748c10a865Sas200622 case VE_REMOVE: 5758c10a865Sas200622 case VE_RENAME_DEST: 576*b819cea2SGordon Ross flags = SMB_OPLOCK_BREAK_TO_NONE | 577*b819cea2SGordon Ross SMB_OPLOCK_BREAK_BATCH; 578cb174861Sjoyce mcintosh rc = smb_fem_oplock_break(arg, ct, flags); 5798c10a865Sas200622 break; 580cb174861Sjoyce mcintosh case VE_RENAME_SRC: 581*b819cea2SGordon Ross flags = SMB_OPLOCK_BREAK_TO_LEVEL_II | 582*b819cea2SGordon Ross SMB_OPLOCK_BREAK_BATCH; 583cb174861Sjoyce mcintosh rc = smb_fem_oplock_break(arg, ct, flags); 584cb174861Sjoyce mcintosh break; 5858c10a865Sas200622 default: 586cb174861Sjoyce mcintosh rc = 0; 5878c10a865Sas200622 break; 5888c10a865Sas200622 } 589*b819cea2SGordon Ross } 590*b819cea2SGordon Ross if (rc == 0) 591*b819cea2SGordon Ross rc = vnext_vnevent(arg, vnevent, dvp, name, ct); 592cb174861Sjoyce mcintosh 593cb174861Sjoyce mcintosh return (rc); 5948c10a865Sas200622 } 5952c2961f8Sjose borrego 5962c2961f8Sjose borrego static int 597cb174861Sjoyce mcintosh smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct, uint32_t flags) 5982c2961f8Sjose borrego { 5992c2961f8Sjose borrego smb_node_t *node; 6002c2961f8Sjose borrego int rc; 6012c2961f8Sjose borrego 6022c2961f8Sjose borrego node = (smb_node_t *)((arg)->fa_fnode->fn_available); 6032c2961f8Sjose borrego SMB_NODE_VALID(node); 6042c2961f8Sjose borrego 605*b819cea2SGordon Ross ASSERT(ct != &smb_ct); 6062c2961f8Sjose borrego 607cb174861Sjoyce mcintosh if (ct && (ct->cc_flags & CC_DONTBLOCK)) { 608cb174861Sjoyce mcintosh flags |= SMB_OPLOCK_BREAK_NOWAIT; 609cb174861Sjoyce mcintosh rc = smb_oplock_break(NULL, node, flags); 610cb174861Sjoyce mcintosh if (rc == EAGAIN) 6112c2961f8Sjose borrego ct->cc_flags |= CC_WOULDBLOCK; 6122c2961f8Sjose borrego } else { 613cb174861Sjoyce mcintosh rc = smb_oplock_break(NULL, node, flags); 6142c2961f8Sjose borrego } 615cb174861Sjoyce mcintosh 6162c2961f8Sjose borrego return (rc); 6172c2961f8Sjose borrego } 618