Print this page
    
NEX-15931 Panic removing files in SMB3 CA share
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Include in backports of:
  NEX-9808 SMB3 persistent handles
NEX-15931 Panic removing files in SMB3 CA share
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Include in backports of:
  NEX-9808 SMB3 persistent handles
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15555 SMB2 async redesign
NEX-15061 smtorture smb2.lock.cancel.cancel is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Also follow-up change to:
 NEX-1643 dtrace provider for smbsrv (remove "done2" probes,
 which don't make sense with the new async design)
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15555 SMB2 async redesign
NEX-15061 smtorture smb2.lock.cancel.cancel is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Also follow-up change to:
 NEX-1643 dtrace provider for smbsrv (remove "done2" probes,
 which don't make sense with the new async design)
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-6042 SMB resilient handle lock replay
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@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>
SMB-122 smbd core dumps in smbd_dc_update / smb_log
SMB-117 Win7 fails to open security properties
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)
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/smbsrv/smb2_lock.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb2_lock.c
   1    1  /*
   2    2   * This file and its contents are supplied under the terms of the
  
    | 
      ↓ open down ↓ | 
    2 lines elided | 
    
      ↑ open up ↑ | 
  
   3    3   * Common Development and Distribution License ("CDDL"), version 1.0.
   4    4   * You may only use this file in accordance with the terms of version
   5    5   * 1.0 of the CDDL.
   6    6   *
   7    7   * A full copy of the text of the CDDL should have accompanied this
   8    8   * source.  A copy of the CDDL is also available via the Internet at
   9    9   * http://www.illumos.org/license/CDDL.
  10   10   */
  11   11  
  12   12  /*
  13      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
       13 + * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  14   14   */
  15   15  
  16   16  /*
  17   17   * Dispatch function for SMB2_LOCK
  18   18   */
  19   19  
  20   20  #include <smbsrv/smb2_kproto.h>
  21   21  
  22      -struct SMB2_LOCK_ELEMENT {
       22 +/*
       23 + * [MS-SMB2] 2.2.26 LockSequenceIndex, LockSequenceNumber.
       24 + */
       25 +#define SMB2_LSN_SHIFT  4
       26 +#define SMB2_LSN_MASK   0xf
       27 +
       28 +typedef struct SMB2_LOCK_ELEMENT {
  23   29          uint64_t Offset;
  24   30          uint64_t Length;
  25   31          uint32_t Flags;
  26   32          uint32_t reserved;
  27      -};
       33 +} lock_elem_t;
  28   34  
  29      -static smb_sdrc_t smb2_lock_async(smb_request_t *);
  30      -static uint32_t smb2_lock_exec(smb_request_t *, uint16_t);
  31      -static uint32_t smb2_lock_elem(smb_request_t *, struct SMB2_LOCK_ELEMENT *);
       35 +static uint32_t smb2_unlock(smb_request_t *);
       36 +static uint32_t smb2__lock(smb_request_t *);
       37 +static uint32_t smb2_lock_blocking(smb_request_t *);
  32   38  
       39 +static boolean_t smb2_lock_chk_lockseq(smb_ofile_t *, uint32_t);
       40 +static void smb2_lock_set_lockseq(smb_ofile_t *, uint32_t);
       41 +
  33   42  /*
  34   43   * This is a somewhat arbitrary sanity limit on the length of the
  35   44   * SMB2_LOCK_ELEMENT array.  It usually has length one or two.
  36   45   */
  37   46  int smb2_lock_max_elem = 1024;
  38   47  
  39   48  smb_sdrc_t
  40   49  smb2_lock(smb_request_t *sr)
  41   50  {
  42      -        struct SMB2_LOCK_ELEMENT elem;
       51 +        lock_elem_t *lvec, *lk;
  43   52          smb2fid_t smb2fid;
  44      -        uint32_t save_offset;
  45   53          uint32_t LockSequence;
  46   54          uint32_t status;
  47   55          uint16_t StructSize;
  48   56          uint16_t LockCount;
  49   57          uint16_t i;
  50      -        boolean_t MayBlock = B_FALSE;
  51      -        int rc = 0;
       58 +        int rc;
  52   59  
  53   60          /*
  54      -         * SMB2 Lock request
       61 +         * Decode SMB2 Lock request
  55   62           */
  56   63          rc = smb_mbc_decodef(
  57   64              &sr->smb_data, "wwlqq",
  58   65              &StructSize,                /* w */
  59   66              &LockCount,                 /* w */
  60   67              &LockSequence,              /* l */
  61   68              &smb2fid.persistent,        /* q */
  62   69              &smb2fid.temporal);         /* q */
  63   70          if (rc || StructSize != 48)
  64   71                  return (SDRC_ERROR);
  65   72  
       73 +        /*
       74 +         * Want FID lookup before the start probe.
       75 +         */
  66   76          status = smb2sr_lookup_fid(sr, &smb2fid);
       77 +        DTRACE_SMB2_START(op__Lock, smb_request_t *, sr);
       78 +
  67   79          if (status)
  68      -                goto errout;
       80 +                goto errout; /* Bad FID */
  69   81          if (sr->fid_ofile->f_node == NULL || LockCount == 0) {
  70   82                  status = NT_STATUS_INVALID_PARAMETER;
  71   83                  goto errout;
  72   84          }
  73   85          if (LockCount > smb2_lock_max_elem) {
  74   86                  status = NT_STATUS_INSUFFICIENT_RESOURCES;
  75   87                  goto errout;
  76   88          }
  77   89  
  78   90          /*
  79      -         * Process the array of SMB2_LOCK_ELEMENT structs
  80      -         * We do this twice.  (it's always a short list)
  81      -         * The first time, just validate the flags, and check
  82      -         * if any of the locking request might need to block.
  83      -         * The second time (either here, or in the async
  84      -         * handler function) process the locks for real.
       91 +         * Check the LockSequence to determine whether a previous
       92 +         * lock request succeeded, but the client disconnected
       93 +         * (retaining a durable or resilient handle).  If so, this
       94 +         * is a lock "replay".  We'll find the lock sequence here
       95 +         * and return success without processing the lock again.
  85   96           */
  86      -        save_offset = sr->smb_data.chain_offset;
       97 +        if (sr->session->dialect < SMB_VERS_2_1)
       98 +                LockSequence = 0;
       99 +        if ((sr->session->dialect == SMB_VERS_2_1) &&
      100 +            sr->fid_ofile->dh_vers != SMB2_RESILIENT)
      101 +                LockSequence = 0;
      102 +        /* dialect 3.0 or later can always use LockSequence */
      103 +
      104 +        if (LockSequence != 0 &&
      105 +            smb2_lock_chk_lockseq(sr->fid_ofile, LockSequence)) {
      106 +                status = NT_STATUS_SUCCESS;
      107 +                goto errout;
      108 +        }
      109 +
      110 +        /*
      111 +         * Parse the array of SMB2_LOCK_ELEMENT structs.
      112 +         * This array is free'd in smb_srm_fini.
      113 +         */
      114 +        lvec = smb_srm_zalloc(sr, LockCount * sizeof (*lvec));
  87  115          for (i = 0; i < LockCount; i++) {
      116 +                lk = &lvec[i];
  88  117                  rc = smb_mbc_decodef(
  89  118                      &sr->smb_data, "qqll",
  90      -                    &elem.Offset,       /* q */
  91      -                    &elem.Length,       /* q */
  92      -                    &elem.Flags,        /* l */
  93      -                    &elem.reserved);    /* l */
      119 +                    &lk->Offset,        /* q */
      120 +                    &lk->Length,        /* q */
      121 +                    &lk->Flags,         /* l */
      122 +                    &lk->reserved);     /* l */
  94  123                  if (rc) {
  95  124                          status = NT_STATUS_INVALID_PARAMETER;
  96  125                          goto errout;
  97  126                  }
      127 +        }
  98  128  
  99      -                /*
 100      -                 * Make sure the flags are valid;
 101      -                 * Find out if we might block.
 102      -                 */
 103      -                switch (elem.Flags) {
 104      -                case SMB2_LOCKFLAG_SHARED_LOCK:
 105      -                case SMB2_LOCKFLAG_EXCLUSIVE_LOCK:
 106      -                        MayBlock = B_TRUE;
 107      -                        break;
 108      -
 109      -                /* BEGIN CSTYLED */
 110      -                case SMB2_LOCKFLAG_SHARED_LOCK |
 111      -                     SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
 112      -                case SMB2_LOCKFLAG_EXCLUSIVE_LOCK |
 113      -                     SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
 114      -                case SMB2_LOCKFLAG_UNLOCK:
 115      -                /* END CSTYLED */
 116      -                        break;
 117      -
 118      -                default:
 119      -                        status = NT_STATUS_INVALID_PARAMETER;
 120      -                        goto errout;
 121      -                }
      129 +        /*
      130 +         * [MS-SMB2] 3.3.5.14
      131 +         * If the flags of the [first element of] the Locks array
      132 +         * [has] SMB2_LOCKFLAG_UNLOCK set, the server MUST process
      133 +         * the lock array as a series of unlocks. Otherwise, it
      134 +         * MUST process the lock array as a series of lock requests.
      135 +         */
      136 +        sr->arg.lock.lvec = lvec;
      137 +        sr->arg.lock.lcnt = LockCount;
      138 +        sr->arg.lock.lseq = LockSequence;
      139 +        if (lvec[0].Flags & SMB2_LOCKFLAG_UNLOCK) {
      140 +                status = smb2_unlock(sr);
      141 +        } else {
      142 +                status = smb2__lock(sr);
 122  143          }
 123  144  
 124      -        if (MayBlock) {
 125      -                /*
 126      -                 * May need to block.  "Go async".
 127      -                 */
 128      -                status = smb2sr_go_async(sr, smb2_lock_async);
 129      -                goto errout;
      145 +        if (sr->fid_ofile->dh_persist) {
      146 +                smb2_dh_update_locks(sr, sr->fid_ofile);
 130  147          }
 131  148  
 132      -        sr->smb_data.chain_offset = save_offset;
 133      -        status = smb2_lock_exec(sr, LockCount);
 134      -        if (status)
 135      -                goto errout;
      149 +errout:
      150 +        sr->smb2_status = status;
      151 +        DTRACE_SMB2_DONE(op__Lock, smb_request_t *, sr);
 136  152  
      153 +        if (status) {
      154 +                smb2sr_put_error(sr, status);
      155 +                return (SDRC_SUCCESS);
      156 +        }
      157 +
 137  158          /*
 138      -         * SMB2 Lock reply (sync)
      159 +         * Encode SMB2 Lock reply
 139  160           */
 140      -        StructSize = 4;
 141  161          (void) smb_mbc_encodef(
 142  162              &sr->reply, "w..",
 143      -            StructSize);        /* w */
 144      -            /* reserved           .. */
      163 +            4); /* StructSize   w */
      164 +            /* reserved         .. */
 145  165          return (SDRC_SUCCESS);
 146      -
 147      -errout:
 148      -        smb2sr_put_error(sr, status);
 149      -        return (SDRC_SUCCESS);
 150  166  }
 151  167  
 152      -static smb_sdrc_t
 153      -smb2_lock_async(smb_request_t *sr)
      168 +/*
      169 + * Process what should be an array of unlock requests.
      170 + */
      171 +static uint32_t
      172 +smb2_unlock(smb_request_t *sr)
 154  173  {
 155      -        smb2fid_t smb2fid;
 156      -        uint32_t LockSequence;
 157      -        uint32_t status;
 158      -        uint16_t StructSize;
 159      -        uint16_t LockCount;
 160      -        int rc = 0;
      174 +        lock_elem_t *lk;
      175 +        lock_elem_t *lvec = sr->arg.lock.lvec;
      176 +        uint32_t LockCount = sr->arg.lock.lcnt;
      177 +        uint32_t LockSequence = sr->arg.lock.lseq;
      178 +        uint32_t status = 0;
      179 +        uint32_t pid = 0;       /* SMB2 ignores lock PIDs. */
      180 +        int i;
 161  181  
 162      -        /*
 163      -         * Decode the lock request again.  It should all decode
 164      -         * exactly the same as the first time we saw it.  If not,
 165      -         * report an "internal error".
 166      -         */
 167      -        rc = smb_mbc_decodef(
 168      -            &sr->smb_data, "wwlqq",
 169      -            &StructSize,                /* w */
 170      -            &LockCount,                 /* w */
 171      -            &LockSequence,              /* l */
 172      -            &smb2fid.persistent,        /* q */
 173      -            &smb2fid.temporal);         /* q */
 174      -        if (rc || StructSize != 48)
 175      -                return (SDRC_ERROR);
      182 +        for (i = 0; i < LockCount; i++) {
      183 +                lk = &lvec[i];
 176  184  
 177      -        status = smb2sr_lookup_fid(sr, &smb2fid);
 178      -        if (status)
 179      -                goto errout;
 180      -        if (sr->fid_ofile->f_node == NULL || LockCount == 0) {
 181      -                status = NT_STATUS_INTERNAL_ERROR;
 182      -                goto errout;
      185 +                if (lk->Flags != SMB2_LOCKFLAG_UNLOCK) {
      186 +                        status = NT_STATUS_INVALID_PARAMETER;
      187 +                        break;
      188 +                }
      189 +
      190 +                status = smb_unlock_range(sr, lk->Offset, lk->Length, pid);
      191 +                if (status != 0)
      192 +                        break;
 183  193          }
      194 +        if (status == 0 && LockSequence != 0) {
      195 +                smb2_lock_set_lockseq(sr->fid_ofile, LockSequence);
      196 +        }
 184  197  
 185      -        status = smb2_lock_exec(sr, LockCount);
 186      -        if (status)
 187      -                goto errout;
 188      -
 189      -        /*
 190      -         * SMB2 Lock reply (async)
 191      -         */
 192      -        StructSize = 4;
 193      -        (void) smb_mbc_encodef(
 194      -            &sr->reply, "w..",
 195      -            StructSize);        /* w */
 196      -            /* reserved           .. */
 197      -        return (SDRC_SUCCESS);
 198      -
 199      -errout:
 200      -        smb2sr_put_error(sr, status);
 201      -        return (SDRC_SUCCESS);
      198 +        return (status);
 202  199  }
 203  200  
 204  201  /*
 205      - * Execute the vector of locks.  This is the common function called by
 206      - * either the sync or async code paths.  We've already decoded this
 207      - * request once when we get here, so if there are any decode errors
 208      - * then it's some kind of internal error.
      202 + * Process what should be an array of lock requests.
 209  203   */
 210  204  static uint32_t
 211      -smb2_lock_exec(smb_request_t *sr, uint16_t LockCount)
      205 +smb2__lock(smb_request_t *sr)
 212  206  {
 213      -        struct SMB2_LOCK_ELEMENT elem;
      207 +        lock_elem_t *lk;
      208 +        lock_elem_t *lvec = sr->arg.lock.lvec;
      209 +        uint32_t LockCount = sr->arg.lock.lcnt;
      210 +        uint32_t LockSequence = sr->arg.lock.lseq;
      211 +        uint32_t i;
      212 +        uint32_t ltype;
      213 +        uint32_t pid = 0;       /* SMB2 ignores lock PIDs */
      214 +        uint32_t timeout = 0;
 214  215          uint32_t status = 0;
 215      -        uint16_t i;
 216      -        int rc;
 217  216  
 218      -        /*
 219      -         * On entry, out position in the input data should be
 220      -         * after both the SMB2 header and the fixed part of
 221      -         * the SMB Lock request header (24).
 222      -         */
 223      -        ASSERT(sr->smb_data.chain_offset ==
 224      -            (sr->smb2_cmd_hdr + SMB2_HDR_SIZE + 24));
      217 +        for (i = 0; i < LockCount; i++) {
      218 +                lk = &lvec[i];
 225  219  
 226      -        /*
 227      -         * This is checked by our callers, but let's make sure.
 228      -         */
 229      -        ASSERT(sr->fid_ofile->f_node != NULL);
      220 +                switch (lk->Flags) {
 230  221  
 231      -        for (i = 0; i < LockCount; i++) {
 232      -                rc = smb_mbc_decodef(
 233      -                    &sr->smb_data, "qqll",
 234      -                    &elem.Offset,       /* q */
 235      -                    &elem.Length,       /* q */
 236      -                    &elem.Flags,        /* l */
 237      -                    &elem.reserved);    /* l */
 238      -                if (rc) {
 239      -                        status = NT_STATUS_INTERNAL_ERROR;
      222 +                case SMB2_LOCKFLAG_SHARED_LOCK:
      223 +                case SMB2_LOCKFLAG_EXCLUSIVE_LOCK:
      224 +                        /*
      225 +                         * Blocking locks have special rules:
      226 +                         * Must be exactly one element, else
      227 +                         * invalid parameter.
      228 +                         */
      229 +                        if (i == 0 && LockCount == 1) {
      230 +                                status = smb2_lock_blocking(sr);
      231 +                                return (status);
      232 +                        }
      233 +                        /* FALLTHROUGH */
      234 +                case SMB2_LOCKFLAG_UNLOCK:
      235 +                default:
      236 +                        status = NT_STATUS_INVALID_PARAMETER;
      237 +                        goto end_loop;
      238 +
      239 +                /* BEGIN CSTYLED */
      240 +                case SMB2_LOCKFLAG_SHARED_LOCK |
      241 +                     SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
      242 +                /* END CSTYLED */
      243 +                        ltype = SMB_LOCK_TYPE_READONLY;
 240  244                          break;
 241      -                }
 242      -                status = smb2_lock_elem(sr, &elem);
 243      -                if (status)
      245 +
      246 +                /* BEGIN CSTYLED */
      247 +                case SMB2_LOCKFLAG_EXCLUSIVE_LOCK |
      248 +                     SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
      249 +                /* END CSTYLED */
      250 +                        ltype = SMB_LOCK_TYPE_READWRITE;
 244  251                          break;
      252 +                }
      253 +
      254 +                status = smb_lock_range(sr, lk->Offset, lk->Length, pid,
      255 +                    ltype, timeout);
      256 +                if (status != 0) {
      257 +                        goto end_loop;
      258 +                }
 245  259          }
      260 +
      261 +end_loop:
      262 +        if (status != 0) {
      263 +                /*
      264 +                 * Oh... we have to rollback.
      265 +                 */
      266 +                while (i > 0) {
      267 +                        --i;
      268 +                        lk = &lvec[i];
      269 +                        (void) smb_unlock_range(sr,
      270 +                            lk->Offset, lk->Length, pid);
      271 +                }
      272 +        }
      273 +        if (status == 0 && LockSequence != 0)
      274 +                smb2_lock_set_lockseq(sr->fid_ofile, LockSequence);
      275 +
 246  276          return (status);
 247  277  }
 248  278  
      279 +/*
      280 + * Handler for blocking lock requests, which may "go async".
      281 + * Always exactly one lock request here.
      282 + */
 249  283  static uint32_t
 250      -smb2_lock_elem(smb_request_t *sr, struct SMB2_LOCK_ELEMENT *elem)
      284 +smb2_lock_blocking(smb_request_t *sr)
 251  285  {
 252      -        smb_node_t *node = sr->fid_ofile->f_node;
      286 +        lock_elem_t *lk = sr->arg.lock.lvec;
      287 +        uint32_t LockCount = sr->arg.lock.lcnt;
      288 +        uint32_t LockSequence = sr->arg.lock.lseq;
 253  289          uint32_t status;
 254  290          uint32_t ltype;
 255      -        uint32_t timeout = 0;
      291 +        uint32_t pid = 0;       /* SMB2 ignores lock PIDs */
      292 +        uint32_t timeout = UINT_MAX;
 256  293  
 257      -        switch (elem->Flags) {
      294 +        ASSERT(sr->fid_ofile->f_node != NULL);
      295 +        ASSERT(LockCount == 1);
      296 +
      297 +        switch (lk->Flags) {
 258  298          case SMB2_LOCKFLAG_SHARED_LOCK:
 259      -                timeout = UINT_MAX;
 260      -                /* FALLTHROUGH */
 261      -        case SMB2_LOCKFLAG_SHARED_LOCK | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
 262  299                  ltype = SMB_LOCK_TYPE_READONLY;
 263      -                status = smb_lock_range(sr,
 264      -                    elem->Offset, elem->Length,
 265      -                    timeout, ltype);
 266  300                  break;
 267  301  
 268  302          case SMB2_LOCKFLAG_EXCLUSIVE_LOCK:
 269      -                timeout = UINT_MAX;
 270      -                /* FALLTHROUGH */
 271      -        case SMB2_LOCKFLAG_EXCLUSIVE_LOCK | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
 272  303                  ltype = SMB_LOCK_TYPE_READWRITE;
 273      -                status = smb_lock_range(sr,
 274      -                    elem->Offset, elem->Length,
 275      -                    timeout, ltype);
 276  304                  break;
 277  305  
 278      -        case SMB2_LOCKFLAG_UNLOCK:
 279      -                status = smb_unlock_range(sr, node,
 280      -                    elem->Offset, elem->Length);
 281      -                break;
      306 +        default:
      307 +                ASSERT(0);
      308 +                return (NT_STATUS_INTERNAL_ERROR);
      309 +        }
 282  310  
 283  311          /*
 284      -         * We've already checked the flags previously, so any
 285      -         * surprises here are some kind of internal error.
      312 +         * Try the lock first with timeout=0 as we can often
      313 +         * get a lock without going async and avoid an extra
      314 +         * round trip with the client.  Also, only go async
      315 +         * for status returns that mean we will block.
 286  316           */
 287      -        default:
 288      -                status = NT_STATUS_INTERNAL_ERROR;
 289      -                break;
      317 +        status = smb_lock_range(sr, lk->Offset, lk->Length, pid, ltype, 0);
      318 +        if (status == NT_STATUS_LOCK_NOT_GRANTED ||
      319 +            status == NT_STATUS_FILE_LOCK_CONFLICT) {
      320 +                status = smb2sr_go_async(sr);
      321 +                if (status != 0)
      322 +                        return (status);
      323 +                status = smb_lock_range(sr, lk->Offset, lk->Length,
      324 +                    pid, ltype, timeout);
 290  325          }
 291  326  
      327 +        if (status == 0 && LockSequence != 0)
      328 +                smb2_lock_set_lockseq(sr->fid_ofile, LockSequence);
      329 +
 292  330          return (status);
      331 +}
      332 +
      333 +/*
      334 + * Check whether we've stored a given LockSequence
      335 + *
      336 + * [MS-SMB2] 3.3.5.14
      337 + *
      338 + * The server verifies the LockSequence by performing the following steps:
      339 + *
      340 + * 1. The server MUST use LockSequenceIndex as an index into the
      341 + * Open.LockSequenceArray in order to locate the sequence number entry.
      342 + * If the index exceeds the maximum extent of the Open.LockSequenceArray,
      343 + * or LockSequenceIndex is 0, or if the sequence number entry is empty,
      344 + * the server MUST skip step 2 and continue lock/unlock processing.
      345 + *
      346 + * 2. The server MUST compare LockSequenceNumber to the SequenceNumber of
      347 + * the entry located in step 1. If the sequence numbers are equal, the
      348 + * server MUST complete the lock/unlock request with success. Otherwise,
      349 + * the server MUST reset the entry value to empty and continue lock/unlock
      350 + * processing.
      351 + */
      352 +boolean_t
      353 +smb2_lock_chk_lockseq(smb_ofile_t *ofile, uint32_t lockseq)
      354 +{
      355 +        uint32_t lsi;
      356 +        uint8_t lsn;
      357 +        boolean_t rv;
      358 +
      359 +        /*
      360 +         * LockSequenceNumber is the low four bits.
      361 +         * LockSequenceIndex is the remaining 28 bits.
      362 +         * valid range is 1..64, which we convert to an
      363 +         * array index in the range 0..63
      364 +         */
      365 +        lsn = lockseq & SMB2_LSN_MASK;
      366 +        lsi = (lockseq >> SMB2_LSN_SHIFT);
      367 +        if (lsi == 0 || lsi > SMB_OFILE_LSEQ_MAX)
      368 +                return (B_FALSE);
      369 +        --lsi;
      370 +
      371 +        mutex_enter(&ofile->f_mutex);
      372 +
      373 +        if (ofile->f_lock_seq[lsi] == lsn) {
      374 +                rv = B_TRUE;
      375 +        } else {
      376 +                ofile->f_lock_seq[lsi] = (uint8_t)-1;   /* "Empty" */
      377 +                rv = B_FALSE;
      378 +        }
      379 +
      380 +        mutex_exit(&ofile->f_mutex);
      381 +
      382 +        return (rv);
      383 +}
      384 +
      385 +static void
      386 +smb2_lock_set_lockseq(smb_ofile_t *ofile, uint32_t lockseq)
      387 +{
      388 +        uint32_t lsi;
      389 +        uint8_t lsn;
      390 +
      391 +        /*
      392 +         * LockSequenceNumber is the low four bits.
      393 +         * LockSequenceIndex is the remaining 28 bits.
      394 +         * valid range is 1..64, which we convert to an
      395 +         * array index in the range 0..63
      396 +         */
      397 +        lsn = lockseq & SMB2_LSN_MASK;
      398 +        lsi = (lockseq >> SMB2_LSN_SHIFT);
      399 +        if (lsi == 0 || lsi > SMB_OFILE_LSEQ_MAX) {
      400 +                cmn_err(CE_NOTE, "smb2_lock_set_lockseq, index=%u", lsi);
      401 +                return;
      402 +        }
      403 +        --lsi;
      404 +
      405 +        mutex_enter(&ofile->f_mutex);
      406 +
      407 +        ofile->f_lock_seq[lsi] = lsn;
      408 +
      409 +        mutex_exit(&ofile->f_mutex);
 293  410  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX