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

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbsrv/smb_fem.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_fem.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23      - * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
       23 + * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  24   24   * Copyright 2015 Joyent, Inc.
  25   25   */
  26   26  
  27   27  #include <smbsrv/smb_kproto.h>
  28   28  #include <smbsrv/smb_fsops.h>
  29   29  #include <sys/sdt.h>
  30   30  #include <sys/fcntl.h>
  31   31  #include <sys/vfs.h>
  32   32  #include <sys/vfs_opreg.h>
  33   33  #include <sys/vnode.h>
↓ open down ↓ 40 lines elided ↑ open up ↑
  74   74   */
  75   75  
  76   76  static int smb_fem_oplock_open(femarg_t *, int, cred_t *,
  77   77      struct caller_context *);
  78   78  static int smb_fem_oplock_read(femarg_t *, uio_t *, int, cred_t *,
  79   79      struct caller_context *);
  80   80  static int smb_fem_oplock_write(femarg_t *, uio_t *, int, cred_t *,
  81   81      struct caller_context *);
  82   82  static int smb_fem_oplock_setattr(femarg_t *, vattr_t *, int, cred_t *,
  83   83      caller_context_t *);
  84      -static int smb_fem_oplock_rwlock(femarg_t *, int, caller_context_t *);
  85   84  static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int,
  86   85      offset_t, cred_t *, caller_context_t *);
  87   86  static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *,
  88   87      caller_context_t *);
  89   88  
  90   89  static const fs_operation_def_t smb_oplock_tmpl[] = {
  91   90          VOPNAME_OPEN,   { .femop_open = smb_fem_oplock_open },
  92   91          VOPNAME_READ,   { .femop_read = smb_fem_oplock_read },
  93   92          VOPNAME_WRITE,  { .femop_write = smb_fem_oplock_write },
  94   93          VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr },
  95      -        VOPNAME_RWLOCK, { .femop_rwlock = smb_fem_oplock_rwlock },
  96   94          VOPNAME_SPACE,  { .femop_space = smb_fem_oplock_space },
  97   95          VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent },
  98   96          NULL, NULL
  99   97  };
 100   98  
 101      -static int smb_fem_oplock_break(femarg_t *, caller_context_t *, uint32_t);
       99 +static int smb_fem_oplock_wait(smb_node_t *, caller_context_t *);
 102  100  
 103  101  /*
 104  102   * smb_fem_init
 105  103   *
 106  104   * This function is not multi-thread safe. The caller must make sure only one
 107  105   * thread makes the call.
 108  106   */
 109  107  int
 110  108  smb_fem_init(void)
 111  109  {
↓ open down ↓ 36 lines elided ↑ open up ↑
 148  146                  fem_free(smb_fcn_ops);
 149  147                  smb_fcn_ops = NULL;
 150  148          }
 151  149          if (smb_oplock_ops != NULL) {
 152  150                  fem_free(smb_oplock_ops);
 153  151                  smb_oplock_ops = NULL;
 154  152          }
 155  153          smb_fem_initialized = B_FALSE;
 156  154  }
 157  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 + */
 158  161  int
 159  162  smb_fem_fcn_install(smb_node_t *node)
 160  163  {
 161  164          int rc;
 162  165  
 163  166          if (smb_fcn_ops == NULL)
 164  167                  return (ENOSYS);
 165  168          rc = fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ,
 166      -            (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
      169 +            NULL, NULL);
 167  170          return (rc);
 168  171  }
 169  172  
 170  173  void
 171  174  smb_fem_fcn_uninstall(smb_node_t *node)
 172  175  {
 173  176          if (smb_fcn_ops == NULL)
 174  177                  return;
 175  178          VERIFY0(fem_uninstall(node->vp, smb_fcn_ops, (void *)node));
 176  179  }
↓ open down ↓ 239 lines elided ↑ open up ↑
 416  419   * CIFS higher-level routines will break oplocks as needed prior
 417  420   * to getting to the VFS layer.
 418  421   */
 419  422  static int
 420  423  smb_fem_oplock_open(
 421  424      femarg_t            *arg,
 422  425      int                 mode,
 423  426      cred_t              *cr,
 424  427      caller_context_t    *ct)
 425  428  {
 426      -        uint32_t        flags;
      429 +        smb_node_t      *node;
      430 +        uint32_t        status;
 427  431          int             rc = 0;
 428  432  
 429  433          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);
      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;
 435  459          }
 436  460          if (rc == 0)
 437  461                  rc = vnext_open(arg, mode, cr, ct);
 438  462  
 439  463          return (rc);
 440  464  }
 441  465  
 442  466  /*
 443  467   * Should normally be hit only via NFSv2/v3.  All other accesses
 444  468   * (CIFS/NFS/local) should call VOP_OPEN first.
 445  469   */
 446  470  
 447  471  static int
 448  472  smb_fem_oplock_read(
 449  473      femarg_t            *arg,
 450  474      uio_t               *uiop,
 451  475      int                 ioflag,
 452  476      cred_t              *cr,
 453  477      caller_context_t    *ct)
 454  478  {
      479 +        smb_node_t      *node;
      480 +        uint32_t        status;
 455  481          int     rc = 0;
 456  482  
 457  483          if (ct != &smb_ct) {
 458      -                rc = smb_fem_oplock_break(arg, ct,
 459      -                    SMB_OPLOCK_BREAK_TO_LEVEL_II);
      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;
 460  492          }
 461  493          if (rc == 0)
 462  494                  rc = vnext_read(arg, uiop, ioflag, cr, ct);
 463  495  
 464  496          return (rc);
 465  497  }
 466  498  
 467  499  /*
 468  500   * Should normally be hit only via NFSv2/v3.  All other accesses
 469  501   * (CIFS/NFS/local) should call VOP_OPEN first.
 470  502   */
 471  503  
 472  504  static int
 473  505  smb_fem_oplock_write(
 474  506      femarg_t            *arg,
 475  507      uio_t               *uiop,
 476  508      int                 ioflag,
 477  509      cred_t              *cr,
 478  510      caller_context_t    *ct)
 479  511  {
      512 +        smb_node_t      *node;
      513 +        uint32_t        status;
 480  514          int     rc = 0;
 481  515  
 482      -        if (ct != &smb_ct)
 483      -                rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
      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 +        }
 484  526          if (rc == 0)
 485  527                  rc = vnext_write(arg, uiop, ioflag, cr, ct);
 486  528  
 487  529          return (rc);
 488  530  }
 489  531  
 490  532  static int
 491  533  smb_fem_oplock_setattr(
 492  534      femarg_t            *arg,
 493  535      vattr_t             *vap,
 494  536      int                 flags,
 495  537      cred_t              *cr,
 496  538      caller_context_t    *ct)
 497  539  {
      540 +        smb_node_t      *node;
      541 +        uint32_t        status;
 498  542          int     rc = 0;
 499  543  
 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      -}
      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);
 506  547  
 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);
      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;
 522  554          }
 523  555          if (rc == 0)
 524      -                rc = vnext_rwlock(arg, write_lock, ct);
 525      -
      556 +                rc = vnext_setattr(arg, vap, flags, cr, ct);
 526  557          return (rc);
 527  558  }
 528  559  
 529  560  static int
 530  561  smb_fem_oplock_space(
 531  562      femarg_t            *arg,
 532  563      int                 cmd,
 533  564      flock64_t           *bfp,
 534  565      int                 flag,
 535  566      offset_t            offset,
 536  567      cred_t              *cr,
 537  568      caller_context_t    *ct)
 538  569  {
      570 +        smb_node_t      *node;
      571 +        uint32_t        status;
 539  572          int     rc = 0;
 540  573  
 541      -        if (ct != &smb_ct)
 542      -                rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
      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 +        }
 543  585          if (rc == 0)
 544  586                  rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct);
 545  587          return (rc);
 546  588  }
 547  589  
 548  590  /*
 549  591   * smb_fem_oplock_vnevent()
 550  592   *
 551  593   * To intercept NFS and local renames and removes in order to break any
 552  594   * existing oplock prior to the operation.
↓ open down ↓ 7 lines elided ↑ open up ↑
 560  602   */
 561  603  
 562  604  static int
 563  605  smb_fem_oplock_vnevent(
 564  606      femarg_t            *arg,
 565  607      vnevent_t           vnevent,
 566  608      vnode_t             *dvp,
 567  609      char                *name,
 568  610      caller_context_t    *ct)
 569  611  {
 570      -        uint32_t        flags;
      612 +        smb_node_t      *node;
      613 +        uint32_t        status;
 571  614          int             rc = 0;
 572  615  
 573  616          if (ct != &smb_ct) {
      617 +                node = (smb_node_t *)(arg->fa_fnode->fn_available);
      618 +                SMB_NODE_VALID(node);
      619 +
 574  620                  switch (vnevent) {
 575  621                  case VE_REMOVE:
 576  622                  case VE_PRE_RENAME_DEST:
 577  623                  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);
      624 +                        status = smb_oplock_break_HANDLE(node, NULL);
 581  625                          break;
 582  626                  case VE_PRE_RENAME_SRC:
 583  627                  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);
      628 +                        status = smb_oplock_break_SETINFO(node, NULL,
      629 +                            FileRenameInformation);
 587  630                          break;
 588  631                  default:
 589      -                        rc = 0;
      632 +                        status = 0;
 590  633                          break;
 591  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;
 592  639          }
 593  640          if (rc == 0)
 594  641                  rc = vnext_vnevent(arg, vnevent, dvp, name, ct);
 595  642  
 596  643          return (rc);
 597  644  }
 598  645  
      646 +int smb_fem_oplock_timeout = 5000; /* mSec. */
      647 +
 599  648  static int
 600      -smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct, uint32_t flags)
      649 +smb_fem_oplock_wait(smb_node_t *node, caller_context_t *ct)
 601  650  {
 602      -        smb_node_t      *node;
 603      -        int             rc;
      651 +        int             rc = 0;
 604  652  
 605      -        node = (smb_node_t *)((arg)->fa_fnode->fn_available);
 606      -        SMB_NODE_VALID(node);
 607      -
 608  653          ASSERT(ct != &smb_ct);
 609  654  
 610  655          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;
      656 +                ct->cc_flags |= CC_WOULDBLOCK;
      657 +                rc = EAGAIN;
 615  658          } else {
 616      -                rc = smb_oplock_break(NULL, node, flags);
      659 +                (void) smb_oplock_wait_break(node,
      660 +                    smb_fem_oplock_timeout);
      661 +                rc = 0;
 617  662          }
 618  663  
 619  664          return (rc);
 620  665  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX