Print this page
NEX-4856 SMB2 kstats don't correctly count compound requests
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-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-15578 SMB2 durable handle redesign
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-10229 SMB v1 response incorrect when signature verification fails
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-9864 Some SMB cancel races remain after NEX-5845
Revert (part of) "NEX-5845 rework SMB immediate cancel"
reverts (part of) commit 7a5da69f6d42b17ebcc95ca3d02925d07a01343e.
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5845 rework SMB immediate cancel
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-5152 immediate SMB cancel may fail
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-5175 want SMB statistics separately for reads, writes, other
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4313 want iops, bandwidth, and latency kstats for smb
Portions contributed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-4391 improve smb cancel support
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4147 Cancelled SMB2 requests sometimes have no response (missed things)
NEX-3611 CLONE NEX-3550 Replace smb2_enable with max_protocol
Reviewed by: Yuri Pankov <Yuri.Pankov@nexenta.com>
NEX-2370 unable to save/modify files (zip,notepad,excel) on CIFS share from Windows 7
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-69 read-raw, write-raw are dead code
SMB-39 Use AF_UNIX pipes for RPC
SMB-50 User-mode SMB server
 Includes work by these authors:
 Thomas Keiser <thomas.keiser@nexenta.com>
 Albert Lee <trisk@nexenta.com>
SMB-65 SMB server in non-global zones (use zone_kcred())
SMB-65 SMB server in non-global zones (data structure changes)
Many things move to the smb_server_t object, and
many functions gain an sv arg (which server).
SMB-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
        
*** 19,29 ****
   * CDDL HEADER END
   */
  
  /*
   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
   */
  
  /*
   * SMB requests.
   *
--- 19,29 ----
   * CDDL HEADER END
   */
  
  /*
   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
   */
  
  /*
   * SMB requests.
   *
*** 166,178 ****
          { "SmbQueryInformation", SMB_SDT_OPS(query_information), /* 0x08 008 */
              0x08, PC_NETWORK_PROGRAM_1_0 },
          { "SmbSetInformation", SMB_SDT_OPS(set_information),    /* 0x09 009 */
              0x09, PC_NETWORK_PROGRAM_1_0 },
          { "SmbRead", SMB_SDT_OPS(read),                         /* 0x0A 010 */
!             0x0A, PC_NETWORK_PROGRAM_1_0 },
          { "SmbWrite", SMB_SDT_OPS(write),                       /* 0x0B 011 */
!             0x0B, PC_NETWORK_PROGRAM_1_0 },
          { "SmbLockByteRange", SMB_SDT_OPS(lock_byte_range),     /* 0x0C 012 */
              0x0C, PC_NETWORK_PROGRAM_1_0 },
          { "SmbUnlockByteRange", SMB_SDT_OPS(unlock_byte_range), /* 0x0D 013 */
              0x0D, PC_NETWORK_PROGRAM_1_0 },
          { "SmbCreateTemporary", SMB_SDT_OPS(create_temporary),  /* 0x0E 014 */
--- 166,178 ----
          { "SmbQueryInformation", SMB_SDT_OPS(query_information), /* 0x08 008 */
              0x08, PC_NETWORK_PROGRAM_1_0 },
          { "SmbSetInformation", SMB_SDT_OPS(set_information),    /* 0x09 009 */
              0x09, PC_NETWORK_PROGRAM_1_0 },
          { "SmbRead", SMB_SDT_OPS(read),                         /* 0x0A 010 */
!             0x0A, PC_NETWORK_PROGRAM_1_0, SDDF_READOP },
          { "SmbWrite", SMB_SDT_OPS(write),                       /* 0x0B 011 */
!             0x0B, PC_NETWORK_PROGRAM_1_0, SDDF_WRITEOP },
          { "SmbLockByteRange", SMB_SDT_OPS(lock_byte_range),     /* 0x0C 012 */
              0x0C, PC_NETWORK_PROGRAM_1_0 },
          { "SmbUnlockByteRange", SMB_SDT_OPS(unlock_byte_range), /* 0x0D 013 */
              0x0D, PC_NETWORK_PROGRAM_1_0 },
          { "SmbCreateTemporary", SMB_SDT_OPS(create_temporary),  /* 0x0E 014 */
*** 185,206 ****
              0x11, PC_NETWORK_PROGRAM_1_0,
              SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID },
          { "SmbSeek", SMB_SDT_OPS(seek),                         /* 0x12 018 */
              0x12, PC_NETWORK_PROGRAM_1_0 },
          { "SmbLockAndRead", SMB_SDT_OPS(lock_and_read),         /* 0x13 019 */
!             0x13, LANMAN1_0 },
          { "SmbWriteAndUnlock", SMB_SDT_OPS(write_and_unlock),   /* 0x14 020 */
!             0x14, LANMAN1_0 },
          { "Invalid", SMB_SDT_OPS(invalid), 0x15, 0 },           /* 0x15 021 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x16, 0 },           /* 0x16 022 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x17, 0 },           /* 0x17 023 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x18, 0 },           /* 0x18 024 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x19, 0 },           /* 0x19 025 */
!         { "SmbReadRaw", SMB_SDT_OPS(invalid), 0x1A, 0 },        /* 0x1A 026 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x1B, 0 },           /* 0x1B 027 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x1C, 0 },           /* 0x1C 028 */
!         { "SmbWriteRaw", SMB_SDT_OPS(invalid), 0x1D, 0 },       /* 0x1D 029 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x1E, 0 },           /* 0x1E 030 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x1F, 0 },           /* 0x1F 031 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x20, 0 },           /* 0x20 032 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x21, 0 },           /* 0x21 033 */
          { "SmbSetInformation2", SMB_SDT_OPS(set_information2),  /* 0x22 034 */
--- 185,208 ----
              0x11, PC_NETWORK_PROGRAM_1_0,
              SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID },
          { "SmbSeek", SMB_SDT_OPS(seek),                         /* 0x12 018 */
              0x12, PC_NETWORK_PROGRAM_1_0 },
          { "SmbLockAndRead", SMB_SDT_OPS(lock_and_read),         /* 0x13 019 */
!             0x13, LANMAN1_0, SDDF_READOP},
          { "SmbWriteAndUnlock", SMB_SDT_OPS(write_and_unlock),   /* 0x14 020 */
!             0x14, LANMAN1_0, SDDF_WRITEOP },
          { "Invalid", SMB_SDT_OPS(invalid), 0x15, 0 },           /* 0x15 021 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x16, 0 },           /* 0x16 022 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x17, 0 },           /* 0x17 023 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x18, 0 },           /* 0x18 024 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x19, 0 },           /* 0x19 025 */
!         { "SmbReadRaw", SMB_SDT_OPS(read_raw),                  /* 0x1A 026 */
!             0x1A, LANMAN1_0 },
          { "Invalid", SMB_SDT_OPS(invalid), 0x1B, 0 },           /* 0x1B 027 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x1C, 0 },           /* 0x1C 028 */
!         { "SmbWriteRaw", SMB_SDT_OPS(write_raw),                /* 0x1D 029 */
!             0x1D, LANMAN1_0 },
          { "Invalid", SMB_SDT_OPS(invalid), 0x1E, 0 },           /* 0x1E 030 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x1F, 0 },           /* 0x1F 031 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x20, 0 },           /* 0x20 032 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x21, 0 },           /* 0x21 033 */
          { "SmbSetInformation2", SMB_SDT_OPS(set_information2),  /* 0x22 034 */
*** 221,237 ****
          { "Invalid", SMB_SDT_OPS(invalid), 0x29, 0 },   /* 0x29 041 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x2A, 0 },   /* 0x2A 042 */
          { "SmbEcho", SMB_SDT_OPS(echo),                         /* 0x2B 043 */
              0x2B, LANMAN1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID },
          { "SmbWriteAndClose", SMB_SDT_OPS(write_and_close),     /* 0x2C 044 */
!             0x2C, LANMAN1_0 },
          { "SmbOpenX", SMB_SDT_OPS(open_andx),                   /* 0x2D 045 */
              0x2D, LANMAN1_0 },
          { "SmbReadX", SMB_SDT_OPS(read_andx),                   /* 0x2E 046 */
!             0x2E, LANMAN1_0 },
          { "SmbWriteX", SMB_SDT_OPS(write_andx),                 /* 0x2F 047 */
!             0x2F, LANMAN1_0 },
          { "Invalid", SMB_SDT_OPS(invalid), 0x30, 0 },   /* 0x30 048 */
          { "SmbCloseAndTreeDisconnect",
              SMB_SDT_OPS(close_and_tree_disconnect),             /* 0x31 049 */
              0x31, LANMAN1_0 },
          { "SmbTransaction2", SMB_SDT_OPS(transaction2),         /* 0x32 050 */
--- 223,239 ----
          { "Invalid", SMB_SDT_OPS(invalid), 0x29, 0 },   /* 0x29 041 */
          { "Invalid", SMB_SDT_OPS(invalid), 0x2A, 0 },   /* 0x2A 042 */
          { "SmbEcho", SMB_SDT_OPS(echo),                         /* 0x2B 043 */
              0x2B, LANMAN1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID },
          { "SmbWriteAndClose", SMB_SDT_OPS(write_and_close),     /* 0x2C 044 */
!             0x2C, LANMAN1_0, SDDF_WRITEOP },
          { "SmbOpenX", SMB_SDT_OPS(open_andx),                   /* 0x2D 045 */
              0x2D, LANMAN1_0 },
          { "SmbReadX", SMB_SDT_OPS(read_andx),                   /* 0x2E 046 */
!             0x2E, LANMAN1_0, SDDF_READOP },
          { "SmbWriteX", SMB_SDT_OPS(write_andx),                 /* 0x2F 047 */
!             0x2F, LANMAN1_0, SDDF_WRITEOP },
          { "Invalid", SMB_SDT_OPS(invalid), 0x30, 0 },   /* 0x30 048 */
          { "SmbCloseAndTreeDisconnect",
              SMB_SDT_OPS(close_and_tree_disconnect),             /* 0x31 049 */
              0x31, LANMAN1_0 },
          { "SmbTransaction2", SMB_SDT_OPS(transaction2),         /* 0x32 050 */
*** 406,416 ****
          { "Invalid", SMB_SDT_OPS(invalid), 0xBE, 0, 0 },        /* 0xBE 190 */
          { "Invalid", SMB_SDT_OPS(invalid), 0xBF, 0, 0 },        /* 0xBF 191 */
          { "SmbOpenPrintFile", SMB_SDT_OPS(open_print_file),     /* 0xC0 192 */
              0xC0, PC_NETWORK_PROGRAM_1_0, 0 },
          { "SmbWritePrintFile", SMB_SDT_OPS(write_print_file),   /* 0xC1 193 */
!             0xC1, PC_NETWORK_PROGRAM_1_0, 0 },
          { "SmbClosePrintFile", SMB_SDT_OPS(close_print_file),   /* 0xC2 194 */
              0xC2, PC_NETWORK_PROGRAM_1_0, 0 },
          { "SmbGetPrintQueue", SMB_SDT_OPS(get_print_queue),     /* 0xC3 195 */
              0xC3, PC_NETWORK_PROGRAM_1_0, 0 },
          { "Invalid", SMB_SDT_OPS(invalid), 0xC4, 0, 0 },        /* 0xC4 196 */
--- 408,418 ----
          { "Invalid", SMB_SDT_OPS(invalid), 0xBE, 0, 0 },        /* 0xBE 190 */
          { "Invalid", SMB_SDT_OPS(invalid), 0xBF, 0, 0 },        /* 0xBF 191 */
          { "SmbOpenPrintFile", SMB_SDT_OPS(open_print_file),     /* 0xC0 192 */
              0xC0, PC_NETWORK_PROGRAM_1_0, 0 },
          { "SmbWritePrintFile", SMB_SDT_OPS(write_print_file),   /* 0xC1 193 */
!             0xC1, PC_NETWORK_PROGRAM_1_0, SDDF_WRITEOP },
          { "SmbClosePrintFile", SMB_SDT_OPS(close_print_file),   /* 0xC2 194 */
              0xC2, PC_NETWORK_PROGRAM_1_0, 0 },
          { "SmbGetPrintQueue", SMB_SDT_OPS(get_print_queue),     /* 0xC3 195 */
              0xC3, PC_NETWORK_PROGRAM_1_0, 0 },
          { "Invalid", SMB_SDT_OPS(invalid), 0xC4, 0, 0 },        /* 0xC4 196 */
*** 501,515 ****
           * Mark this request so we know that we've already cleaned it up.
           * A request should only get cleaned up once so multiple calls to
           * smbsr_cleanup for the same request indicate a bug.
           */
          mutex_enter(&sr->sr_mutex);
!         if (sr->sr_state != SMB_REQ_STATE_CANCELED)
                  sr->sr_state = SMB_REQ_STATE_CLEANED_UP;
          mutex_exit(&sr->sr_mutex);
  }
  
  /*
   * This is the SMB1 handler for new smb requests, called from
   * smb_session_reader after SMB negotiate is done.  For most SMB
   * requests, we just enqueue them for the smb_session_worker to
   * execute via the task queue, so they can block for resources
--- 503,519 ----
           * Mark this request so we know that we've already cleaned it up.
           * A request should only get cleaned up once so multiple calls to
           * smbsr_cleanup for the same request indicate a bug.
           */
          mutex_enter(&sr->sr_mutex);
!         if (sr->sr_state != SMB_REQ_STATE_CANCELLED)
                  sr->sr_state = SMB_REQ_STATE_CLEANED_UP;
          mutex_exit(&sr->sr_mutex);
  }
  
+ int smb_cancel_in_reader = 1;
+ 
  /*
   * This is the SMB1 handler for new smb requests, called from
   * smb_session_reader after SMB negotiate is done.  For most SMB
   * requests, we just enqueue them for the smb_session_worker to
   * execute via the task queue, so they can block for resources
*** 525,548 ****
   * will drop the session.
   */
  int
  smb1sr_newrq(smb_request_t *sr)
  {
!         uint32_t magic;
  
!         magic = SMB_READ_PROTOCOL(sr->sr_request_buf);
!         if (magic != SMB_PROTOCOL_MAGIC) {
                  smb_request_free(sr);
                  return (EPROTO);
          }
  
          if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
-                 if (SMB_IS_NT_CANCEL(sr)) {
                          sr->session->signing.seqnum++;
                          sr->sr_seqnum = sr->session->signing.seqnum + 1;
                          sr->reply_seqnum = 0;
                  } else {
                          sr->session->signing.seqnum += 2;
                          sr->sr_seqnum = sr->session->signing.seqnum;
                          sr->reply_seqnum = sr->sr_seqnum + 1;
                  }
          }
--- 529,590 ----
   * will drop the session.
   */
  int
  smb1sr_newrq(smb_request_t *sr)
  {
!         uint16_t pid_hi, pid_lo;
!         int rc, save_offset;
  
!         /*
!          * Decode the SMB header now (peek) so that
!          * SMB_COM_NT_CANCEL can find this SR.
!          */
!         save_offset = sr->command.chain_offset;
!         rc = smb_mbc_decodef(&sr->command, SMB_HEADER_ED_FMT,
!             &sr->smb_com,
!             &sr->smb_rcls,
!             &sr->smb_reh,
!             &sr->smb_err,
!             &sr->smb_flg,
!             &sr->smb_flg2,
!             &pid_hi,
!             sr->smb_sig,
!             &sr->smb_tid,
!             &pid_lo,
!             &sr->smb_uid,
!             &sr->smb_mid);
!         sr->command.chain_offset = save_offset;
!         if (rc != 0) {
!                 /* Failed decoding the header. Drop 'em. */
                  smb_request_free(sr);
                  return (EPROTO);
          }
+         sr->smb_pid = (pid_hi << 16) | pid_lo;
  
+         if (sr->smb_com == SMB_COM_NT_CANCEL) {
                  if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
                          sr->session->signing.seqnum++;
                          sr->sr_seqnum = sr->session->signing.seqnum + 1;
                          sr->reply_seqnum = 0;
+                 }
+ 
+                 /*
+                  * Normally execute cancel requests immediately,
+                  * (here in the reader thread) so they won't wait
+                  * for other commands already in the task queue.
+                  * Disable this via smb_cancel_in_reader=0 for
+                  * testing or diagnostic efforts, in which case
+                  * cancel runs via taskq_dispatch.
+                  */
+                 if (smb_cancel_in_reader != 0) {
+                         rc = smb1sr_newrq_cancel(sr);
+                         smb_request_free(sr);
+                         return (rc);
+                 }
          } else {
+                 /* not NT cancel */
+                 if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
                          sr->session->signing.seqnum += 2;
                          sr->sr_seqnum = sr->session->signing.seqnum;
                          sr->reply_seqnum = sr->sr_seqnum + 1;
                  }
          }
*** 572,599 ****
          srq = sr->session->s_srqueue;
          smb_srqueue_waitq_to_runq(srq);
          sr->sr_worker = curthread;
          sr->sr_time_active = gethrtime();
  
          mutex_enter(&sr->sr_mutex);
!         switch (sr->sr_state) {
!         case SMB_REQ_STATE_SUBMITTED:
                  mutex_exit(&sr->sr_mutex);
                  smb1sr_work(sr);
-                 sr = NULL;
-                 break;
  
-         default:
-                 /*
-                  * SMB1 requests that have been cancelled
-                  * have no reply.  Just free it.
-                  */
-                 sr->sr_state = SMB_REQ_STATE_COMPLETED;
-                 mutex_exit(&sr->sr_mutex);
-                 smb_request_free(sr);
-                 break;
-         }
          smb_srqueue_runq_exit(srq);
  }
  
  /*
   * smb1sr_work
--- 614,634 ----
          srq = sr->session->s_srqueue;
          smb_srqueue_waitq_to_runq(srq);
          sr->sr_worker = curthread;
          sr->sr_time_active = gethrtime();
  
+         /*
+          * Always dispatch to the work function, because cancelled
+          * requests need an error reply (NT_STATUS_CANCELLED).
+          */
          mutex_enter(&sr->sr_mutex);
!         if (sr->sr_state == SMB_REQ_STATE_SUBMITTED)
!                 sr->sr_state = SMB_REQ_STATE_ACTIVE;
          mutex_exit(&sr->sr_mutex);
+ 
          smb1sr_work(sr);
  
          smb_srqueue_runq_exit(srq);
  }
  
  /*
   * smb1sr_work
*** 608,617 ****
--- 643,654 ----
          const smb_disp_entry_t  *sdd;
          smb_disp_stats_t        *sds;
          boolean_t               disconnect = B_FALSE;
          smb_session_t           *session;
          smb_server_t            *server;
+         int32_t                 txbase;
+         uint32_t                rxbytes;
          uint32_t                byte_count;
          uint32_t                max_bytes;
          uint16_t                pid_hi, pid_lo;
  
          session = sr->session;
*** 676,685 ****
--- 713,725 ----
              pid_lo,
              sr->smb_uid,
              sr->smb_mid);
          sr->first_smb_com = sr->smb_com;
  
+         /* Need this for early goto report_error cases. */
+         sr->cur_reply_offset = sr->reply.chain_offset;
+ 
          if ((session->signing.flags & SMB_SIGNING_CHECK) != 0) {
                  if ((sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) == 0 ||
                      smb_sign_check_request(sr) != 0) {
                          smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
                              ERRDOS, ERROR_ACCESS_DENIED);
*** 704,717 ****
          if (smb_mbc_decodef(&sr->command, "#.w", sr->smb_wct*2, &sr->smb_bcc)) {
                  disconnect = B_TRUE;
                  goto report_error;
          }
  
-         atomic_add_64(&sds->sdt_rxb,
-             (int64_t)(sr->smb_wct * 2 + sr->smb_bcc + 1));
-         sr->sr_txb = sr->reply.chain_offset;
- 
          /*
           * Ignore smb_bcc if CAP_LARGE_READX/CAP_LARGE_WRITEX
           * and this is SmbReadX/SmbWriteX since this enables
           * large reads/write and bcc is only 16-bits.
           */
--- 744,753 ----
*** 725,734 ****
--- 761,774 ----
          } else {
                  /* ordinary case */
                  byte_count = (uint32_t)sr->smb_bcc;
          }
  
+         /* Save these for kstat updates below. */
+         rxbytes = byte_count + 1 + 2 * sr->smb_wct;
+         txbase = sr->reply.chain_offset;
+ 
          (void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command,
              sr->command.chain_offset, byte_count);
  
          sr->command.chain_offset += byte_count;
          if (sr->command.chain_offset > sr->command.max_bytes) {
*** 750,764 ****
                  sr->andx_com = (unsigned char)-1;
          }
  
          mutex_enter(&sr->sr_mutex);
          switch (sr->sr_state) {
!         case SMB_REQ_STATE_SUBMITTED:
          case SMB_REQ_STATE_CLEANED_UP:
                  sr->sr_state = SMB_REQ_STATE_ACTIVE;
                  break;
!         case SMB_REQ_STATE_CANCELED:
                  break;
          default:
                  ASSERT(0);
                  break;
          }
--- 790,809 ----
                  sr->andx_com = (unsigned char)-1;
          }
  
          mutex_enter(&sr->sr_mutex);
          switch (sr->sr_state) {
!         case SMB_REQ_STATE_ACTIVE:
!                 break;
          case SMB_REQ_STATE_CLEANED_UP:
                  sr->sr_state = SMB_REQ_STATE_ACTIVE;
                  break;
!         case SMB_REQ_STATE_CANCELLED:
!                 /*
!                  * Keep cancelled.  Handlers that might block will
!                  * check the state and return NT_STATUS_CANCELLED.
!                  */
                  break;
          default:
                  ASSERT(0);
                  break;
          }
