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)
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Dispatch function for SMB2_LOCK
  18  */
  19 
  20 #include <smbsrv/smb2_kproto.h>
  21 
  22 struct SMB2_LOCK_ELEMENT {






  23         uint64_t Offset;
  24         uint64_t Length;
  25         uint32_t Flags;
  26         uint32_t reserved;
  27 };
  28 
  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 *);
  32 



  33 /*
  34  * This is a somewhat arbitrary sanity limit on the length of the
  35  * SMB2_LOCK_ELEMENT array.  It usually has length one or two.
  36  */
  37 int smb2_lock_max_elem = 1024;
  38 
  39 smb_sdrc_t
  40 smb2_lock(smb_request_t *sr)
  41 {
  42         struct SMB2_LOCK_ELEMENT elem;
  43         smb2fid_t smb2fid;
  44         uint32_t save_offset;
  45         uint32_t LockSequence;
  46         uint32_t status;
  47         uint16_t StructSize;
  48         uint16_t LockCount;
  49         uint16_t i;
  50         boolean_t MayBlock = B_FALSE;
  51         int rc = 0;
  52 
  53         /*
  54          * SMB2 Lock request
  55          */
  56         rc = smb_mbc_decodef(
  57             &sr->smb_data, "wwlqq",
  58             &StructSize,            /* w */
  59             &LockCount,                     /* w */
  60             &LockSequence,          /* l */
  61             &smb2fid.persistent,    /* q */
  62             &smb2fid.temporal);             /* q */
  63         if (rc || StructSize != 48)
  64                 return (SDRC_ERROR);
  65 



  66         status = smb2sr_lookup_fid(sr, &smb2fid);


  67         if (status)
  68                 goto errout;
  69         if (sr->fid_ofile->f_node == NULL || LockCount == 0) {
  70                 status = NT_STATUS_INVALID_PARAMETER;
  71                 goto errout;
  72         }
  73         if (LockCount > smb2_lock_max_elem) {
  74                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
  75                 goto errout;
  76         }
  77 
  78         /*
  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.
  85          */
  86         save_offset = sr->smb_data.chain_offset;
  87         for (i = 0; i < LockCount; i++) {
  88                 rc = smb_mbc_decodef(
  89                     &sr->smb_data, "qqll",
  90                     &elem.Offset,   /* q */
  91                     &elem.Length,   /* q */
  92                     &elem.Flags,    /* l */
  93                     &elem.reserved);        /* l */
  94                 if (rc) {
  95                         status = NT_STATUS_INVALID_PARAMETER;
  96                         goto errout;
  97                 }
  98 
  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                 }
 122         }
 123 
 124         if (MayBlock) {
 125                 /*
 126                  * May need to block.  "Go async".




 127                  */
 128                 status = smb2sr_go_async(sr, smb2_lock_async);
 129                 goto errout;





 130         }
 131 
 132         sr->smb_data.chain_offset = save_offset;
 133         status = smb2_lock_exec(sr, LockCount);
 134         if (status)
 135                 goto errout;
 136 









 137         /*
 138          * SMB2 Lock reply (sync)
 139          */
 140         StructSize = 4;
 141         (void) smb_mbc_encodef(
 142             &sr->reply, "w..",
 143             StructSize);        /* w */
 144             /* reserved           .. */
 145         return (SDRC_SUCCESS);
 146 
 147 errout:
 148         smb2sr_put_error(sr, status);
 149         return (SDRC_SUCCESS);
 150 }
 151 
 152 static smb_sdrc_t
 153 smb2_lock_async(smb_request_t *sr)



 154 {
 155         smb2fid_t smb2fid;
 156         uint32_t LockSequence;
 157         uint32_t status;
 158         uint16_t StructSize;
 159         uint16_t LockCount;
 160         int rc = 0;

 161 
 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);
 176 
 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;
 183         }
 184 
 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);
 202 }
 203 
 204 /*
 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.
 209  */
 210 static uint32_t
 211 smb2_lock_exec(smb_request_t *sr, uint16_t LockCount)
 212 {
 213         struct SMB2_LOCK_ELEMENT elem;







 214         uint32_t status = 0;
 215         uint16_t i;
 216         int rc;
 217 
 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));
 225 




 226         /*
 227          * This is checked by our callers, but let's make sure.


 228          */
 229         ASSERT(sr->fid_ofile->f_node != NULL);








 230 
 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;
 240                         break;
 241                 }
 242                 status = smb2_lock_elem(sr, &elem);
 243                 if (status)



 244                         break;
 245         }























 246         return (status);
 247 }
 248 




 249 static uint32_t
 250 smb2_lock_elem(smb_request_t *sr, struct SMB2_LOCK_ELEMENT *elem)
 251 {
 252         smb_node_t *node = sr->fid_ofile->f_node;


 253         uint32_t status;
 254         uint32_t ltype;
 255         uint32_t timeout = 0;

 256 
 257         switch (elem->Flags) {



 258         case SMB2_LOCKFLAG_SHARED_LOCK:
 259                 timeout = UINT_MAX;
 260                 /* FALLTHROUGH */
 261         case SMB2_LOCKFLAG_SHARED_LOCK | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
 262                 ltype = SMB_LOCK_TYPE_READONLY;
 263                 status = smb_lock_range(sr,
 264                     elem->Offset, elem->Length,
 265                     timeout, ltype);
 266                 break;
 267 
 268         case SMB2_LOCKFLAG_EXCLUSIVE_LOCK:
 269                 timeout = UINT_MAX;
 270                 /* FALLTHROUGH */
 271         case SMB2_LOCKFLAG_EXCLUSIVE_LOCK | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
 272                 ltype = SMB_LOCK_TYPE_READWRITE;
 273                 status = smb_lock_range(sr,
 274                     elem->Offset, elem->Length,
 275                     timeout, ltype);
 276                 break;
 277 
 278         case SMB2_LOCKFLAG_UNLOCK:
 279                 status = smb_unlock_range(sr, node,
 280                     elem->Offset, elem->Length);
 281                 break;
 282 
 283         /*
 284          * We've already checked the flags previously, so any
 285          * surprises here are some kind of internal error.


 286          */
 287         default:
 288                 status = NT_STATUS_INTERNAL_ERROR;
 289                 break;





 290         }
 291 



 292         return (status);















































































 293 }
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Dispatch function for SMB2_LOCK
  18  */
  19 
  20 #include <smbsrv/smb2_kproto.h>
  21 
  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 {
  29         uint64_t Offset;
  30         uint64_t Length;
  31         uint32_t Flags;
  32         uint32_t reserved;
  33 } lock_elem_t;
  34 
  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 *);
  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 
  42 /*
  43  * This is a somewhat arbitrary sanity limit on the length of the
  44  * SMB2_LOCK_ELEMENT array.  It usually has length one or two.
  45  */
  46 int smb2_lock_max_elem = 1024;
  47 
  48 smb_sdrc_t
  49 smb2_lock(smb_request_t *sr)
  50 {
  51         lock_elem_t *lvec, *lk;
  52         smb2fid_t smb2fid;

  53         uint32_t LockSequence;
  54         uint32_t status;
  55         uint16_t StructSize;
  56         uint16_t LockCount;
  57         uint16_t i;
  58         int rc;

  59 
  60         /*
  61          * Decode SMB2 Lock request
  62          */
  63         rc = smb_mbc_decodef(
  64             &sr->smb_data, "wwlqq",
  65             &StructSize,            /* w */
  66             &LockCount,                     /* w */
  67             &LockSequence,          /* l */
  68             &smb2fid.persistent,    /* q */
  69             &smb2fid.temporal);             /* q */
  70         if (rc || StructSize != 48)
  71                 return (SDRC_ERROR);
  72 
  73         /*
  74          * Want FID lookup before the start probe.
  75          */
  76         status = smb2sr_lookup_fid(sr, &smb2fid);
  77         DTRACE_SMB2_START(op__Lock, smb_request_t *, sr);
  78 
  79         if (status)
  80                 goto errout; /* Bad FID */
  81         if (sr->fid_ofile->f_node == NULL || LockCount == 0) {
  82                 status = NT_STATUS_INVALID_PARAMETER;
  83                 goto errout;
  84         }
  85         if (LockCount > smb2_lock_max_elem) {
  86                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
  87                 goto errout;
  88         }
  89 
  90         /*
  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.

  96          */
  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));
 115         for (i = 0; i < LockCount; i++) {
 116                 lk = &lvec[i];
 117                 rc = smb_mbc_decodef(
 118                     &sr->smb_data, "qqll",
 119                     &lk->Offset, /* q */
 120                     &lk->Length, /* q */
 121                     &lk->Flags,          /* l */
 122                     &lk->reserved);      /* l */
 123                 if (rc) {






 124                         status = NT_STATUS_INVALID_PARAMETER;
 125                         goto errout;
 126                 }
 127         }
 128 

 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);
 143         }
 144 
 145         if (sr->fid_ofile->dh_persist) {
 146                 smb2_dh_update_locks(sr, sr->fid_ofile);
 147         }

 148 
 149 errout:
 150         sr->smb2_status = status;
 151         DTRACE_SMB2_DONE(op__Lock, smb_request_t *, sr);
 152 
 153         if (status) {
 154                 smb2sr_put_error(sr, status);
 155                 return (SDRC_SUCCESS);
 156         }
 157 
 158         /*
 159          * Encode SMB2 Lock reply
 160          */

 161         (void) smb_mbc_encodef(
 162             &sr->reply, "w..",
 163             4); /* StructSize   w */
 164             /* reserved         .. */
 165         return (SDRC_SUCCESS);




 166 }
 167 
 168 /*
 169  * Process what should be an array of unlock requests.
 170  */
 171 static uint32_t
 172 smb2_unlock(smb_request_t *sr)
 173 {
 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;
 181 
 182         for (i = 0; i < LockCount; i++) {
 183                 lk = &lvec[i];












 184 
 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;
 193         }
 194         if (status == 0 && LockSequence != 0) {
 195                 smb2_lock_set_lockseq(sr->fid_ofile, LockSequence);
 196         }
 197 
 198         return (status);












 199 }
 200 
 201 /*
 202  * Process what should be an array of lock requests.



 203  */
 204 static uint32_t
 205 smb2__lock(smb_request_t *sr)
 206 {
 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;
 215         uint32_t status = 0;


 216 
 217         for (i = 0; i < LockCount; i++) {
 218                 lk = &lvec[i];





 219 
 220                 switch (lk->Flags) {
 221 
 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;




 244                         break;
 245 
 246                 /* BEGIN CSTYLED */
 247                 case SMB2_LOCKFLAG_EXCLUSIVE_LOCK |
 248                      SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
 249                 /* END CSTYLED */
 250                         ltype = SMB_LOCK_TYPE_READWRITE;
 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                 }
 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 
 276         return (status);
 277 }
 278 
 279 /*
 280  * Handler for blocking lock requests, which may "go async".
 281  * Always exactly one lock request here.
 282  */
 283 static uint32_t
 284 smb2_lock_blocking(smb_request_t *sr)
 285 {
 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;
 289         uint32_t status;
 290         uint32_t ltype;
 291         uint32_t pid = 0;       /* SMB2 ignores lock PIDs */
 292         uint32_t timeout = UINT_MAX;
 293 
 294         ASSERT(sr->fid_ofile->f_node != NULL);
 295         ASSERT(LockCount == 1);
 296 
 297         switch (lk->Flags) {
 298         case SMB2_LOCKFLAG_SHARED_LOCK:



 299                 ltype = SMB_LOCK_TYPE_READONLY;



 300                 break;
 301 
 302         case SMB2_LOCKFLAG_EXCLUSIVE_LOCK:



 303                 ltype = SMB_LOCK_TYPE_READWRITE;



 304                 break;
 305 
 306         default:
 307                 ASSERT(0);
 308                 return (NT_STATUS_INTERNAL_ERROR);
 309         }
 310 
 311         /*
 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.
 316          */
 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);
 325         }
 326 
 327         if (status == 0 && LockSequence != 0)
 328                 smb2_lock_set_lockseq(sr->fid_ofile, LockSequence);
 329 
 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);
 410 }