Print this page
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-3906 Prefer that SMB change notify not tie up a worker thread
NEX-5278 SMB notify should buffer per file handle
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4083 Upstream changes from illumos 5917 and 5995
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-3620 need upstream cleanups for smbsrv
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
SMB-58 smbsrv should be immune to its own FEM hooks
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
re #11215 rb3676 sesctl to SGI JBOD hangs in biowait() with a command stuck in mptsas driver
re #10734 NT Trans. Notify returning too quickly


   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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright 2015 Joyent, Inc.
  25  */
  26 
  27 #include <smbsrv/smb_kproto.h>
  28 #include <smbsrv/smb_fsops.h>
  29 #include <sys/sdt.h>
  30 #include <sys/fcntl.h>
  31 #include <sys/vfs.h>
  32 #include <sys/vfs_opreg.h>
  33 #include <sys/vnode.h>
  34 #include <sys/fem.h>
  35 
  36 extern caller_context_t smb_ct;
  37 
  38 static boolean_t        smb_fem_initialized = B_FALSE;
  39 static fem_t            *smb_fcn_ops = NULL;
  40 static fem_t            *smb_oplock_ops = NULL;
  41 
  42 /*
  43  * Declarations for FCN (file change notification) FEM monitors


  64         VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename},
  65         VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir},
  66         VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir},
  67         VOPNAME_LINK, {.femop_link = smb_fem_fcn_link},
  68         VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink},
  69         NULL, NULL
  70 };
  71 
  72 /*
  73  * Declarations for oplock FEM monitors
  74  */
  75 
  76 static int smb_fem_oplock_open(femarg_t *, int, cred_t *,
  77     struct caller_context *);
  78 static int smb_fem_oplock_read(femarg_t *, uio_t *, int, cred_t *,
  79     struct caller_context *);
  80 static int smb_fem_oplock_write(femarg_t *, uio_t *, int, cred_t *,
  81     struct caller_context *);
  82 static int smb_fem_oplock_setattr(femarg_t *, vattr_t *, int, cred_t *,
  83     caller_context_t *);
  84 static int smb_fem_oplock_rwlock(femarg_t *, int, caller_context_t *);
  85 static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int,
  86     offset_t, cred_t *, caller_context_t *);
  87 static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *,
  88     caller_context_t *);
  89 
  90 static const fs_operation_def_t smb_oplock_tmpl[] = {
  91         VOPNAME_OPEN,   { .femop_open = smb_fem_oplock_open },
  92         VOPNAME_READ,   { .femop_read = smb_fem_oplock_read },
  93         VOPNAME_WRITE,  { .femop_write = smb_fem_oplock_write },
  94         VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr },
  95         VOPNAME_RWLOCK, { .femop_rwlock = smb_fem_oplock_rwlock },
  96         VOPNAME_SPACE,  { .femop_space = smb_fem_oplock_space },
  97         VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent },
  98         NULL, NULL
  99 };
 100 
 101 static int smb_fem_oplock_break(femarg_t *, caller_context_t *, uint32_t);
 102 
 103 /*
 104  * smb_fem_init
 105  *
 106  * This function is not multi-thread safe. The caller must make sure only one
 107  * thread makes the call.
 108  */
 109 int
 110 smb_fem_init(void)
 111 {
 112         int     rc = 0;
 113 
 114         if (smb_fem_initialized)
 115                 return (0);
 116 
 117         rc = fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops);
 118         if (rc)
 119                 return (rc);
 120 
 121         rc = fem_create("smb_oplock_ops", smb_oplock_tmpl,


 138  * This function is not multi-thread safe. The caller must make sure only one
 139  * thread makes the call.
 140  */
 141 void
 142 smb_fem_fini(void)
 143 {
 144         if (!smb_fem_initialized)
 145                 return;
 146 
 147         if (smb_fcn_ops != NULL) {
 148                 fem_free(smb_fcn_ops);
 149                 smb_fcn_ops = NULL;
 150         }
 151         if (smb_oplock_ops != NULL) {
 152                 fem_free(smb_oplock_ops);
 153                 smb_oplock_ops = NULL;
 154         }
 155         smb_fem_initialized = B_FALSE;
 156 }
 157 





 158 int
 159 smb_fem_fcn_install(smb_node_t *node)
 160 {
 161         int rc;
 162 
 163         if (smb_fcn_ops == NULL)
 164                 return (ENOSYS);
 165         rc = fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ,
 166             (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
 167         return (rc);
 168 }
 169 
 170 void
 171 smb_fem_fcn_uninstall(smb_node_t *node)
 172 {
 173         if (smb_fcn_ops == NULL)
 174                 return;
 175         VERIFY0(fem_uninstall(node->vp, smb_fcn_ops, (void *)node));
 176 }
 177 
 178 int
 179 smb_fem_oplock_install(smb_node_t *node)
 180 {
 181         int rc;
 182 
 183         if (smb_oplock_ops == NULL)
 184                 return (ENOSYS);
 185         rc = fem_install(node->vp, smb_oplock_ops, (void *)node, OPARGUNIQ,
 186             (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);


 406         if (error == 0 && ct != &smb_ct)
 407                 smb_node_notify_change(dnode, FILE_ACTION_ADDED, linkname);
 408 
 409         return (error);
 410 }
 411 
 412 /*
 413  * FEM oplock monitors
 414  *
 415  * The monitors below are not intended to intercept CIFS calls.
 416  * CIFS higher-level routines will break oplocks as needed prior
 417  * to getting to the VFS layer.
 418  */
 419 static int
 420 smb_fem_oplock_open(
 421     femarg_t            *arg,
 422     int                 mode,
 423     cred_t              *cr,
 424     caller_context_t    *ct)
 425 {
 426         uint32_t        flags;

 427         int             rc = 0;
 428 
 429         if (ct != &smb_ct) {
 430                 if (mode & (FWRITE|FTRUNC))
 431                         flags = SMB_OPLOCK_BREAK_TO_NONE;
 432                 else
 433                         flags = SMB_OPLOCK_BREAK_TO_LEVEL_II;
 434                 rc = smb_fem_oplock_break(arg, ct, flags);












 435         }








 436         if (rc == 0)
 437                 rc = vnext_open(arg, mode, cr, ct);
 438 
 439         return (rc);
 440 }
 441 
 442 /*
 443  * Should normally be hit only via NFSv2/v3.  All other accesses
 444  * (CIFS/NFS/local) should call VOP_OPEN first.
 445  */
 446 
 447 static int
 448 smb_fem_oplock_read(
 449     femarg_t            *arg,
 450     uio_t               *uiop,
 451     int                 ioflag,
 452     cred_t              *cr,
 453     caller_context_t    *ct)
 454 {


 455         int     rc = 0;
 456 
 457         if (ct != &smb_ct) {
 458                 rc = smb_fem_oplock_break(arg, ct,
 459                     SMB_OPLOCK_BREAK_TO_LEVEL_II);






 460         }
 461         if (rc == 0)
 462                 rc = vnext_read(arg, uiop, ioflag, cr, ct);
 463 
 464         return (rc);
 465 }
 466 
 467 /*
 468  * Should normally be hit only via NFSv2/v3.  All other accesses
 469  * (CIFS/NFS/local) should call VOP_OPEN first.
 470  */
 471 
 472 static int
 473 smb_fem_oplock_write(
 474     femarg_t            *arg,
 475     uio_t               *uiop,
 476     int                 ioflag,
 477     cred_t              *cr,
 478     caller_context_t    *ct)
 479 {


 480         int     rc = 0;
 481 
 482         if (ct != &smb_ct)
 483                 rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);








 484         if (rc == 0)
 485                 rc = vnext_write(arg, uiop, ioflag, cr, ct);
 486 
 487         return (rc);
 488 }
 489 
 490 static int
 491 smb_fem_oplock_setattr(
 492     femarg_t            *arg,
 493     vattr_t             *vap,
 494     int                 flags,
 495     cred_t              *cr,
 496     caller_context_t    *ct)
 497 {


 498         int     rc = 0;
 499 
 500         if (ct != &smb_ct && (vap->va_mask & AT_SIZE) != 0)
 501                 rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
 502         if (rc == 0)
 503                 rc = vnext_setattr(arg, vap, flags, cr, ct);
 504         return (rc);
 505 }
 506 
 507 static int
 508 smb_fem_oplock_rwlock(
 509     femarg_t            *arg,
 510     int                 write_lock,
 511     caller_context_t    *ct)
 512 {
 513         uint32_t        flags;
 514         int             rc = 0;
 515 
 516         if (ct != &smb_ct) {
 517                 if (write_lock)
 518                         flags = SMB_OPLOCK_BREAK_TO_NONE;
 519                 else
 520                         flags = SMB_OPLOCK_BREAK_TO_LEVEL_II;
 521                 rc = smb_fem_oplock_break(arg, ct, flags);
 522         }
 523         if (rc == 0)
 524                 rc = vnext_rwlock(arg, write_lock, ct);
 525 
 526         return (rc);
 527 }
 528 
 529 static int
 530 smb_fem_oplock_space(
 531     femarg_t            *arg,
 532     int                 cmd,
 533     flock64_t           *bfp,
 534     int                 flag,
 535     offset_t            offset,
 536     cred_t              *cr,
 537     caller_context_t    *ct)
 538 {


 539         int     rc = 0;
 540 
 541         if (ct != &smb_ct)
 542                 rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);









 543         if (rc == 0)
 544                 rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct);
 545         return (rc);
 546 }
 547 
 548 /*
 549  * smb_fem_oplock_vnevent()
 550  *
 551  * To intercept NFS and local renames and removes in order to break any
 552  * existing oplock prior to the operation.
 553  *
 554  * Note: Currently, this monitor is traversed only when an FS is mounted
 555  * non-nbmand.  (When the FS is mounted nbmand, share reservation checking
 556  * will detect a share violation and return an error prior to the VOP layer
 557  * being reached.)  Thus, for nbmand NFS and local renames and removes,
 558  * an existing oplock is never broken prior to share checking (contrary to
 559  * how it is with intra-CIFS remove and rename requests).
 560  */
 561 
 562 static int
 563 smb_fem_oplock_vnevent(
 564     femarg_t            *arg,
 565     vnevent_t           vnevent,
 566     vnode_t             *dvp,
 567     char                *name,
 568     caller_context_t    *ct)
 569 {
 570         uint32_t        flags;

 571         int             rc = 0;
 572 
 573         if (ct != &smb_ct) {



 574                 switch (vnevent) {
 575                 case VE_REMOVE:
 576                 case VE_PRE_RENAME_DEST:
 577                 case VE_RENAME_DEST:
 578                         flags = SMB_OPLOCK_BREAK_TO_NONE |
 579                             SMB_OPLOCK_BREAK_BATCH;
 580                         rc = smb_fem_oplock_break(arg, ct, flags);
 581                         break;
 582                 case VE_PRE_RENAME_SRC:
 583                 case VE_RENAME_SRC:
 584                         flags = SMB_OPLOCK_BREAK_TO_LEVEL_II |
 585                             SMB_OPLOCK_BREAK_BATCH;
 586                         rc = smb_fem_oplock_break(arg, ct, flags);
 587                         break;
 588                 default:
 589                         rc = 0;
 590                         break;
 591                 }




 592         }
 593         if (rc == 0)
 594                 rc = vnext_vnevent(arg, vnevent, dvp, name, ct);
 595 
 596         return (rc);
 597 }
 598 


 599 static int
 600 smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct, uint32_t flags)
 601 {
 602         smb_node_t      *node;
 603         int             rc;
 604 
 605         node = (smb_node_t *)((arg)->fa_fnode->fn_available);
 606         SMB_NODE_VALID(node);
 607 
 608         ASSERT(ct != &smb_ct);
 609 
 610         if (ct && (ct->cc_flags & CC_DONTBLOCK)) {
 611                 flags |= SMB_OPLOCK_BREAK_NOWAIT;
 612                 rc = smb_oplock_break(NULL, node, flags);
 613                 if (rc == EAGAIN)
 614                         ct->cc_flags |= CC_WOULDBLOCK;

 615         } else {
 616                 rc = smb_oplock_break(NULL, node, flags);


 617         }
 618 
 619         return (rc);
 620 }


   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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright 2015 Joyent, Inc.
  25  */
  26 
  27 #include <smbsrv/smb_kproto.h>
  28 #include <smbsrv/smb_fsops.h>
  29 #include <sys/sdt.h>
  30 #include <sys/fcntl.h>
  31 #include <sys/vfs.h>
  32 #include <sys/vfs_opreg.h>
  33 #include <sys/vnode.h>
  34 #include <sys/fem.h>
  35 
  36 extern caller_context_t smb_ct;
  37 
  38 static boolean_t        smb_fem_initialized = B_FALSE;
  39 static fem_t            *smb_fcn_ops = NULL;
  40 static fem_t            *smb_oplock_ops = NULL;
  41 
  42 /*
  43  * Declarations for FCN (file change notification) FEM monitors


  64         VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename},
  65         VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir},
  66         VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir},
  67         VOPNAME_LINK, {.femop_link = smb_fem_fcn_link},
  68         VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink},
  69         NULL, NULL
  70 };
  71 
  72 /*
  73  * Declarations for oplock FEM monitors
  74  */
  75 
  76 static int smb_fem_oplock_open(femarg_t *, int, cred_t *,
  77     struct caller_context *);
  78 static int smb_fem_oplock_read(femarg_t *, uio_t *, int, cred_t *,
  79     struct caller_context *);
  80 static int smb_fem_oplock_write(femarg_t *, uio_t *, int, cred_t *,
  81     struct caller_context *);
  82 static int smb_fem_oplock_setattr(femarg_t *, vattr_t *, int, cred_t *,
  83     caller_context_t *);

  84 static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int,
  85     offset_t, cred_t *, caller_context_t *);
  86 static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *,
  87     caller_context_t *);
  88 
  89 static const fs_operation_def_t smb_oplock_tmpl[] = {
  90         VOPNAME_OPEN,   { .femop_open = smb_fem_oplock_open },
  91         VOPNAME_READ,   { .femop_read = smb_fem_oplock_read },
  92         VOPNAME_WRITE,  { .femop_write = smb_fem_oplock_write },
  93         VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr },

  94         VOPNAME_SPACE,  { .femop_space = smb_fem_oplock_space },
  95         VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent },
  96         NULL, NULL
  97 };
  98 
  99 static int smb_fem_oplock_wait(smb_node_t *, caller_context_t *);
 100 
 101 /*
 102  * smb_fem_init
 103  *
 104  * This function is not multi-thread safe. The caller must make sure only one
 105  * thread makes the call.
 106  */
 107 int
 108 smb_fem_init(void)
 109 {
 110         int     rc = 0;
 111 
 112         if (smb_fem_initialized)
 113                 return (0);
 114 
 115         rc = fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops);
 116         if (rc)
 117                 return (rc);
 118 
 119         rc = fem_create("smb_oplock_ops", smb_oplock_tmpl,


 136  * This function is not multi-thread safe. The caller must make sure only one
 137  * thread makes the call.
 138  */
 139 void
 140 smb_fem_fini(void)
 141 {
 142         if (!smb_fem_initialized)
 143                 return;
 144 
 145         if (smb_fcn_ops != NULL) {
 146                 fem_free(smb_fcn_ops);
 147                 smb_fcn_ops = NULL;
 148         }
 149         if (smb_oplock_ops != NULL) {
 150                 fem_free(smb_oplock_ops);
 151                 smb_oplock_ops = NULL;
 152         }
 153         smb_fem_initialized = B_FALSE;
 154 }
 155 
 156 /*
 157  * Install our fem hooks for change notify.
 158  * Not using hold/rele function here because we
 159  * remove the fem hooks before node destroy.
 160  */
 161 int
 162 smb_fem_fcn_install(smb_node_t *node)
 163 {
 164         int rc;
 165 
 166         if (smb_fcn_ops == NULL)
 167                 return (ENOSYS);
 168         rc = fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ,
 169             NULL, NULL);
 170         return (rc);
 171 }
 172 
 173 void
 174 smb_fem_fcn_uninstall(smb_node_t *node)
 175 {
 176         if (smb_fcn_ops == NULL)
 177                 return;
 178         VERIFY0(fem_uninstall(node->vp, smb_fcn_ops, (void *)node));
 179 }
 180 
 181 int
 182 smb_fem_oplock_install(smb_node_t *node)
 183 {
 184         int rc;
 185 
 186         if (smb_oplock_ops == NULL)
 187                 return (ENOSYS);
 188         rc = fem_install(node->vp, smb_oplock_ops, (void *)node, OPARGUNIQ,
 189             (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);


 409         if (error == 0 && ct != &smb_ct)
 410                 smb_node_notify_change(dnode, FILE_ACTION_ADDED, linkname);
 411 
 412         return (error);
 413 }
 414 
 415 /*
 416  * FEM oplock monitors
 417  *
 418  * The monitors below are not intended to intercept CIFS calls.
 419  * CIFS higher-level routines will break oplocks as needed prior
 420  * to getting to the VFS layer.
 421  */
 422 static int
 423 smb_fem_oplock_open(
 424     femarg_t            *arg,
 425     int                 mode,
 426     cred_t              *cr,
 427     caller_context_t    *ct)
 428 {
 429         smb_node_t      *node;
 430         uint32_t        status;
 431         int             rc = 0;
 432 
 433         if (ct != &smb_ct) {
 434                 uint32_t req_acc = FILE_READ_DATA;
 435                 uint32_t cr_disp = FILE_OPEN_IF;
 436 
 437                 node = (smb_node_t *)(arg->fa_fnode->fn_available);
 438                 SMB_NODE_VALID(node);
 439 
 440                 /*
 441                  * Get req_acc, cr_disp just accurate enough so
 442                  * the oplock break call does the right thing.
 443                  */
 444                 if (mode & FWRITE) {
 445                         req_acc = FILE_READ_DATA | FILE_WRITE_DATA;
 446                         cr_disp = (mode & FTRUNC) ?
 447                             FILE_OVERWRITE_IF : FILE_OPEN_IF;
 448                 } else {
 449                         req_acc = FILE_READ_DATA;
 450                         cr_disp = FILE_OPEN_IF;
 451                 }
 452 
 453                 status = smb_oplock_break_OPEN(node, NULL,
 454                     req_acc, cr_disp);
 455                 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
 456                         rc = smb_fem_oplock_wait(node, ct);
 457                 else if (status != 0)
 458                         rc = EIO;
 459         }
 460         if (rc == 0)
 461                 rc = vnext_open(arg, mode, cr, ct);
 462 
 463         return (rc);
 464 }
 465 
 466 /*
 467  * Should normally be hit only via NFSv2/v3.  All other accesses
 468  * (CIFS/NFS/local) should call VOP_OPEN first.
 469  */
 470 
 471 static int
 472 smb_fem_oplock_read(
 473     femarg_t            *arg,
 474     uio_t               *uiop,
 475     int                 ioflag,
 476     cred_t              *cr,
 477     caller_context_t    *ct)
 478 {
 479         smb_node_t      *node;
 480         uint32_t        status;
 481         int     rc = 0;
 482 
 483         if (ct != &smb_ct) {
 484                 node = (smb_node_t *)(arg->fa_fnode->fn_available);
 485                 SMB_NODE_VALID(node);
 486 
 487                 status = smb_oplock_break_READ(node, NULL);
 488                 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
 489                         rc = smb_fem_oplock_wait(node, ct);
 490                 else if (status != 0)
 491                         rc = EIO;
 492         }
 493         if (rc == 0)
 494                 rc = vnext_read(arg, uiop, ioflag, cr, ct);
 495 
 496         return (rc);
 497 }
 498 
 499 /*
 500  * Should normally be hit only via NFSv2/v3.  All other accesses
 501  * (CIFS/NFS/local) should call VOP_OPEN first.
 502  */
 503 
 504 static int
 505 smb_fem_oplock_write(
 506     femarg_t            *arg,
 507     uio_t               *uiop,
 508     int                 ioflag,
 509     cred_t              *cr,
 510     caller_context_t    *ct)
 511 {
 512         smb_node_t      *node;
 513         uint32_t        status;
 514         int     rc = 0;
 515 
 516         if (ct != &smb_ct) {
 517                 node = (smb_node_t *)(arg->fa_fnode->fn_available);
 518                 SMB_NODE_VALID(node);
 519 
 520                 status = smb_oplock_break_WRITE(node, NULL);
 521                 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
 522                         rc = smb_fem_oplock_wait(node, ct);
 523                 else if (status != 0)
 524                         rc = EIO;
 525         }
 526         if (rc == 0)
 527                 rc = vnext_write(arg, uiop, ioflag, cr, ct);
 528 
 529         return (rc);
 530 }
 531 
 532 static int
 533 smb_fem_oplock_setattr(
 534     femarg_t            *arg,
 535     vattr_t             *vap,
 536     int                 flags,
 537     cred_t              *cr,
 538     caller_context_t    *ct)
 539 {
 540         smb_node_t      *node;
 541         uint32_t        status;
 542         int     rc = 0;
 543 
 544         if (ct != &smb_ct && (vap->va_mask & AT_SIZE) != 0) {
 545                 node = (smb_node_t *)(arg->fa_fnode->fn_available);
 546                 SMB_NODE_VALID(node);



 547 
 548                 status = smb_oplock_break_SETINFO(node, NULL,
 549                     FileEndOfFileInformation);
 550                 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
 551                         rc = smb_fem_oplock_wait(node, ct);
 552                 else if (status != 0)
 553                         rc = EIO;









 554         }
 555         if (rc == 0)
 556                 rc = vnext_setattr(arg, vap, flags, cr, ct);

 557         return (rc);
 558 }
 559 
 560 static int
 561 smb_fem_oplock_space(
 562     femarg_t            *arg,
 563     int                 cmd,
 564     flock64_t           *bfp,
 565     int                 flag,
 566     offset_t            offset,
 567     cred_t              *cr,
 568     caller_context_t    *ct)
 569 {
 570         smb_node_t      *node;
 571         uint32_t        status;
 572         int     rc = 0;
 573 
 574         if (ct != &smb_ct) {
 575                 node = (smb_node_t *)(arg->fa_fnode->fn_available);
 576                 SMB_NODE_VALID(node);
 577 
 578                 status = smb_oplock_break_SETINFO(node, NULL,
 579                     FileAllocationInformation);
 580                 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
 581                         rc = smb_fem_oplock_wait(node, ct);
 582                 else if (status != 0)
 583                         rc = EIO;
 584         }
 585         if (rc == 0)
 586                 rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct);
 587         return (rc);
 588 }
 589 
 590 /*
 591  * smb_fem_oplock_vnevent()
 592  *
 593  * To intercept NFS and local renames and removes in order to break any
 594  * existing oplock prior to the operation.
 595  *
 596  * Note: Currently, this monitor is traversed only when an FS is mounted
 597  * non-nbmand.  (When the FS is mounted nbmand, share reservation checking
 598  * will detect a share violation and return an error prior to the VOP layer
 599  * being reached.)  Thus, for nbmand NFS and local renames and removes,
 600  * an existing oplock is never broken prior to share checking (contrary to
 601  * how it is with intra-CIFS remove and rename requests).
 602  */
 603 
 604 static int
 605 smb_fem_oplock_vnevent(
 606     femarg_t            *arg,
 607     vnevent_t           vnevent,
 608     vnode_t             *dvp,
 609     char                *name,
 610     caller_context_t    *ct)
 611 {
 612         smb_node_t      *node;
 613         uint32_t        status;
 614         int             rc = 0;
 615 
 616         if (ct != &smb_ct) {
 617                 node = (smb_node_t *)(arg->fa_fnode->fn_available);
 618                 SMB_NODE_VALID(node);
 619 
 620                 switch (vnevent) {
 621                 case VE_REMOVE:
 622                 case VE_PRE_RENAME_DEST:
 623                 case VE_RENAME_DEST:
 624                         status = smb_oplock_break_HANDLE(node, NULL);


 625                         break;
 626                 case VE_PRE_RENAME_SRC:
 627                 case VE_RENAME_SRC:
 628                         status = smb_oplock_break_SETINFO(node, NULL,
 629                             FileRenameInformation);

 630                         break;
 631                 default:
 632                         status = 0;
 633                         break;
 634                 }
 635                 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
 636                         rc = smb_fem_oplock_wait(node, ct);
 637                 else if (status != 0)
 638                         rc = EIO;
 639         }
 640         if (rc == 0)
 641                 rc = vnext_vnevent(arg, vnevent, dvp, name, ct);
 642 
 643         return (rc);
 644 }
 645 
 646 int smb_fem_oplock_timeout = 5000; /* mSec. */
 647 
 648 static int
 649 smb_fem_oplock_wait(smb_node_t *node, caller_context_t *ct)
 650 {
 651         int             rc = 0;

 652 



 653         ASSERT(ct != &smb_ct);
 654 
 655         if (ct && (ct->cc_flags & CC_DONTBLOCK)) {



 656                 ct->cc_flags |= CC_WOULDBLOCK;
 657                 rc = EAGAIN;
 658         } else {
 659                 (void) smb_oplock_wait_break(node,
 660                     smb_fem_oplock_timeout);
 661                 rc = 0;
 662         }
 663 
 664         return (rc);
 665 }