*** 796,810 ****
  
          if (sdrc != SDRC_SR_KEPT) {
                  (*sdd->sdt_post_op)(sr);
                  smbsr_cleanup(sr);
          }
-         smb_latency_add_sample(&sds->sdt_lat, gethrtime() - sr->sr_time_start);
  
!         atomic_add_64(&sds->sdt_txb,
!             (int64_t)(sr->reply.chain_offset - sr->sr_txb));
  
          switch (sdrc) {
          case SDRC_SUCCESS:
                  break;
  
          case SDRC_DROP_VC:
--- 841,891 ----
  
          if (sdrc != SDRC_SR_KEPT) {
                  (*sdd->sdt_post_op)(sr);
                  smbsr_cleanup(sr);
          }
  
!         /* Record latency and rx/tx bytes per:  server, session, share. */
!         {
!                 hrtime_t        dt;
!                 int64_t         rxb, txb;
!                 smb_disp_stats_t        *client_sds;    /* session */
!                 smb_disp_stats_t        *share_sds;  /* kshare */
!                 int     cmd_type;
  
+                 if (sdd->sdt_flags & SDDF_READOP) {
+                         cmd_type = SMBSRV_CLSH_READ;
+                 } else if (sdd->sdt_flags & SDDF_WRITEOP) {
+                         cmd_type = SMBSRV_CLSH_WRITE;
+                 } else {
+                         cmd_type = SMBSRV_CLSH_OTHER;
+                 }
+ 
+                 dt = gethrtime() - sr->sr_time_start;
+                 rxb = (int64_t)rxbytes;
+                 txb = (int64_t)(sr->reply.chain_offset - txbase);
+ 
+                 smb_server_inc_req(server);
+                 smb_latency_add_sample(&sds->sdt_lat, dt);
+                 atomic_add_64(&sds->sdt_rxb, rxb);
+                 atomic_add_64(&sds->sdt_txb, txb);
+ 
+                 client_sds = &session->s_stats[cmd_type];
+                 smb_latency_add_sample(&client_sds->sdt_lat, dt);
+                 atomic_add_64(&client_sds->sdt_rxb, rxb);
+                 atomic_add_64(&client_sds->sdt_txb, txb);
+ 
+                 if ((sr->tid_tree != NULL) &&
+                     (sr->tid_tree->t_kshare != NULL)) {
+                         share_sds =
+                             &sr->tid_tree->t_kshare->shr_stats[cmd_type];
+                         smb_latency_add_sample(&share_sds->sdt_lat, dt);
+                         atomic_add_64(&share_sds->sdt_rxb, rxb);
+                         atomic_add_64(&share_sds->sdt_txb, txb);
+                 }
+         }
+ 
          switch (sdrc) {
          case SDRC_SUCCESS:
                  break;
  
          case SDRC_DROP_VC:
*** 859,881 ****
  
  reply_ready:
          smbsr_send_reply(sr);
  
  drop_connection:
!         if (disconnect) {
!                 smb_rwx_rwenter(&session->s_lock, RW_WRITER);
!                 switch (session->s_state) {
!                 case SMB_SESSION_STATE_DISCONNECTED:
!                 case SMB_SESSION_STATE_TERMINATED:
!                         break;
!                 default:
!                         smb_soshutdown(session->sock);
!                         session->s_state = SMB_SESSION_STATE_DISCONNECTED;
!                         break;
!                 }
!                 smb_rwx_rwexit(&session->s_lock);
!         }
  
  out:
          if (sr != NULL) {
                  mutex_enter(&sr->sr_mutex);
                  sr->sr_state = SMB_REQ_STATE_COMPLETED;
--- 940,951 ----
  
  reply_ready:
          smbsr_send_reply(sr);
  
  drop_connection:
!         if (disconnect)
!                 smb_session_disconnect(session);
  
  out:
          if (sr != NULL) {
                  mutex_enter(&sr->sr_mutex);
                  sr->sr_state = SMB_REQ_STATE_COMPLETED;
*** 1184,1201 ****
   * transports and NT supports mpx only over connectionless transports.
   */
  smb_sdrc_t
  smb_pre_invalid(smb_request_t *sr)
  {
!         DTRACE_SMB_1(op__Invalid__start, smb_request_t *, sr);
          return (SDRC_SUCCESS);
  }
  
  void
  smb_post_invalid(smb_request_t *sr)
  {
!         DTRACE_SMB_1(op__Invalid__done, smb_request_t *, sr);
  }
  
  smb_sdrc_t
  smb_com_invalid(smb_request_t *sr)
  {
--- 1254,1271 ----
   * transports and NT supports mpx only over connectionless transports.
   */
  smb_sdrc_t
  smb_pre_invalid(smb_request_t *sr)
  {
!         DTRACE_SMB_START(op__Invalid, smb_request_t *, sr);
          return (SDRC_SUCCESS);
  }
  
  void
  smb_post_invalid(smb_request_t *sr)
  {
!         DTRACE_SMB_DONE(op__Invalid, smb_request_t *, sr);
  }
  
  smb_sdrc_t
  smb_com_invalid(smb_request_t *sr)
  {