Print this page
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-6041 Should pass the smbtorture lock tests
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-3553 SMB2/3 durable handles
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-5555 smb locks don't need l_uid or l_session_kid
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-5537 Want reference counts for users, trees...
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-5314 SMB server may wait for oplock break ack on disconnected session
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-2516 Need a way to disable exclusive oplocks
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-74 Process oplock breaks as session requests (part two)
SMB-74 Process oplock breaks as session requests
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
SMB-64 smbsrv workers run at excessively high priority
SUP-599 smb_oplock_acquire thread deadlock

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbsrv/smb_oplock.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_oplock.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 2014 Nexenta Systems, Inc.  All rights reserved.
       23 + * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  
  26   26  /*
  27      - * smb_oplock_wait / smb_oplock_broadcast
  28      - * When an oplock is being acquired, we must ensure that the acquisition
  29      - * response is submitted to the network stack before any other operation
  30      - * is permitted on the oplock.
  31      - * In smb_oplock_acquire, oplock.ol_xthread is set to point to the worker
  32      - * thread processing the command that is granting the oplock.
  33      - * Other threads accessing the oplock will be suspended in smb_oplock_wait().
  34      - * They will be awakened when the worker thread referenced in 'ol_xthread'
  35      - * calls smb_oplock_broadcast().
  36      - *
  37      - * The purpose of this mechanism is to prevent another thread from
  38      - * triggering an oplock break before the response conveying the grant
  39      - * has been sent.
       27 + * smb1 oplock support
  40   28   */
  41   29  
  42   30  #include <smbsrv/smb_kproto.h>
  43      -#include <sys/nbmlock.h>
  44   31  
  45      -#define SMB_OPLOCK_IS_EXCLUSIVE(level)          \
  46      -        (((level) == SMB_OPLOCK_EXCLUSIVE) ||   \
  47      -        ((level) == SMB_OPLOCK_BATCH))
       32 +#define BATCH_OR_EXCL   (OPLOCK_LEVEL_BATCH | OPLOCK_LEVEL_ONE)
  48   33  
  49      -static int smb_oplock_install_fem(smb_node_t *);
  50      -static void smb_oplock_uninstall_fem(smb_node_t *);
  51      -
  52      -static void smb_oplock_wait(smb_node_t *);
  53      -static void smb_oplock_wait_ack(smb_node_t *, uint32_t);
  54      -static void smb_oplock_timedout(smb_node_t *);
  55      -
  56      -static smb_oplock_grant_t *smb_oplock_set_grant(smb_ofile_t *, uint8_t);
  57      -void smb_oplock_clear_grant(smb_oplock_grant_t *);
  58      -static int smb_oplock_insert_grant(smb_node_t *, smb_oplock_grant_t *);
  59      -static void smb_oplock_remove_grant(smb_node_t *, smb_oplock_grant_t *);
  60      -static smb_oplock_grant_t *smb_oplock_exclusive_grant(list_t *);
  61      -static smb_oplock_grant_t *smb_oplock_get_grant(smb_oplock_t *, smb_ofile_t *);
  62      -
  63      -static void smb_oplock_sched_async_break(smb_oplock_grant_t *, uint8_t);
  64      -static void smb_oplock_exec_async_break(void *);
  65      -static void smb_oplock_break_levelII_locked(smb_node_t *);
  66      -
  67   34  /*
  68      - * smb_oplock_install_fem
  69      - * Install fem monitor for cross protocol oplock breaking.
       35 + * Client has an open handle and requests an oplock.
       36 + * Convert SMB1 oplock request info in to internal form,
       37 + * call common oplock code, convert result to SMB1.
  70   38   */
  71      -static int
  72      -smb_oplock_install_fem(smb_node_t *node)
  73      -{
  74      -        ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
  75      -
  76      -        if (node->n_oplock.ol_fem == B_FALSE) {
  77      -                if (smb_fem_oplock_install(node) != 0) {
  78      -                        cmn_err(CE_NOTE, "No oplock granted: "
  79      -                            "failed to install fem monitor %s",
  80      -                            node->vp->v_path);
  81      -                        return (-1);
  82      -                }
  83      -                node->n_oplock.ol_fem = B_TRUE;
  84      -        }
  85      -        return (0);
  86      -}
  87      -
  88      -/*
  89      - * smb_oplock_uninstall_fem
  90      - * Uninstall fem monitor for cross protocol oplock breaking.
  91      - */
  92      -static void
  93      -smb_oplock_uninstall_fem(smb_node_t *node)
  94      -{
  95      -        ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
  96      -
  97      -        if (node->n_oplock.ol_fem) {
  98      -                smb_fem_oplock_uninstall(node);
  99      -                node->n_oplock.ol_fem = B_FALSE;
 100      -        }
 101      -}
 102      -
 103      -/*
 104      - * This provides a way to fully disable oplocks, i.e. for testing.
 105      - * You _really_ do _not_ want to turn this off, because if you do,
 106      - * the clients send you very small read requests, and a _lot_ more
 107      - * of them.  The skc_oplock_enable parameter can be used to enable
 108      - * or disable exclusive oplocks.  Disabling that can be helpful
 109      - * when there are clients not responding to oplock breaks.
 110      - */
 111      -int smb_oplocks_enabled = 1;
 112      -
 113      -/*
 114      - * smb_oplock_acquire
 115      - *
 116      - * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH,
 117      - * but might only be granted LEVEL_II or NONE.
 118      - *
 119      - * If oplocks are not supported on the tree, or node, grant NONE.
 120      - * If nobody else has the file open, grant the requested level.
 121      - * If any of the following are true, grant NONE:
 122      - * - there is an exclusive oplock on the node
 123      - * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd.
 124      - * - LEVEL_II oplocks are not supported for the session
 125      - * - a BATCH oplock is requested on a named stream
 126      - * - there are any range locks on the node (SMB writers)
 127      - * Otherwise, grant LEVEL_II.
 128      - *
 129      - * ol->ol_xthread is set to the current thread to lock the oplock against
 130      - * other operations until the acquire response is on the wire. When the
 131      - * acquire response is on the wire, smb_oplock_broadcast() is called to
 132      - * reset ol->ol_xthread and wake any waiting threads.
 133      - */
 134   39  void
 135      -smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile)
       40 +smb1_oplock_acquire(smb_request_t *sr, boolean_t level2ok)
 136   41  {
 137      -        smb_oplock_t            *ol;
 138      -        smb_oplock_grant_t      *og;
 139      -        list_t                  *grants;
 140      -        smb_arg_open_t          *op;
 141      -        smb_tree_t              *tree;
 142      -        smb_session_t           *session;
       42 +        smb_arg_open_t *op = &sr->arg.open;
       43 +        smb_ofile_t *ofile = sr->fid_ofile;
       44 +        uint32_t status;
 143   45  
 144      -        SMB_NODE_VALID(node);
 145      -        SMB_OFILE_VALID(ofile);
 146      -
 147      -        ASSERT(node == SMB_OFILE_GET_NODE(ofile));
 148      -        ASSERT(RW_LOCK_HELD(&node->n_lock));
 149      -
 150      -        op = &sr->sr_open;
 151      -        tree = SMB_OFILE_GET_TREE(ofile);
 152      -        session = SMB_OFILE_GET_SESSION(ofile);
 153      -
 154      -        if (smb_oplocks_enabled == 0 ||
 155      -            (op->op_oplock_level == SMB_OPLOCK_NONE) ||
 156      -            ((op->op_oplock_level == SMB_OPLOCK_BATCH) &&
 157      -            SMB_IS_STREAM(node))) {
       46 +        /* Only disk trees get oplocks. */
       47 +        if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
 158   48                  op->op_oplock_level = SMB_OPLOCK_NONE;
 159   49                  return;
 160   50          }
 161   51  
 162      -        ol = &node->n_oplock;
 163      -        grants = &ol->ol_grants;
 164      -
 165      -        mutex_enter(&ol->ol_mutex);
 166      -        smb_oplock_wait(node);
 167      -
 168      -        /*
 169      -         * Even if there are no other opens, we might want to
 170      -         * grant only a Level II (shared) oplock so we avoid
 171      -         * ever granting exclusive oplocks.
 172      -         *
 173      -         * Borrowing the SMB_TREE_OPLOCKS flag to enable/disable
 174      -         * exclusive oplocks (for now).  See skc_oplock_enable,
 175      -         * which can now be taken as "exclusive oplock enable".
 176      -         * Should rename this parameter, and/or implement a new
 177      -         * multi-valued parameter for oplock enables.
 178      -         */
 179      -        if ((node->n_open_count > 1) ||
 180      -            (node->n_opening_count > 1) ||
 181      -            !smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) ||
 182      -            smb_vop_other_opens(node->vp, ofile->f_mode)) {
 183      -                /*
 184      -                 * There are other opens.
 185      -                 */
 186      -                if ((!op->op_oplock_levelII) ||
 187      -                    (!smb_session_levelII_oplocks(session)) ||
 188      -                    (smb_oplock_exclusive_grant(grants) != NULL) ||
 189      -                    (smb_lock_range_access(sr, node, 0, 0, B_FALSE))) {
 190      -                        /*
 191      -                         * LevelII (shared) oplock not allowed,
 192      -                         * so reply with "none".
 193      -                         */
 194      -                        op->op_oplock_level = SMB_OPLOCK_NONE;
 195      -                        mutex_exit(&ol->ol_mutex);
 196      -                        return;
 197      -                }
 198      -
 199      -                op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
 200      -        }
 201      -
 202      -        og = smb_oplock_set_grant(ofile, op->op_oplock_level);
 203      -        if (smb_oplock_insert_grant(node, og) != 0) {
 204      -                smb_oplock_clear_grant(og);
       52 +        if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
 205   53                  op->op_oplock_level = SMB_OPLOCK_NONE;
 206      -                mutex_exit(&ol->ol_mutex);
 207   54                  return;
 208   55          }
 209   56  
 210      -        ol->ol_xthread = curthread;
 211      -        mutex_exit(&ol->ol_mutex);
 212      -}
       57 +        if (!smb_session_levelII_oplocks(sr->session))
       58 +                level2ok = B_FALSE;
 213   59  
 214      -/*
 215      - * smb_oplock_break
 216      - *
 217      - * Break granted oplocks according to the following rules:
 218      - *
 219      - * If there's an exclusive oplock granted on the node
 220      - *  - if the BREAK_BATCH flags is specified and the oplock is not
 221      - *    a batch oplock, no break is required.
 222      - *  - if the session doesn't support LEVEL II oplocks, and 'brk' is
 223      - *    BREAK_TO_LEVEL_II, do a BREAK_TO_NONE.
 224      - *  - if the oplock is already breaking update the break level (if
 225      - *    the requested break is to a lesser level), otherwise send an
 226      - *    oplock break.
 227      - *    Wait for acknowledgement of the break (unless NOWAIT flag is set)
 228      - *
 229      - * Otherwise:
 230      - * If there are level II oplocks granted on the node, and the flags
 231      - * indicate that they should be broken (BREAK_TO_NONE specified,
 232      - * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII
 233      - * break request for asynchronous processing.
 234      - *
 235      - * Returns:
 236      - *       0 - oplock broken (or no break required)
 237      - *  EAGAIN - oplock break request sent and would block
 238      - *           awaiting the reponse but NOWAIT was specified
 239      - *
 240      - * NB: sr == NULL when called by FEM framework.
 241      - */
 242      -int
 243      -smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags)
 244      -{
 245      -        smb_oplock_t            *ol;
 246      -        smb_oplock_grant_t      *og;
 247      -        list_t                  *grants;
 248      -        uint32_t                timeout;
 249      -        uint8_t                 brk;
       60 +        /* Common code checks file type. */
 250   61  
 251      -        SMB_NODE_VALID(node);
 252      -        ol = &node->n_oplock;
 253      -        grants = &ol->ol_grants;
 254      -
 255      -        mutex_enter(&ol->ol_mutex);
 256      -        smb_oplock_wait(node);
 257      -
 258      -        og = list_head(grants);
 259      -        if (og == NULL) {
 260      -                mutex_exit(&ol->ol_mutex);
 261      -                return (0);
 262      -        }
 263      -
 264      -        SMB_OPLOCK_GRANT_VALID(og);
 265      -
 266      -        /* break levelII oplocks */
 267      -        if (og->og_level == SMB_OPLOCK_LEVEL_II) {
 268      -                mutex_exit(&ol->ol_mutex);
 269      -
 270      -                if ((flags & SMB_OPLOCK_BREAK_TO_NONE) &&
 271      -                    !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) &&
 272      -                    !(flags & SMB_OPLOCK_BREAK_BATCH))  {
 273      -                        smb_oplock_break_levelII(node);
 274      -                }
 275      -                return (0);
 276      -        }
 277      -
 278      -        /* break exclusive oplock */
 279      -        if ((flags & SMB_OPLOCK_BREAK_BATCH) &&
 280      -            (og->og_level != SMB_OPLOCK_BATCH)) {
 281      -                mutex_exit(&ol->ol_mutex);
 282      -                return (0);
 283      -        }
 284      -
 285      -        if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) &&
 286      -            smb_session_levelII_oplocks(og->og_session)) {
 287      -                brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
 288      -        } else {
 289      -                brk = SMB_OPLOCK_BREAK_TO_NONE;
 290      -        }
 291      -
 292      -        switch (ol->ol_break) {
 293      -        case SMB_OPLOCK_NO_BREAK:
 294      -                ol->ol_break = brk;
 295      -                smb_oplock_sched_async_break(og, brk);
       62 +        /*
       63 +         * SMB1: Convert to internal form.
       64 +         */
       65 +        switch (op->op_oplock_level) {
       66 +        case SMB_OPLOCK_BATCH:
       67 +                op->op_oplock_state = OPLOCK_LEVEL_BATCH;
 296   68                  break;
 297      -        case SMB_OPLOCK_BREAK_TO_LEVEL_II:
 298      -                if (brk == SMB_OPLOCK_BREAK_TO_NONE)
 299      -                        ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE;
       69 +        case SMB_OPLOCK_EXCLUSIVE:
       70 +                op->op_oplock_state = OPLOCK_LEVEL_ONE;
 300   71                  break;
 301      -        case SMB_OPLOCK_BREAK_TO_NONE:
 302      -        default:
       72 +        case SMB_OPLOCK_LEVEL_II:
       73 +                op->op_oplock_state = OPLOCK_LEVEL_TWO;
 303   74                  break;
       75 +        case SMB_OPLOCK_NONE:
       76 +        default:
       77 +                op->op_oplock_level = SMB_OPLOCK_NONE;
       78 +                return;
 304   79          }
 305   80  
 306      -        if (flags & SMB_OPLOCK_BREAK_NOWAIT) {
 307      -                mutex_exit(&ol->ol_mutex);
 308      -                return (EAGAIN);
       81 +        /*
       82 +         * Tree options may force shared oplocks
       83 +         */
       84 +        if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) {
       85 +                op->op_oplock_state = OPLOCK_LEVEL_TWO;
 309   86          }
 310   87  
 311      -        if (sr && (sr->session == og->og_session) &&
 312      -            (sr->smb_uid == og->og_uid)) {
 313      -                timeout = smb_oplock_min_timeout;
       88 +        /*
       89 +         * Try exclusive first, if requested
       90 +         */
       91 +        if ((op->op_oplock_state & BATCH_OR_EXCL) != 0) {
       92 +                status = smb_oplock_request(sr, ofile,
       93 +                    &op->op_oplock_state);
 314   94          } else {
 315      -                timeout = smb_oplock_timeout;
       95 +                status = NT_STATUS_OPLOCK_NOT_GRANTED;
 316   96          }
 317   97  
 318      -        mutex_exit(&ol->ol_mutex);
 319      -        smb_oplock_wait_ack(node, timeout);
 320      -        return (0);
 321      -}
 322      -
 323      -/*
 324      - * smb_oplock_break_levelII
 325      - *
 326      - * This is called after a file is modified in some way.  If there are
 327      - * LevelII (shared) oplocks, break those to none.  If there is an
 328      - * exclusive oplock, there can be no LevelII oplocks, so do nothing.
 329      - *
 330      - * LevelII (shared) oplock breaks are processed asynchronously.
 331      - * Unlike exclusive oplock breaks, the thread initiating the break
 332      - * is NOT blocked while the request is processed.
 333      - *
 334      - * There may be a thread with exclusive rights to oplock state for
 335      - * this node (via ol_xthread in smb_oplock_wait) and if so, we must
 336      - * avoid breaking oplocks until that's out of the way.  However, we
 337      - * really don't want to block here, so when ol_xthread is set, we'll
 338      - * just mark that a "break level II to none" is pending, and let the
 339      - * exclusive thread do this work when it's done being exclusive.
 340      - */
 341      -void
 342      -smb_oplock_break_levelII(smb_node_t *node)
 343      -{
 344      -        smb_oplock_t            *ol;
 345      -
 346      -        ol = &node->n_oplock;
 347      -        mutex_enter(&ol->ol_mutex);
 348      -
 349      -        /* Instead of: smb_oplock_wait() ... */
 350      -        if (ol->ol_xthread != NULL) {
 351      -                /* Defer the call to smb_oplock_broadcast(). */
 352      -                ol->ol_brk_pending = SMB_OPLOCK_BREAK_TO_NONE;
 353      -        } else {
 354      -                /* Equivalent of smb_oplock_wait() done. */
 355      -                smb_oplock_break_levelII_locked(node);
       98 +        /*
       99 +         * If exclusive failed (or tree forced shared oplocks)
      100 +         * and if the caller supports Level II, try shared.
      101 +         */
      102 +        if (status == NT_STATUS_OPLOCK_NOT_GRANTED && level2ok) {
      103 +                op->op_oplock_state = OPLOCK_LEVEL_TWO;
      104 +                status = smb_oplock_request(sr, ofile,
      105 +                    &op->op_oplock_state);
 356  106          }
 357  107  
 358      -        mutex_exit(&ol->ol_mutex);
 359      -}
 360      -
 361      -/*
 362      - * smb_oplock_break_levelII_locked
 363      - * Internal helper for smb_oplock_break_levelII()
 364      - *
 365      - * Called with the oplock mutex already held, and _after_
 366      - * (the equivalent of) an smb_oplock_wait().
 367      - */
 368      -static void
 369      -smb_oplock_break_levelII_locked(smb_node_t *node)
 370      -{
 371      -        smb_oplock_t            *ol;
 372      -        smb_oplock_grant_t      *og;
 373      -        list_t                  *grants;
 374      -
 375      -        ol = &node->n_oplock;
 376      -        grants = &ol->ol_grants;
 377      -
 378      -        ASSERT(MUTEX_HELD(&ol->ol_mutex));
 379      -        ASSERT(ol->ol_xthread == NULL);
 380      -
 381      -        while ((og = list_head(grants)) != NULL) {
 382      -                SMB_OPLOCK_GRANT_VALID(og);
 383      -
 384      -                /*
 385      -                 * If there's an exclusive oplock, there are
 386      -                 * no LevelII oplocks, so do nothing.
 387      -                 */
 388      -                if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
 389      -                        break;
 390      -
 391      -                smb_oplock_sched_async_break(og, SMB_OPLOCK_BREAK_TO_NONE);
 392      -                smb_oplock_remove_grant(node, og);
 393      -                smb_oplock_clear_grant(og);
      108 +        /*
      109 +         * Either of the above may have returned the
      110 +         * status code that says we should wait.
      111 +         */
      112 +        if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
      113 +                (void) smb_oplock_wait_break(ofile->f_node, 0);
      114 +                status = 0;
 394  115          }
 395      -}
 396  116  
 397      -/*
 398      - * Schedule a call to smb_session_oplock_break
 399      - * using an smb_request on the owning session.
 400      - */
 401      -static void
 402      -smb_oplock_sched_async_break(smb_oplock_grant_t *og, uint8_t brk)
 403      -{
 404      -        smb_request_t           *sr;
 405      -        smb_ofile_t             *ofile;
 406      -
 407  117          /*
 408      -         * Make sure we can get a hold on the ofile.  If we can't,
 409      -         * the file is closing, and there's no point scheduling an
 410      -         * oplock break on it.  (Also hold the tree and user.)
 411      -         * These holds account for the pointers we copy into the
 412      -         * smb_request fields: fid_ofile, tid_tree, uid_user.
 413      -         * These holds are released via smb_request_free after
 414      -         * the oplock break has been sent.
      118 +         * Keep track of what we got (in ofile->f_oplock.og_state)
      119 +         * so we'll know what we had when sending a break later.
      120 +         * The og_dialect here is the oplock dialect, which may be
      121 +         * different than SMB dialect.  Pre-NT clients did not
      122 +         * support "Level II" oplocks.  If we're talking to a
      123 +         * client that didn't set the CAP_LEVEL_II_OPLOCKS in
      124 +         * its capabilities, let og_dialect = LANMAN2_1.
 415  125           */
 416      -        ofile = og->og_ofile;
 417      -        if (!smb_ofile_hold(ofile))
      126 +        ofile->f_oplock.og_dialect = (level2ok) ?
      127 +            NT_LM_0_12 : LANMAN2_1;
      128 +        switch (status) {
      129 +        case NT_STATUS_SUCCESS:
      130 +                ofile->f_oplock.og_state = op->op_oplock_state;
      131 +                break;
      132 +        case NT_STATUS_OPLOCK_NOT_GRANTED:
      133 +                ofile->f_oplock.og_state = 0;
      134 +                op->op_oplock_level = SMB_OPLOCK_NONE;
 418  135                  return;
 419      -        smb_tree_hold_internal(ofile->f_tree);
 420      -        smb_user_hold_internal(ofile->f_user);
 421      -
 422      -        sr = smb_request_alloc(og->og_session, 0);
 423      -        sr->sr_state = SMB_REQ_STATE_SUBMITTED;
 424      -        sr->user_cr = zone_kcred();
 425      -        sr->fid_ofile = ofile;
 426      -        sr->tid_tree = ofile->f_tree;
 427      -        sr->uid_user = ofile->f_user;
 428      -
 429      -        sr->arg.olbrk = *og; /* struct copy */
 430      -        sr->arg.olbrk.og_breaking = brk;
 431      -
 432      -        (void) taskq_dispatch(
 433      -            sr->sr_server->sv_worker_pool,
 434      -            smb_oplock_exec_async_break, sr, TQ_SLEEP);
 435      -}
 436      -
 437      -/*
 438      - * smb_oplock_exec_async_break
 439      - *
 440      - * Called via the taskq to handle an asynchronous oplock break.
 441      - * We have a hold on the ofile, which keeps the FID here valid.
 442      - */
 443      -static void
 444      -smb_oplock_exec_async_break(void *arg)
 445      -{
 446      -        smb_request_t *sr = arg;
 447      -        smb_oplock_grant_t *og = &sr->arg.olbrk;
 448      -
 449      -        SMB_REQ_VALID(sr);
 450      -        SMB_OPLOCK_GRANT_VALID(og);
 451      -
 452      -        mutex_enter(&sr->sr_mutex);
 453      -        sr->sr_worker = curthread;
 454      -        sr->sr_time_active = gethrtime();
 455      -
 456      -        switch (sr->sr_state) {
 457      -        case SMB_REQ_STATE_SUBMITTED:
 458      -                sr->sr_state = SMB_REQ_STATE_ACTIVE;
 459      -                mutex_exit(&sr->sr_mutex);
 460      -
 461      -                /*
 462      -                 * This is where we actually do the deferred work
 463      -                 * requested by smb_oplock_sched_async_break().
 464      -                 */
 465      -                smb_session_oplock_break(sr, og->og_breaking);
 466      -
 467      -                mutex_enter(&sr->sr_mutex);
 468      -                /* FALLTHROUGH */
 469      -
 470      -        default: /* typically cancelled */
 471      -                sr->sr_state = SMB_REQ_STATE_COMPLETED;
 472      -                mutex_exit(&sr->sr_mutex);
 473      -        }
 474      -
 475      -        smb_request_free(sr);
 476      -}
 477      -
 478      -/*
 479      - * smb_oplock_wait_ack
 480      - *
 481      - * Timed wait for an oplock break acknowledgement (or oplock release).
 482      - */
 483      -static void
 484      -smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout)
 485      -{
 486      -        smb_oplock_t    *ol;
 487      -        clock_t         time;
 488      -
 489      -        ol = &node->n_oplock;
 490      -        mutex_enter(&ol->ol_mutex);
 491      -        time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
 492      -
 493      -        while (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
 494      -                if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) {
 495      -                        smb_oplock_timedout(node);
 496      -                        cv_broadcast(&ol->ol_cv);
 497      -                        break;
 498      -                }
 499      -        }
 500      -        mutex_exit(&ol->ol_mutex);
 501      -}
 502      -
 503      -/*
 504      - * smb_oplock_timedout
 505      - *
 506      - * An oplock break has not been acknowledged within timeout
 507      - * 'smb_oplock_timeout'.
 508      - * Set oplock grant to the desired break level.
 509      - */
 510      -static void
 511      -smb_oplock_timedout(smb_node_t *node)
 512      -{
 513      -        smb_oplock_t            *ol;
 514      -        smb_oplock_grant_t      *og;
 515      -        list_t                  *grants;
 516      -
 517      -        ol = &node->n_oplock;
 518      -        grants = &ol->ol_grants;
 519      -
 520      -        ASSERT(MUTEX_HELD(&ol->ol_mutex));
 521      -
 522      -        og = smb_oplock_exclusive_grant(grants);
 523      -        if (og) {
 524      -                switch (ol->ol_break) {
 525      -                case SMB_OPLOCK_BREAK_TO_NONE:
 526      -                        og->og_level = SMB_OPLOCK_NONE;
 527      -                        smb_oplock_remove_grant(node, og);
 528      -                        smb_oplock_clear_grant(og);
 529      -                        break;
 530      -                case SMB_OPLOCK_BREAK_TO_LEVEL_II:
 531      -                        og->og_level = SMB_OPLOCK_LEVEL_II;
 532      -                        break;
 533      -                default:
 534      -                        SMB_PANIC();
 535      -                }
 536      -        }
 537      -        ol->ol_break = SMB_OPLOCK_NO_BREAK;
 538      -}
 539      -
 540      -/*
 541      - * smb_oplock_release
 542      - *
 543      - * Release the oplock granted on ofile 'of'.
 544      - * Wake any threads waiting for an oplock break acknowledgement for
 545      - * this oplock.
 546      - * This is called when the ofile is being closed.
 547      - */
 548      -void
 549      -smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
 550      -{
 551      -        smb_oplock_t            *ol;
 552      -        smb_oplock_grant_t      *og;
 553      -
 554      -        ol = &node->n_oplock;
 555      -        mutex_enter(&ol->ol_mutex);
 556      -        smb_oplock_wait(node);
 557      -
 558      -        og = smb_oplock_get_grant(ol, of);
 559      -        if (og) {
 560      -                smb_oplock_remove_grant(node, og);
 561      -                smb_oplock_clear_grant(og);
 562      -
 563      -                if (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
 564      -                        ol->ol_break = SMB_OPLOCK_NO_BREAK;
 565      -                        cv_broadcast(&ol->ol_cv);
 566      -                }
 567      -        }
 568      -
 569      -        mutex_exit(&ol->ol_mutex);
 570      -}
 571      -
 572      -/*
 573      - * smb_oplock_ack
 574      - *
 575      - * Process oplock acknowledgement received for ofile 'of'.
 576      - * - oplock.ol_break is the break level that was requested.
 577      - * - brk is the break level being acknowledged by the client.
 578      - *
 579      - * Update the oplock grant level to the lesser of ol_break and brk.
 580      - * If the grant is now SMB_OPLOCK_NONE, remove the grant from the
 581      - * oplock's grant list and delete it.
 582      - * If the requested break level (ol_break) was NONE and the brk is
 583      - * LEVEL_II, send another oplock break (NONE). Do not wait for an
 584      - * acknowledgement.
 585      - * Wake any threads waiting for the oplock break acknowledgement.
 586      - */
 587      -void
 588      -smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk)
 589      -{
 590      -        smb_oplock_t            *ol;
 591      -        smb_oplock_grant_t      *og;
 592      -
 593      -        ol = &node->n_oplock;
 594      -        mutex_enter(&ol->ol_mutex);
 595      -        smb_oplock_wait(node);
 596      -
 597      -        if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) ||
 598      -            ((og = smb_oplock_get_grant(ol, of)) == NULL)) {
 599      -                mutex_exit(&ol->ol_mutex);
      136 +        default:
      137 +                /* Caller did not check args sufficiently? */
      138 +                cmn_err(CE_NOTE, "clnt %s oplock req. err 0x%x",
      139 +                    sr->session->ip_addr_str, status);
      140 +                ofile->f_oplock.og_state = 0;
      141 +                op->op_oplock_level = SMB_OPLOCK_NONE;
 600  142                  return;
 601  143          }
 602  144  
 603      -        switch (brk) {
 604      -        case SMB_OPLOCK_BREAK_TO_NONE:
 605      -                og->og_level = SMB_OPLOCK_NONE;
 606      -                break;
 607      -        case SMB_OPLOCK_BREAK_TO_LEVEL_II:
 608      -                if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) {
 609      -                        og->og_level = SMB_OPLOCK_LEVEL_II;
 610      -                } else {
 611      -                        /* SMB_OPLOCK_BREAK_TO_NONE */
 612      -                        og->og_level = SMB_OPLOCK_NONE;
 613      -                        smb_oplock_sched_async_break(og,
 614      -                            SMB_OPLOCK_BREAK_TO_NONE);
 615      -                }
 616      -                break;
 617      -        default:
 618      -                SMB_PANIC();
      145 +        /*
      146 +         * Have STATUS_SUCCESS
      147 +         * Convert internal oplock state to SMB1
      148 +         */
      149 +        if (op->op_oplock_state & OPLOCK_LEVEL_BATCH) {
      150 +                op->op_oplock_level = SMB_OPLOCK_BATCH;
      151 +        } else if (op->op_oplock_state & OPLOCK_LEVEL_ONE) {
      152 +                op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
      153 +        } else if (op->op_oplock_state & OPLOCK_LEVEL_TWO) {
      154 +                op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
      155 +        } else {
      156 +                op->op_oplock_level = SMB_OPLOCK_NONE;
 619  157          }
 620      -
 621      -        if (og->og_level == SMB_OPLOCK_NONE) {
 622      -                smb_oplock_remove_grant(node, og);
 623      -                smb_oplock_clear_grant(og);
 624      -        }
 625      -
 626      -        ol->ol_break = SMB_OPLOCK_NO_BREAK;
 627      -        cv_broadcast(&ol->ol_cv);
 628      -
 629      -        mutex_exit(&ol->ol_mutex);
 630      -}
 631      -
 632      -/*
 633      - * smb_oplock_broadcast
 634      - *
 635      - * Called when an open with oplock request completes.
 636      - *
 637      - * ol->ol_xthread identifies the thread that was performing an oplock
 638      - * acquire. Other threads may be blocked awaiting completion of the
 639      - * acquire.
 640      - * If the calling thread is ol_xthread, wake any waiting threads.
 641      - */
 642      -void
 643      -smb_oplock_broadcast(smb_node_t *node)
 644      -{
 645      -        smb_oplock_t    *ol;
 646      -
 647      -        SMB_NODE_VALID(node);
 648      -        ol = &node->n_oplock;
 649      -
 650      -        mutex_enter(&ol->ol_mutex);
 651      -        if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) {
 652      -                ol->ol_xthread = NULL;
 653      -                if (ol->ol_brk_pending) {
 654      -                        ol->ol_brk_pending = 0;
 655      -                        smb_oplock_break_levelII_locked(node);
 656      -                }
 657      -                cv_broadcast(&ol->ol_cv);
 658      -        }
 659      -        mutex_exit(&ol->ol_mutex);
 660      -}
 661      -
 662      -/*
 663      - * smb_oplock_wait
 664      - *
 665      - * Wait for the completion of an oplock acquire.
 666      - * If ol_xthread is not NULL and doesn't contain the pointer to the
 667      - * context of the calling thread, the caller will sleep until the
 668      - * ol_xthread is reset to NULL (via smb_oplock_broadcast()).
 669      - */
 670      -static void
 671      -smb_oplock_wait(smb_node_t *node)
 672      -{
 673      -        smb_oplock_t    *ol;
 674      -
 675      -        ol = &node->n_oplock;
 676      -        ASSERT(MUTEX_HELD(&ol->ol_mutex));
 677      -
 678      -        if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) {
 679      -                while (ol->ol_xthread != NULL)
 680      -                        cv_wait(&ol->ol_cv, &ol->ol_mutex);
 681      -        }
 682      -}
 683      -
 684      -/*
 685      - * smb_oplock_set_grant
 686      - */
 687      -static smb_oplock_grant_t *
 688      -smb_oplock_set_grant(smb_ofile_t *of, uint8_t level)
 689      -{
 690      -        smb_oplock_grant_t      *og;
 691      -
 692      -        og = &of->f_oplock_grant;
 693      -
 694      -        og->og_magic = SMB_OPLOCK_GRANT_MAGIC;
 695      -        og->og_breaking = 0;
 696      -        og->og_level = level;
 697      -        og->og_ofile = of;
 698      -        og->og_fid = of->f_fid;
 699      -        og->og_tid = of->f_tree->t_tid;
 700      -        og->og_uid = of->f_user->u_uid;
 701      -        og->og_session = of->f_session;
 702      -        return (og);
 703      -}
 704      -
 705      -/*
 706      - * smb_oplock_clear_grant
 707      - */
 708      -void
 709      -smb_oplock_clear_grant(smb_oplock_grant_t *og)
 710      -{
 711      -        bzero(og, sizeof (smb_oplock_grant_t));
 712      -}
 713      -
 714      -/*
 715      - * smb_oplock_insert_grant
 716      - *
 717      - * If there are no grants in the oplock's list install the fem
 718      - * monitor.
 719      - * Insert the grant into the list and increment the grant count.
 720      - */
 721      -static int
 722      -smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og)
 723      -{
 724      -        smb_oplock_t *ol = &node->n_oplock;
 725      -
 726      -        ASSERT(MUTEX_HELD(&ol->ol_mutex));
 727      -
 728      -        if (ol->ol_count == 0) {
 729      -                if (smb_oplock_install_fem(node) != 0)
 730      -                        return (-1);
 731      -        }
 732      -
 733      -        list_insert_tail(&ol->ol_grants, og);
 734      -        ++ol->ol_count;
 735      -        return (0);
 736      -}
 737      -
 738      -/*
 739      - * smb_oplock_remove_grant
 740      - *
 741      - * Remove the oplock grant from the list, decrement the grant count
 742      - * and, if there are no other grants in the list, uninstall the fem
 743      - * monitor.
 744      - */
 745      -static void
 746      -smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og)
 747      -{
 748      -        smb_oplock_t *ol = &node->n_oplock;
 749      -
 750      -        ASSERT(MUTEX_HELD(&ol->ol_mutex));
 751      -        ASSERT(ol->ol_count > 0);
 752      -
 753      -        list_remove(&ol->ol_grants, og);
 754      -        if (--ol->ol_count == 0)
 755      -                smb_oplock_uninstall_fem(node);
 756      -}
 757      -
 758      -/*
 759      - * smb_oplock_exclusive_grant
 760      - *
 761      - * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists,
 762      - * return it. Otherwise return NULL.
 763      - */
 764      -static smb_oplock_grant_t *
 765      -smb_oplock_exclusive_grant(list_t *grants)
 766      -{
 767      -        smb_oplock_grant_t      *og;
 768      -
 769      -        og = list_head(grants);
 770      -        if (og) {
 771      -                SMB_OPLOCK_GRANT_VALID(og);
 772      -                if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
 773      -                        return (og);
 774      -        }
 775      -        return (NULL);
 776      -}
 777      -
 778      -/*
 779      - * smb_oplock_get_grant
 780      - *
 781      - * Find oplock grant corresponding to the specified ofile.
 782      - */
 783      -static smb_oplock_grant_t *
 784      -smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile)
 785      -{
 786      -        ASSERT(MUTEX_HELD(&ol->ol_mutex));
 787      -
 788      -        if (SMB_OFILE_OPLOCK_GRANTED(ofile))
 789      -                return (&ofile->f_oplock_grant);
 790      -        else
 791      -                return (NULL);
 792  158  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX