Print this page
NEX-20459 smb/server service restart fails, stuck in offlining state
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
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-18748 (Hyper-V 2016) VM goes to poweroff state when smbd is restarted
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
NEX-17589 Get "too high" smbd error when copy big file to cifs share (redo)
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-16519 Panic while running IOmeter to a pool through an SMB share
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@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-15581 SMB keep-alive feature is just noise
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-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@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-15581 SMB keep-alive feature is just noise
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-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@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-5273 SMB 3 Encryption
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-8120 smbstat -C requires IPv4 addresses to be prefixed with ::ffff: if ipv6_enable is true
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
NEX-6308 namespace collision for per-share kstats when changing sharesmb property
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-5845 rework SMB immediate cancel
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-5560 smb2 should use 64-bit server-global uids
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-5537 Want reference counts for users, trees...
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-5330 SMB server should combine TCP+NBT session lists
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-3906 Prefer that SMB change notify not tie up a worker thread
NEX-5278 SMB notify should buffer per file handle
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-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-4714 smbstat -t tbytes/s always zero
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-2522 svcadm disable network/smb/server may hang
Reviewed by: Matt Barden <Matt.Barden@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-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>
SUP-672 Zero-padded IP address strings returned by SMB server...
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-3738 Should support SMB2_CAP_LARGE_MTU
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-3610 CLONE NEX-3591 SMB3 signing
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-3004 Keep track of remote TCP port
Reviewed by: Dan Fields <Dan.Fields@nexenta.com>
Reviewed by: Josef Sipek <Josef.Sipek@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Kevin Crowe <Kevin.Crowe@nexenta.com>
Reviewed by: Alek Pinchuk <Alek.Pinchuk@nexenta.com>
Reviewed by: Rick McNeal <Rick.McNeal@nexenta.com>
NEX-2798 SMB 1 disconnects after large write attempt
NEX-2781 SMB2 credit handling needs work
NEX-2353 Codenomicon: SMB2 TC # 448950 - PANIC in SMB2.Compounded-commands...
NEX-1991 SMB2 never grants level II oplocks
SMB-137 assertion failed: (sr->reply.chain_offset & 7) == 0, file: ../../common/fs/smbsrv/smb2_dispatch.c, line: 727
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-50 User-mode SMB server (fix elfchk noise)
SMB-56 extended security NTLMSSP, inbound (fix a leak)
SMB-39 Use AF_UNIX pipes for RPC (fix a leak)
SMB-75 smb_session_timers way too frequent
SMB-69 read-raw, write-raw are dead code
SMB-56 extended security NTLMSSP, inbound
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 (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
SMB-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
Fix up some merges where we wanted the upstream version.
SMB-48 Panic with smbtorture raw.scan-eamax
re #7126 rb4153 smbd panic with missing negotiate challenge
re #11215 rb3676 sesctl to SGI JBOD hangs in biowait() with a command stuck in mptsas driver
re #10734 NT Trans. Notify returning too quickly
re #6813 rb1757 port 2976 Child folder visibility through shares

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbsrv/smb_session.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_session.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 2015 Nexenta Systems, Inc.  All rights reserved.
       23 + * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  
  26   26  #include <sys/atomic.h>
  27   27  #include <sys/synch.h>
  28   28  #include <sys/types.h>
  29   29  #include <sys/sdt.h>
  30   30  #include <sys/random.h>
  31   31  #include <smbsrv/netbios.h>
  32   32  #include <smbsrv/smb2_kproto.h>
  33   33  #include <smbsrv/string.h>
↓ open down ↓ 5 lines elided ↑ open up ↑
  39   39  #define SMB_NEW_KID()   atomic_inc_64_nv(&smb_kids)
  40   40  
  41   41  static volatile uint64_t smb_kids;
  42   42  
  43   43  /*
  44   44   * We track the keepalive in minutes, but this constant
  45   45   * specifies it in seconds, so convert to minutes.
  46   46   */
  47   47  uint32_t smb_keep_alive = SMB_PI_KEEP_ALIVE_MIN / 60;
  48   48  
       49 +/*
       50 + * There are many smbtorture test cases that send
       51 + * racing requests, and where the tests fail if we
       52 + * don't execute them in exactly the order sent.
       53 + * These are test bugs.  The protocol makes no
       54 + * guarantees about execution order of requests
       55 + * that are concurrently active.
       56 + *
       57 + * Nonetheless, smbtorture has many useful tests,
       58 + * so we have this work-around we can enable to
       59 + * basically force sequential execution.  When
       60 + * enabled, insert a delay after each request is
       61 + * issued a taskq job.  Enable this with mdb by
       62 + * setting smb_reader_delay to 10.  Don't make it
       63 + * more than 500 or so or the server will appear
       64 + * to be so slow that tests may time out.
       65 + */
       66 +int smb_reader_delay = 0;  /* mSec. */
       67 +
  49   68  static int  smbsr_newrq_initial(smb_request_t *);
  50   69  
  51   70  static void smb_session_cancel(smb_session_t *);
  52   71  static int smb_session_reader(smb_session_t *);
  53   72  static int smb_session_xprt_puthdr(smb_session_t *,
  54   73      uint8_t msg_type, uint32_t msg_len,
  55   74      uint8_t *dst, size_t dstlen);
  56      -static smb_tree_t *smb_session_get_tree(smb_session_t *, smb_tree_t *);
  57      -static void smb_session_logoff(smb_session_t *);
       75 +static void smb_session_disconnect_trees(smb_session_t  *);
  58   76  static void smb_request_init_command_mbuf(smb_request_t *sr);
  59   77  static void smb_session_genkey(smb_session_t *);
       78 +static int smb_session_kstat_update(kstat_t *, int);
       79 +void session_stats_init(smb_server_t *, smb_session_t *);
       80 +void session_stats_fini(smb_session_t *);
  60   81  
       82 +/*
       83 + * This (legacy) code is in support of an "idle timeout" feature,
       84 + * which is apparently incomplete.  To complete it, we should:
       85 + * when the keep_alive timer expires, check whether the client
       86 + * has any open files, and if not then kill their session.
       87 + * Right now the timers are there, but nothing happens when
       88 + * a timer expires.
       89 + *
       90 + * Todo: complete logic to kill idle sessions.
       91 + *
       92 + * Only called when sv_cfg.skc_keepalive != 0
       93 + */
  61   94  void
  62      -smb_session_timers(smb_llist_t *ll)
       95 +smb_session_timers(smb_server_t *sv)
  63   96  {
  64   97          smb_session_t   *session;
       98 +        smb_llist_t     *ll;
  65   99  
      100 +        ll = &sv->sv_session_list;
  66  101          smb_llist_enter(ll, RW_READER);
  67  102          session = smb_llist_head(ll);
  68  103          while (session != NULL) {
  69  104                  /*
  70  105                   * Walk through the table and decrement each keep_alive
  71  106                   * timer that has not timed out yet. (keepalive > 0)
  72  107                   */
  73  108                  SMB_SESSION_VALID(session);
  74  109                  if (session->keep_alive &&
  75  110                      (session->keep_alive != (uint32_t)-1))
  76  111                          session->keep_alive--;
      112 +
  77  113                  session = smb_llist_next(ll, session);
  78  114          }
  79  115          smb_llist_exit(ll);
  80  116  }
  81  117  
  82      -void
  83      -smb_session_correct_keep_alive_values(smb_llist_t *ll, uint32_t new_keep_alive)
  84      -{
  85      -        smb_session_t           *sn;
  86      -
  87      -        /*
  88      -         * Caller specifies seconds, but we track in minutes, so
  89      -         * convert to minutes (rounded up).
  90      -         */
  91      -        new_keep_alive = (new_keep_alive + 59) / 60;
  92      -
  93      -        if (new_keep_alive == smb_keep_alive)
  94      -                return;
  95      -        /*
  96      -         * keep alive == 0 means do not drop connection if it's idle
  97      -         */
  98      -        smb_keep_alive = (new_keep_alive) ? new_keep_alive : -1;
  99      -
 100      -        /*
 101      -         * Walk through the table and set each session to the new keep_alive
 102      -         * value if they have not already timed out.  Block clock interrupts.
 103      -         */
 104      -        smb_llist_enter(ll, RW_READER);
 105      -        sn = smb_llist_head(ll);
 106      -        while (sn != NULL) {
 107      -                SMB_SESSION_VALID(sn);
 108      -                if (sn->keep_alive != 0)
 109      -                        sn->keep_alive = new_keep_alive;
 110      -                sn = smb_llist_next(ll, sn);
 111      -        }
 112      -        smb_llist_exit(ll);
 113      -}
 114      -
 115  118  /*
 116  119   * Send a session message - supports SMB-over-NBT and SMB-over-TCP.
 117  120   * If an mbuf chain is provided (optional), it will be freed and
 118  121   * set to NULL -- unconditionally!  (error or not)
 119  122   *
 120  123   * Builds a I/O vector (uio/iov) to do the send from mbufs, plus one
 121  124   * segment for the 4-byte NBT header.
 122  125   */
 123  126  int
 124  127  smb_session_send(smb_session_t *session, uint8_t nbt_type, mbuf_chain_t *mbc)
↓ open down ↓ 91 lines elided ↑ open up ↑
 216  219   * Session requests are not valid for SMB-over-TCP, which is unfortunate
 217  220   * because without the client name leftover state cannot be cleaned up
 218  221   * if the client is behind a NAT server.
 219  222   */
 220  223  static int
 221  224  smb_netbios_session_request(struct smb_session *session)
 222  225  {
 223  226          int                     rc;
 224  227          char                    *calling_name;
 225  228          char                    *called_name;
 226      -        char                    client_name[NETBIOS_NAME_SZ];
 227      -        struct mbuf_chain       mbc;
 228      -        char                    *names = NULL;
      229 +        char                    client_name[NETBIOS_NAME_SZ];
      230 +        struct mbuf_chain       mbc;
      231 +        char                    *names = NULL;
 229  232          smb_wchar_t             *wbuf = NULL;
 230  233          smb_xprt_t              hdr;
 231  234          char *p;
 232  235          int rc1, rc2;
 233  236  
 234  237          session->keep_alive = smb_keep_alive;
 235  238  
 236  239          if ((rc = smb_session_xprt_gethdr(session, &hdr)) != 0)
 237  240                  return (rc);
 238  241  
↓ open down ↓ 171 lines elided ↑ open up ↑
 410  413  
 411  414  /*
 412  415   * smb_request_cancel
 413  416   *
 414  417   * Handle a cancel for a request properly depending on the current request
 415  418   * state.
 416  419   */
 417  420  void
 418  421  smb_request_cancel(smb_request_t *sr)
 419  422  {
      423 +        void (*cancel_method)(smb_request_t *) = NULL;
      424 +
 420  425          mutex_enter(&sr->sr_mutex);
 421  426          switch (sr->sr_state) {
 422  427  
 423  428          case SMB_REQ_STATE_INITIALIZING:
 424  429          case SMB_REQ_STATE_SUBMITTED:
 425  430          case SMB_REQ_STATE_ACTIVE:
 426  431          case SMB_REQ_STATE_CLEANED_UP:
 427      -                sr->sr_state = SMB_REQ_STATE_CANCELED;
      432 +                sr->sr_state = SMB_REQ_STATE_CANCELLED;
 428  433                  break;
 429  434  
      435 +        case SMB_REQ_STATE_WAITING_AUTH:
      436 +        case SMB_REQ_STATE_WAITING_FCN1:
 430  437          case SMB_REQ_STATE_WAITING_LOCK:
      438 +        case SMB_REQ_STATE_WAITING_PIPE:
 431  439                  /*
 432      -                 * This request is waiting on a lock.  Wakeup everything
 433      -                 * waiting on the lock so that the relevant thread regains
 434      -                 * control and notices that is has been canceled.  The
 435      -                 * other lock request threads waiting on this lock will go
 436      -                 * back to sleep when they discover they are still blocked.
      440 +                 * These are states that have a cancel_method.
      441 +                 * Make the state change now, to ensure that
      442 +                 * we call cancel_method exactly once.  Do the
      443 +                 * method call below, after we drop sr_mutex.
      444 +                 * When the cancelled request thread resumes,
      445 +                 * it should re-take sr_mutex and set sr_state
      446 +                 * to CANCELLED, then return STATUS_CANCELLED.
 437  447                   */
 438      -                sr->sr_state = SMB_REQ_STATE_CANCELED;
 439      -
 440      -                ASSERT(sr->sr_awaiting != NULL);
 441      -                mutex_enter(&sr->sr_awaiting->l_mutex);
 442      -                cv_broadcast(&sr->sr_awaiting->l_cv);
 443      -                mutex_exit(&sr->sr_awaiting->l_mutex);
      448 +                sr->sr_state = SMB_REQ_STATE_CANCEL_PENDING;
      449 +                cancel_method = sr->cancel_method;
      450 +                VERIFY(cancel_method != NULL);
 444  451                  break;
 445  452  
 446      -        case SMB_REQ_STATE_WAITING_EVENT:
 447      -                /*
 448      -                 * This request is waiting in change notify.
 449      -                 */
 450      -                sr->sr_state = SMB_REQ_STATE_CANCELED;
 451      -                cv_signal(&sr->sr_ncr.nc_cv);
 452      -                break;
 453      -
 454      -        case SMB_REQ_STATE_EVENT_OCCURRED:
      453 +        case SMB_REQ_STATE_WAITING_FCN2:
 455  454          case SMB_REQ_STATE_COMPLETED:
 456      -        case SMB_REQ_STATE_CANCELED:
      455 +        case SMB_REQ_STATE_CANCEL_PENDING:
      456 +        case SMB_REQ_STATE_CANCELLED:
 457  457                  /*
 458  458                   * No action required for these states since the request
 459  459                   * is completing.
 460  460                   */
 461  461                  break;
 462  462  
 463  463          case SMB_REQ_STATE_FREE:
 464  464          default:
 465  465                  SMB_PANIC();
 466  466          }
 467  467          mutex_exit(&sr->sr_mutex);
      468 +
      469 +        if (cancel_method != NULL) {
      470 +                cancel_method(sr);
      471 +        }
 468  472  }
 469  473  
 470  474  /*
 471  475   * smb_session_receiver
 472  476   *
 473  477   * Receives request from the network and dispatches them to a worker.
      478 + *
      479 + * When we receive a disconnect here, it _could_ be due to the server
      480 + * having initiated disconnect, in which case the session state will be
      481 + * SMB_SESSION_STATE_TERMINATED and we want to keep that state so later
      482 + * tear-down logic will know which side initiated.
 474  483   */
 475  484  void
 476  485  smb_session_receiver(smb_session_t *session)
 477  486  {
 478  487          int     rc = 0;
 479  488  
 480  489          SMB_SESSION_VALID(session);
 481  490  
 482  491          session->s_thread = curthread;
 483  492  
 484  493          if (session->s_local_port == IPPORT_NETBIOS_SSN) {
 485  494                  rc = smb_netbios_session_request(session);
 486  495                  if (rc != 0) {
 487  496                          smb_rwx_rwenter(&session->s_lock, RW_WRITER);
 488      -                        session->s_state = SMB_SESSION_STATE_DISCONNECTED;
      497 +                        if (session->s_state != SMB_SESSION_STATE_TERMINATED)
      498 +                                session->s_state =
      499 +                                    SMB_SESSION_STATE_DISCONNECTED;
 489  500                          smb_rwx_rwexit(&session->s_lock);
 490  501                          return;
 491  502                  }
 492  503          }
 493  504  
 494  505          smb_rwx_rwenter(&session->s_lock, RW_WRITER);
 495  506          session->s_state = SMB_SESSION_STATE_ESTABLISHED;
 496  507          smb_rwx_rwexit(&session->s_lock);
 497  508  
 498  509          (void) smb_session_reader(session);
 499  510  
 500  511          smb_rwx_rwenter(&session->s_lock, RW_WRITER);
 501      -        session->s_state = SMB_SESSION_STATE_DISCONNECTED;
      512 +        if (session->s_state != SMB_SESSION_STATE_TERMINATED)
      513 +                session->s_state = SMB_SESSION_STATE_DISCONNECTED;
 502  514          smb_rwx_rwexit(&session->s_lock);
 503  515  
 504  516          smb_soshutdown(session->sock);
 505  517  
 506  518          DTRACE_PROBE2(session__drop, struct session *, session, int, rc);
 507  519  
 508  520          smb_session_cancel(session);
 509  521          /*
 510  522           * At this point everything related to the session should have been
 511  523           * cleaned up and we expect that nothing will attempt to use the
 512  524           * socket.
 513  525           */
 514  526  }
 515  527  
 516  528  /*
 517  529   * smb_session_disconnect
 518  530   *
 519      - * Disconnects the session passed in.
      531 + * Server-initiated disconnect (i.e. server shutdown)
 520  532   */
 521  533  void
 522  534  smb_session_disconnect(smb_session_t *session)
 523  535  {
 524  536          SMB_SESSION_VALID(session);
 525  537  
 526  538          smb_rwx_rwenter(&session->s_lock, RW_WRITER);
 527  539          switch (session->s_state) {
 528  540          case SMB_SESSION_STATE_INITIALIZED:
 529  541          case SMB_SESSION_STATE_CONNECTED:
 530  542          case SMB_SESSION_STATE_ESTABLISHED:
 531  543          case SMB_SESSION_STATE_NEGOTIATED:
 532  544                  smb_soshutdown(session->sock);
 533      -                session->s_state = SMB_SESSION_STATE_DISCONNECTED;
 534      -                _NOTE(FALLTHRU)
      545 +                session->s_state = SMB_SESSION_STATE_TERMINATED;
      546 +                break;
 535  547          case SMB_SESSION_STATE_DISCONNECTED:
 536  548          case SMB_SESSION_STATE_TERMINATED:
 537  549                  break;
 538  550          }
 539  551          smb_rwx_rwexit(&session->s_lock);
 540  552  }
 541  553  
 542  554  /*
 543  555   * Read and process SMB requests.
 544  556   *
↓ open down ↓ 50 lines elided ↑ open up ↑
 595  607  
 596  608                  if (hdr.xh_length < SMB_HEADER_LEN)
 597  609                          return (EPROTO);
 598  610                  if (hdr.xh_length > session->cmd_max_bytes)
 599  611                          return (EPROTO);
 600  612  
 601  613                  session->keep_alive = smb_keep_alive;
 602  614  
 603  615                  /*
 604  616                   * Allocate a request context, read the whole message.
      617 +                 * If the request alloc fails, we've disconnected
      618 +                 * and won't be able to send the reply anyway, so bail now.
 605  619                   */
 606      -                sr = smb_request_alloc(session, hdr.xh_length);
      620 +                if ((sr = smb_request_alloc(session, hdr.xh_length)) == NULL)
      621 +                        break;
 607  622  
 608  623                  req_buf = (uint8_t *)sr->sr_request_buf;
 609  624                  resid = hdr.xh_length;
 610  625  
 611  626                  rc = smb_sorecv(session->sock, req_buf, resid);
 612  627                  if (rc) {
 613  628                          smb_request_free(sr);
 614  629                          break;
 615  630                  }
 616  631  
 617      -                /* accounting: requests, received bytes */
 618      -                smb_server_inc_req(sv);
      632 +                /* accounting: received bytes */
 619  633                  smb_server_add_rxb(sv,
 620  634                      (int64_t)(hdr.xh_length + NETBIOS_HDR_SZ));
 621  635  
 622  636                  /*
 623  637                   * Initialize command MBC to represent the received data.
 624  638                   */
 625  639                  smb_request_init_command_mbuf(sr);
 626  640  
 627  641                  DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr);
 628  642  
 629  643                  rc = session->newrq_func(sr);
 630  644                  sr = NULL;      /* enqueued or freed */
 631  645                  if (rc != 0)
 632  646                          break;
      647 +
      648 +                /* See notes where this is defined (above). */
      649 +                if (smb_reader_delay) {
      650 +                        delay(MSEC_TO_TICK(smb_reader_delay));
      651 +                }
 633  652          }
 634  653          return (rc);
 635  654  }
 636  655  
 637  656  /*
 638  657   * This is the initial handler for new smb requests, called from
 639  658   * from smb_session_reader when we have not yet seen any requests.
 640  659   * The first SMB request must be "negotiate", which determines
 641  660   * which protocol and dialect we'll be using.  That's the ONLY
 642  661   * request type handled here, because with all later requests,
 643  662   * we know the protocol and handle those with either the SMB1 or
 644  663   * SMB2 handlers:  smb1sr_post() or smb2sr_post().
 645  664   * Those do NOT allow SMB negotiate, because that's only allowed
 646  665   * as the first request on new session.
 647  666   *
 648  667   * This and other "post a request" handlers must either enqueue
 649  668   * the new request for the session taskq, or smb_request_free it
 650  669   * (in case we've decided to drop this connection).  In this
 651  670   * (special) new request handler, we always free the request.
      671 + *
      672 + * Return value is 0 for success, and anything else will
      673 + * terminate the reader thread (drop the connection).
 652  674   */
 653  675  static int
 654  676  smbsr_newrq_initial(smb_request_t *sr)
 655  677  {
 656  678          uint32_t magic;
 657  679          int rc = EPROTO;
 658  680  
 659  681          mutex_enter(&sr->sr_mutex);
 660  682          sr->sr_state = SMB_REQ_STATE_ACTIVE;
 661  683          mutex_exit(&sr->sr_mutex);
↓ open down ↓ 34 lines elided ↑ open up ↑
 696  718                  return (NULL);
 697  719          }
 698  720          if (smb_idpool_constructor(&session->s_tid_pool)) {
 699  721                  smb_idpool_destructor(&session->s_uid_pool);
 700  722                  kmem_cache_free(smb_cache_session, session);
 701  723                  return (NULL);
 702  724          }
 703  725  
 704  726          now = ddi_get_lbolt64();
 705  727  
      728 +        session->s_server = sv;
 706  729          session->s_kid = SMB_NEW_KID();
 707  730          session->s_state = SMB_SESSION_STATE_INITIALIZED;
 708  731          session->native_os = NATIVE_OS_UNKNOWN;
 709  732          session->opentime = now;
 710  733          session->keep_alive = smb_keep_alive;
 711  734          session->activity_timestamp = now;
 712      -
 713  735          smb_session_genkey(session);
 714  736  
 715  737          mutex_init(&session->s_credits_mutex, NULL, MUTEX_DEFAULT, NULL);
 716  738  
 717  739          smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t),
 718  740              offsetof(smb_request_t, sr_session_lnd));
 719  741  
 720  742          smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t),
 721  743              offsetof(smb_user_t, u_lnd));
 722  744  
 723  745          smb_llist_constructor(&session->s_tree_list, sizeof (smb_tree_t),
 724  746              offsetof(smb_tree_t, t_lnd));
 725  747  
 726  748          smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t),
 727  749              offsetof(smb_xa_t, xa_lnd));
 728  750  
 729  751          smb_net_txl_constructor(&session->s_txlst);
 730  752  
 731  753          smb_rwx_init(&session->s_lock);
 732  754  
 733      -        if (new_so != NULL) {
      755 +        session->s_srqueue = &sv->sv_srqueue;
      756 +        smb_server_get_cfg(sv, &session->s_cfg);
      757 +
      758 +        if (new_so == NULL) {
      759 +                /*
      760 +                 * This call is creating the special "server" session,
      761 +                 * used for kshare export, oplock breaks, CA import.
      762 +                 * CA import creates temporary trees on this session
      763 +                 * and those should never get map/unmap up-calls, so
      764 +                 * force the map/unmap flags zero on this session.
      765 +                 * Set a "modern" dialect for CA import too, so
      766 +                 * pathname parse doesn't do OS/2 stuff, etc.
      767 +                 */
      768 +                session->s_cfg.skc_execflags = 0;
      769 +                session->dialect = session->s_cfg.skc_max_protocol;
      770 +        } else {
 734  771                  if (family == AF_INET) {
 735  772                          slen = sizeof (sin);
 736  773                          (void) ksocket_getsockname(new_so,
 737  774                              (struct sockaddr *)&sin, &slen, CRED());
 738  775                          bcopy(&sin.sin_addr,
 739  776                              &session->local_ipaddr.au_addr.au_ipv4,
 740  777                              sizeof (in_addr_t));
 741  778                          slen = sizeof (sin);
 742  779                          (void) ksocket_getpeername(new_so,
 743  780                              (struct sockaddr *)&sin, &slen, CRED());
↓ open down ↓ 21 lines elided ↑ open up ↑
 765  802                  session->s_local_port = port;
 766  803                  session->s_remote_port = ntohs(rport);
 767  804                  session->sock = new_so;
 768  805                  (void) smb_inet_ntop(&session->ipaddr,
 769  806                      session->ip_addr_str, INET6_ADDRSTRLEN);
 770  807                  if (port == IPPORT_NETBIOS_SSN)
 771  808                          smb_server_inc_nbt_sess(sv);
 772  809                  else
 773  810                          smb_server_inc_tcp_sess(sv);
 774  811          }
 775      -        session->s_server = sv;
 776      -        smb_server_get_cfg(sv, &session->s_cfg);
 777      -        session->s_srqueue = &sv->sv_srqueue;
 778  812  
 779  813          /*
 780  814           * The initial new request handler is special,
 781  815           * and only accepts negotiation requests.
 782  816           */
 783  817          session->newrq_func = smbsr_newrq_initial;
 784  818  
 785  819          /* These may increase in SMB2 negotiate. */
 786  820          session->cmd_max_bytes = SMB_REQ_MAX_SIZE;
 787  821          session->reply_max_bytes = SMB_REQ_MAX_SIZE;
 788  822  
      823 +        session_stats_init(sv, session);
      824 +
 789  825          session->s_magic = SMB_SESSION_MAGIC;
      826 +
 790  827          return (session);
 791  828  }
 792  829  
 793  830  void
      831 +session_stats_init(smb_server_t *sv, smb_session_t *ss)
      832 +{
      833 +        static const char       *kr_names[] = SMBSRV_CLSH__NAMES;
      834 +        char                    ks_name[KSTAT_STRLEN];
      835 +        char                    *ipaddr_str = ss->ip_addr_str;
      836 +        smbsrv_clsh_kstats_t    *ksr;
      837 +        int                     idx;
      838 +
      839 +        /* Don't include the special internal session (sv->sv_session). */
      840 +        if (ss->sock == NULL)
      841 +                return;
      842 +
      843 +        /*
      844 +         * If ipv6_enable is set to true, IPv4 addresses will be prefixed
      845 +         * with ::ffff: (IPv4-mapped IPv6 address), strip it.
      846 +         */
      847 +        if (strncasecmp(ipaddr_str, "::ffff:", 7) == 0)
      848 +                ipaddr_str += 7;
      849 +
      850 +        /*
      851 +         * Create raw kstats for sessions with a name composed as:
      852 +         * cl/$IPADDR  and instance ss->s_kid
      853 +         * These will look like: smbsrv:0:cl/10.10.0.5
      854 +         */
      855 +        (void) snprintf(ks_name, sizeof (ks_name), "cl/%s", ipaddr_str);
      856 +
      857 +        ss->s_ksp = kstat_create_zone(SMBSRV_KSTAT_MODULE, ss->s_kid,
      858 +            ks_name, SMBSRV_KSTAT_CLASS, KSTAT_TYPE_RAW,
      859 +            sizeof (smbsrv_clsh_kstats_t), 0, sv->sv_zid);
      860 +
      861 +        if (ss->s_ksp == NULL)
      862 +                return;
      863 +
      864 +        ss->s_ksp->ks_update = smb_session_kstat_update;
      865 +        ss->s_ksp->ks_private = ss;
      866 +
      867 +        /*
      868 +         * In-line equivalent of smb_dispatch_stats_init
      869 +         */
      870 +        ksr = (smbsrv_clsh_kstats_t *)ss->s_ksp->ks_data;
      871 +        for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++) {
      872 +                smb_latency_init(&ss->s_stats[idx].sdt_lat);
      873 +                (void) strlcpy(ksr->ks_clsh[idx].kr_name, kr_names[idx],
      874 +                    KSTAT_STRLEN);
      875 +        }
      876 +
      877 +        kstat_install(ss->s_ksp);
      878 +}
      879 +
      880 +void
      881 +session_stats_fini(smb_session_t *ss)
      882 +{
      883 +        int     idx;
      884 +
      885 +        for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++)
      886 +                smb_latency_destroy(&ss->s_stats[idx].sdt_lat);
      887 +}
      888 +
      889 +/*
      890 + * Update the kstat data from our private stats.
      891 + */
      892 +static int
      893 +smb_session_kstat_update(kstat_t *ksp, int rw)
      894 +{
      895 +        smb_session_t *session;
      896 +        smb_disp_stats_t *sds;
      897 +        smbsrv_clsh_kstats_t    *clsh;
      898 +        smb_kstat_req_t *ksr;
      899 +        int i;
      900 +
      901 +        if (rw == KSTAT_WRITE)
      902 +                return (EACCES);
      903 +
      904 +        session = ksp->ks_private;
      905 +        SMB_SESSION_VALID(session);
      906 +        sds = session->s_stats;
      907 +
      908 +        clsh = (smbsrv_clsh_kstats_t *)ksp->ks_data;
      909 +        ksr = clsh->ks_clsh;
      910 +
      911 +        for (i = 0; i < SMBSRV_CLSH__NREQ; i++, ksr++, sds++) {
      912 +                ksr->kr_rxb = sds->sdt_rxb;
      913 +                ksr->kr_txb = sds->sdt_txb;
      914 +                mutex_enter(&sds->sdt_lat.ly_mutex);
      915 +                ksr->kr_nreq = sds->sdt_lat.ly_a_nreq;
      916 +                ksr->kr_sum = sds->sdt_lat.ly_a_sum;
      917 +                ksr->kr_a_mean = sds->sdt_lat.ly_a_mean;
      918 +                ksr->kr_a_stddev = sds->sdt_lat.ly_a_stddev;
      919 +                ksr->kr_d_mean = sds->sdt_lat.ly_d_mean;
      920 +                ksr->kr_d_stddev = sds->sdt_lat.ly_d_stddev;
      921 +                sds->sdt_lat.ly_d_mean = 0;
      922 +                sds->sdt_lat.ly_d_nreq = 0;
      923 +                sds->sdt_lat.ly_d_stddev = 0;
      924 +                sds->sdt_lat.ly_d_sum = 0;
      925 +                mutex_exit(&sds->sdt_lat.ly_mutex);
      926 +        }
      927 +
      928 +        return (0);
      929 +}
      930 +
      931 +void
 794  932  smb_session_delete(smb_session_t *session)
 795  933  {
 796  934  
 797  935          ASSERT(session->s_magic == SMB_SESSION_MAGIC);
 798  936  
      937 +        if (session->s_ksp != NULL) {
      938 +                kstat_delete(session->s_ksp);
      939 +                session->s_ksp = NULL;
      940 +                session_stats_fini(session);
      941 +        }
      942 +
      943 +        if (session->enc_mech != NULL)
      944 +                smb3_encrypt_fini(session);
      945 +
 799  946          if (session->sign_fini != NULL)
 800  947                  session->sign_fini(session);
 801  948  
 802  949          if (session->signing.mackey != NULL) {
 803  950                  kmem_free(session->signing.mackey,
 804  951                      session->signing.mackey_len);
 805  952          }
 806  953  
 807  954          session->s_magic = 0;
 808  955  
↓ open down ↓ 31 lines elided ↑ open up ↑
 840  987          /* All the request currently being treated must be canceled. */
 841  988          smb_session_cancel_requests(session, NULL, NULL);
 842  989  
 843  990          /*
 844  991           * We wait for the completion of all the requests associated with
 845  992           * this session.
 846  993           */
 847  994          smb_slist_wait_for_empty(&session->s_req_list);
 848  995  
 849  996          /*
 850      -         * At this point the reference count of the users, trees, files,
 851      -         * directories should be zero. It should be possible to destroy them
 852      -         * without any problem.
      997 +         * Cleanup transact state objects
 853  998           */
 854  999          xa = smb_llist_head(&session->s_xa_list);
 855 1000          while (xa) {
 856 1001                  nextxa = smb_llist_next(&session->s_xa_list, xa);
 857 1002                  smb_xa_close(xa);
 858 1003                  xa = nextxa;
 859 1004          }
 860 1005  
     1006 +        /*
     1007 +         * At this point the reference count of the files and directories
     1008 +         * should be zero. It should be possible to destroy them without
     1009 +         * any problem, which should trigger the destruction of other objects.
     1010 +         */
 861 1011          smb_session_logoff(session);
 862 1012  }
 863 1013  
 864 1014  /*
 865 1015   * Cancel requests.  If a non-null tree is specified, only requests specific
 866 1016   * to that tree will be cancelled.  If a non-null sr is specified, that sr
 867 1017   * will be not be cancelled - this would typically be the caller's sr.
 868 1018   */
 869 1019  void
 870 1020  smb_session_cancel_requests(
↓ open down ↓ 17 lines elided ↑ open up ↑
 888 1038  
 889 1039          smb_slist_exit(&session->s_req_list);
 890 1040  }
 891 1041  
 892 1042  /*
 893 1043   * Find a user on the specified session by SMB UID.
 894 1044   */
 895 1045  smb_user_t *
 896 1046  smb_session_lookup_uid(smb_session_t *session, uint16_t uid)
 897 1047  {
 898      -        return (smb_session_lookup_uid_st(session, uid,
     1048 +        return (smb_session_lookup_uid_st(session, 0, uid,
 899 1049              SMB_USER_STATE_LOGGED_ON));
 900 1050  }
 901 1051  
     1052 +/*
     1053 + * Find a user on the specified session by SMB2 SSNID.
     1054 + */
 902 1055  smb_user_t *
 903      -smb_session_lookup_uid_st(smb_session_t *session, uint16_t uid,
 904      -    smb_user_state_t st)
     1056 +smb_session_lookup_ssnid(smb_session_t *session, uint64_t ssnid)
 905 1057  {
     1058 +        return (smb_session_lookup_uid_st(session, ssnid, 0,
     1059 +            SMB_USER_STATE_LOGGED_ON));
     1060 +}
     1061 +
     1062 +smb_user_t *
     1063 +smb_session_lookup_uid_st(smb_session_t *session, uint64_t ssnid,
     1064 +    uint16_t uid, smb_user_state_t st)
     1065 +{
 906 1066          smb_user_t      *user;
 907 1067          smb_llist_t     *user_list;
 908 1068  
 909 1069          SMB_SESSION_VALID(session);
 910 1070  
 911 1071          user_list = &session->s_user_list;
 912 1072          smb_llist_enter(user_list, RW_READER);
 913 1073  
 914      -        user = smb_llist_head(user_list);
 915      -        while (user) {
     1074 +        for (user = smb_llist_head(user_list);
     1075 +            user != NULL;
     1076 +            user = smb_llist_next(user_list, user)) {
     1077 +
 916 1078                  SMB_USER_VALID(user);
 917 1079                  ASSERT(user->u_session == session);
 918 1080  
 919      -                if (user->u_uid == uid && user->u_state == st) {
 920      -                        smb_user_hold_internal(user);
     1081 +                if (user->u_ssnid != ssnid && user->u_uid != uid)
     1082 +                        continue;
     1083 +
     1084 +                mutex_enter(&user->u_mutex);
     1085 +                if (user->u_state == st) {
     1086 +                        // smb_user_hold_internal(user);
     1087 +                        user->u_refcnt++;
     1088 +                        mutex_exit(&user->u_mutex);
 921 1089                          break;
 922 1090                  }
 923      -
 924      -                user = smb_llist_next(user_list, user);
     1091 +                mutex_exit(&user->u_mutex);
 925 1092          }
 926 1093  
 927 1094          smb_llist_exit(user_list);
 928 1095          return (user);
 929 1096  }
 930 1097  
 931      -void
 932      -smb_session_post_user(smb_session_t *session, smb_user_t *user)
 933      -{
 934      -        SMB_USER_VALID(user);
 935      -        ASSERT(user->u_refcnt == 0);
 936      -        ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
 937      -        ASSERT(user->u_session == session);
 938      -
 939      -        smb_llist_post(&session->s_user_list, user, smb_user_delete);
 940      -}
 941      -
 942 1098  /*
 943 1099   * Find a tree by tree-id.
 944 1100   */
 945 1101  smb_tree_t *
 946 1102  smb_session_lookup_tree(
 947 1103      smb_session_t       *session,
 948 1104      uint16_t            tid)
 949      -
 950 1105  {
 951 1106          smb_tree_t      *tree;
 952 1107  
 953 1108          SMB_SESSION_VALID(session);
 954 1109  
 955 1110          smb_llist_enter(&session->s_tree_list, RW_READER);
 956 1111          tree = smb_llist_head(&session->s_tree_list);
 957 1112  
 958 1113          while (tree) {
 959 1114                  ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
↓ open down ↓ 10 lines elided ↑ open up ↑
 970 1125                  }
 971 1126  
 972 1127                  tree = smb_llist_next(&session->s_tree_list, tree);
 973 1128          }
 974 1129  
 975 1130          smb_llist_exit(&session->s_tree_list);
 976 1131          return (NULL);
 977 1132  }
 978 1133  
 979 1134  /*
 980      - * Find the first connected tree that matches the specified sharename.
 981      - * If the specified tree is NULL the search starts from the beginning of
 982      - * the user's tree list.  If a tree is provided the search starts just
 983      - * after that tree.
 984      - */
 985      -smb_tree_t *
 986      -smb_session_lookup_share(
 987      -    smb_session_t       *session,
 988      -    const char          *sharename,
 989      -    smb_tree_t          *tree)
 990      -{
 991      -        SMB_SESSION_VALID(session);
 992      -        ASSERT(sharename);
 993      -
 994      -        smb_llist_enter(&session->s_tree_list, RW_READER);
 995      -
 996      -        if (tree) {
 997      -                ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
 998      -                ASSERT(tree->t_session == session);
 999      -                tree = smb_llist_next(&session->s_tree_list, tree);
1000      -        } else {
1001      -                tree = smb_llist_head(&session->s_tree_list);
1002      -        }
1003      -
1004      -        while (tree) {
1005      -                ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1006      -                ASSERT(tree->t_session == session);
1007      -                if (smb_strcasecmp(tree->t_sharename, sharename, 0) == 0) {
1008      -                        if (smb_tree_hold(tree)) {
1009      -                                smb_llist_exit(&session->s_tree_list);
1010      -                                return (tree);
1011      -                        }
1012      -                }
1013      -                tree = smb_llist_next(&session->s_tree_list, tree);
1014      -        }
1015      -
1016      -        smb_llist_exit(&session->s_tree_list);
1017      -        return (NULL);
1018      -}
1019      -
1020      -/*
1021      - * Find the first connected tree that matches the specified volume name.
1022      - * If the specified tree is NULL the search starts from the beginning of
1023      - * the user's tree list.  If a tree is provided the search starts just
1024      - * after that tree.
1025      - */
1026      -smb_tree_t *
1027      -smb_session_lookup_volume(
1028      -    smb_session_t       *session,
1029      -    const char          *name,
1030      -    smb_tree_t          *tree)
1031      -{
1032      -        SMB_SESSION_VALID(session);
1033      -        ASSERT(name);
1034      -
1035      -        smb_llist_enter(&session->s_tree_list, RW_READER);
1036      -
1037      -        if (tree) {
1038      -                ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1039      -                ASSERT(tree->t_session == session);
1040      -                tree = smb_llist_next(&session->s_tree_list, tree);
1041      -        } else {
1042      -                tree = smb_llist_head(&session->s_tree_list);
1043      -        }
1044      -
1045      -        while (tree) {
1046      -                ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1047      -                ASSERT(tree->t_session == session);
1048      -
1049      -                if (smb_strcasecmp(tree->t_volume, name, 0) == 0) {
1050      -                        if (smb_tree_hold(tree)) {
1051      -                                smb_llist_exit(&session->s_tree_list);
1052      -                                return (tree);
1053      -                        }
1054      -                }
1055      -
1056      -                tree = smb_llist_next(&session->s_tree_list, tree);
1057      -        }
1058      -
1059      -        smb_llist_exit(&session->s_tree_list);
1060      -        return (NULL);
1061      -}
1062      -
1063      -/*
1064 1135   * Disconnect all trees that match the specified client process-id.
     1136 + * Used by the SMB1 "process exit" request.
1065 1137   */
1066 1138  void
1067 1139  smb_session_close_pid(
1068 1140      smb_session_t       *session,
1069 1141      uint32_t            pid)
1070 1142  {
     1143 +        smb_llist_t     *tree_list = &session->s_tree_list;
1071 1144          smb_tree_t      *tree;
1072 1145  
1073      -        SMB_SESSION_VALID(session);
     1146 +        smb_llist_enter(tree_list, RW_READER);
1074 1147  
1075      -        tree = smb_session_get_tree(session, NULL);
     1148 +        tree = smb_llist_head(tree_list);
1076 1149          while (tree) {
1077      -                smb_tree_t *next;
1078      -                ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1079      -                ASSERT(tree->t_session == session);
1080      -                smb_tree_close_pid(tree, pid);
1081      -                next = smb_session_get_tree(session, tree);
1082      -                smb_tree_release(tree);
1083      -                tree = next;
     1150 +                if (smb_tree_hold(tree)) {
     1151 +                        smb_tree_close_pid(tree, pid);
     1152 +                        smb_tree_release(tree);
     1153 +                }
     1154 +                tree = smb_llist_next(tree_list, tree);
1084 1155          }
     1156 +
     1157 +        smb_llist_exit(tree_list);
1085 1158  }
1086 1159  
1087 1160  static void
1088      -smb_session_tree_dtor(void *t)
     1161 +smb_session_tree_dtor(void *arg)
1089 1162  {
1090      -        smb_tree_t      *tree = (smb_tree_t *)t;
     1163 +        smb_tree_t      *tree = arg;
1091 1164  
1092 1165          smb_tree_disconnect(tree, B_TRUE);
1093 1166          /* release the ref acquired during the traversal loop */
1094 1167          smb_tree_release(tree);
1095 1168  }
1096 1169  
1097 1170  
1098 1171  /*
1099 1172   * Disconnect all trees that this user has connected.
1100 1173   */
↓ open down ↓ 10 lines elided ↑ open up ↑
1111 1184  
1112 1185          smb_llist_enter(tree_list, RW_READER);
1113 1186  
1114 1187          tree = smb_llist_head(tree_list);
1115 1188          while (tree) {
1116 1189                  if ((tree->t_owner == owner) &&
1117 1190                      smb_tree_hold(tree)) {
1118 1191                          /*
1119 1192                           * smb_tree_hold() succeeded, hence we are in state
1120 1193                           * SMB_TREE_STATE_CONNECTED; schedule this tree
1121      -                         * for asynchronous disconnect, which will fire
1122      -                         * after we drop the llist traversal lock.
     1194 +                         * for disconnect after smb_llist_exit because
     1195 +                         * the "unmap exec" up-call can block, and we'd
     1196 +                         * rather not block with the tree list locked.
1123 1197                           */
1124 1198                          smb_llist_post(tree_list, tree, smb_session_tree_dtor);
1125 1199                  }
1126 1200                  tree = smb_llist_next(tree_list, tree);
1127 1201          }
1128 1202  
1129 1203          /* drop the lock and flush the dtor queue */
1130 1204          smb_llist_exit(tree_list);
1131 1205  }
1132 1206  
1133 1207  /*
1134 1208   * Disconnect all trees that this user has connected.
1135 1209   */
1136      -void
     1210 +static void
1137 1211  smb_session_disconnect_trees(
1138 1212      smb_session_t       *session)
1139 1213  {
     1214 +        smb_llist_t     *tree_list = &session->s_tree_list;
1140 1215          smb_tree_t      *tree;
1141 1216  
1142      -        SMB_SESSION_VALID(session);
     1217 +        smb_llist_enter(tree_list, RW_READER);
1143 1218  
1144      -        tree = smb_session_get_tree(session, NULL);
     1219 +        tree = smb_llist_head(tree_list);
1145 1220          while (tree) {
1146      -                ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1147      -                ASSERT(tree->t_session == session);
1148      -                smb_tree_disconnect(tree, B_TRUE);
1149      -                smb_tree_release(tree);
1150      -                tree = smb_session_get_tree(session, NULL);
     1221 +                if (smb_tree_hold(tree)) {
     1222 +                        smb_llist_post(tree_list, tree,
     1223 +                            smb_session_tree_dtor);
     1224 +                }
     1225 +                tree = smb_llist_next(tree_list, tree);
1151 1226          }
     1227 +
     1228 +        /* drop the lock and flush the dtor queue */
     1229 +        smb_llist_exit(tree_list);
1152 1230  }
1153 1231  
1154 1232  /*
1155      - * Disconnect all trees that match the specified share name.
     1233 + * Variant of smb_session_tree_dtor that also
     1234 + * cancels requests using this tree.
1156 1235   */
1157      -void
1158      -smb_session_disconnect_share(
1159      -    smb_session_t       *session,
1160      -    const char          *sharename)
     1236 +static void
     1237 +smb_session_tree_kill(void *arg)
1161 1238  {
1162      -        smb_tree_t      *tree;
1163      -        smb_tree_t      *next;
     1239 +        smb_tree_t      *tree = arg;
1164 1240  
1165      -        SMB_SESSION_VALID(session);
1166      -
1167      -        tree = smb_session_lookup_share(session, sharename, NULL);
1168      -        while (tree) {
1169      -                ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1170      -                ASSERT(tree->t_session == session);
1171      -                smb_session_cancel_requests(session, tree, NULL);
1172      -                smb_tree_disconnect(tree, B_TRUE);
1173      -                next = smb_session_lookup_share(session, sharename, tree);
1174      -                smb_tree_release(tree);
1175      -                tree = next;
1176      -        }
1177      -}
1178      -
1179      -void
1180      -smb_session_post_tree(smb_session_t *session, smb_tree_t *tree)
1181      -{
1182      -        SMB_SESSION_VALID(session);
1183 1241          SMB_TREE_VALID(tree);
1184      -        ASSERT0(tree->t_refcnt);
1185      -        ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
1186      -        ASSERT(tree->t_session == session);
1187 1242  
1188      -        smb_llist_post(&session->s_tree_list, tree, smb_tree_dealloc);
     1243 +        smb_tree_disconnect(tree, B_TRUE);
     1244 +        smb_session_cancel_requests(tree->t_session, tree, NULL);
     1245 +
     1246 +        /* release the ref acquired during the traversal loop */
     1247 +        smb_tree_release(tree);
1189 1248  }
1190 1249  
1191 1250  /*
1192      - * Get the next connected tree in the list.  A reference is taken on
1193      - * the tree, which can be released later with smb_tree_release().
1194      - *
1195      - * If the specified tree is NULL the search starts from the beginning of
1196      - * the tree list.  If a tree is provided the search starts just after
1197      - * that tree.
1198      - *
1199      - * Returns NULL if there are no connected trees in the list.
     1251 + * Disconnect all trees that match the specified share name,
     1252 + * and kill requests using those trees.
1200 1253   */
1201      -static smb_tree_t *
1202      -smb_session_get_tree(
     1254 +void
     1255 +smb_session_disconnect_share(
1203 1256      smb_session_t       *session,
1204      -    smb_tree_t          *tree)
     1257 +    const char          *sharename)
1205 1258  {
1206      -        smb_llist_t     *tree_list;
     1259 +        smb_llist_t     *ll;
     1260 +        smb_tree_t      *tree;
1207 1261  
1208 1262          SMB_SESSION_VALID(session);
1209      -        tree_list = &session->s_tree_list;
1210 1263  
1211      -        smb_llist_enter(tree_list, RW_READER);
     1264 +        ll = &session->s_tree_list;
     1265 +        smb_llist_enter(ll, RW_READER);
1212 1266  
1213      -        if (tree) {
1214      -                ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1215      -                tree = smb_llist_next(tree_list, tree);
1216      -        } else {
1217      -                tree = smb_llist_head(tree_list);
1218      -        }
     1267 +        for (tree = smb_llist_head(ll);
     1268 +            tree != NULL;
     1269 +            tree = smb_llist_next(ll, tree)) {
1219 1270  
1220      -        while (tree) {
1221      -                if (smb_tree_hold(tree))
1222      -                        break;
     1271 +                SMB_TREE_VALID(tree);
     1272 +                ASSERT(tree->t_session == session);
1223 1273  
1224      -                tree = smb_llist_next(tree_list, tree);
     1274 +                if (smb_strcasecmp(tree->t_sharename, sharename, 0) != 0)
     1275 +                        continue;
     1276 +
     1277 +                if (smb_tree_hold(tree)) {
     1278 +                        smb_llist_post(ll, tree,
     1279 +                            smb_session_tree_kill);
     1280 +                }
1225 1281          }
1226 1282  
1227      -        smb_llist_exit(tree_list);
1228      -        return (tree);
     1283 +        smb_llist_exit(ll);
1229 1284  }
1230 1285  
1231 1286  /*
1232 1287   * Logoff all users associated with the specified session.
     1288 + *
     1289 + * This is called for both server-initiated disconnect
     1290 + * (SMB_SESSION_STATE_TERMINATED) and client-initiated
     1291 + * disconnect (SMB_SESSION_STATE_DISCONNECTED).
     1292 + * If client-initiated, save durable handles.
1233 1293   */
1234      -static void
     1294 +void
1235 1295  smb_session_logoff(smb_session_t *session)
1236 1296  {
     1297 +        smb_llist_t     *ulist;
1237 1298          smb_user_t      *user;
1238 1299  
1239 1300          SMB_SESSION_VALID(session);
1240 1301  
1241      -        smb_session_disconnect_trees(session);
     1302 +top:
     1303 +        ulist = &session->s_user_list;
     1304 +        smb_llist_enter(ulist, RW_READER);
1242 1305  
1243      -        smb_llist_enter(&session->s_user_list, RW_READER);
1244      -
1245      -        user = smb_llist_head(&session->s_user_list);
     1306 +        user = smb_llist_head(ulist);
1246 1307          while (user) {
1247 1308                  SMB_USER_VALID(user);
1248 1309                  ASSERT(user->u_session == session);
1249 1310  
     1311 +                mutex_enter(&user->u_mutex);
1250 1312                  switch (user->u_state) {
1251 1313                  case SMB_USER_STATE_LOGGING_ON:
1252 1314                  case SMB_USER_STATE_LOGGED_ON:
1253      -                        smb_user_hold_internal(user);
     1315 +                        // smb_user_hold_internal(user);
     1316 +                        user->u_refcnt++;
     1317 +                        mutex_exit(&user->u_mutex);
1254 1318                          smb_user_logoff(user);
1255 1319                          smb_user_release(user);
1256 1320                          break;
1257 1321  
1258 1322                  case SMB_USER_STATE_LOGGED_OFF:
1259 1323                  case SMB_USER_STATE_LOGGING_OFF:
     1324 +                        mutex_exit(&user->u_mutex);
1260 1325                          break;
1261 1326  
1262 1327                  default:
     1328 +                        mutex_exit(&user->u_mutex);
1263 1329                          ASSERT(0);
1264 1330                          break;
1265 1331                  }
1266 1332  
1267      -                user = smb_llist_next(&session->s_user_list, user);
     1333 +                user = smb_llist_next(ulist, user);
1268 1334          }
1269 1335  
1270      -        smb_llist_exit(&session->s_user_list);
     1336 +        /* Needed below (Was the list empty?) */
     1337 +        user = smb_llist_head(ulist);
     1338 +
     1339 +        smb_llist_exit(ulist);
     1340 +
     1341 +        /*
     1342 +         * It's possible for user objects to remain due to references
     1343 +         * obtained via smb_server_lookup_ssnid(), when an SMB2
     1344 +         * session setup is destroying a previous session.
     1345 +         *
     1346 +         * Wait for user objects to clear out (last refs. go away,
     1347 +         * then smb_user_delete takes them out of the list).  When
     1348 +         * the last user object is removed, the session state is
     1349 +         * set to SHUTDOWN and s_lock is signaled.
     1350 +         *
     1351 +         * Not all places that call smb_user_release necessarily
     1352 +         * flush the delete queue, so after we wait for the list
     1353 +         * to empty out, go back to the top and recheck the list
     1354 +         * delete queue to make sure smb_user_delete happens.
     1355 +         */
     1356 +        if (user == NULL) {
     1357 +                /* User list is empty. */
     1358 +                smb_rwx_rwenter(&session->s_lock, RW_WRITER);
     1359 +                session->s_state = SMB_SESSION_STATE_SHUTDOWN;
     1360 +                smb_rwx_rwexit(&session->s_lock);
     1361 +        } else {
     1362 +                smb_rwx_rwenter(&session->s_lock, RW_READER);
     1363 +                if (session->s_state != SMB_SESSION_STATE_SHUTDOWN) {
     1364 +                        (void) smb_rwx_cvwait(&session->s_lock,
     1365 +                            MSEC_TO_TICK(200));
     1366 +                        smb_rwx_rwexit(&session->s_lock);
     1367 +                        goto top;
     1368 +                }
     1369 +                smb_rwx_rwexit(&session->s_lock);
     1370 +        }
     1371 +        ASSERT(session->s_state == SMB_SESSION_STATE_SHUTDOWN);
     1372 +
     1373 +        /*
     1374 +         * User list should be empty now.
     1375 +         */
     1376 +#ifdef  DEBUG
     1377 +        if (ulist->ll_count != 0) {
     1378 +                cmn_err(CE_WARN, "user list not empty?");
     1379 +                debug_enter("s_user_list");
     1380 +        }
     1381 +#endif
     1382 +
     1383 +        /*
     1384 +         * User logoff happens first so we'll set preserve_opens
     1385 +         * for client-initiated disconnect.  When that's done
     1386 +         * there should be no trees left, but check anyway.
     1387 +         */
     1388 +        smb_session_disconnect_trees(session);
1271 1389  }
1272 1390  
1273 1391  /*
1274 1392   * Copy the session workstation/client name to buf.  If the workstation
1275 1393   * is an empty string (which it will be on TCP connections), use the
1276 1394   * client IP address.
1277 1395   */
1278 1396  void
1279 1397  smb_session_getclient(smb_session_t *sn, char *buf, size_t buflen)
1280 1398  {
↓ open down ↓ 32 lines elided ↑ open up ↑
1313 1431  
1314 1432          return (B_FALSE);
1315 1433  }
1316 1434  
1317 1435  /*
1318 1436   * smb_request_alloc
1319 1437   *
1320 1438   * Allocate an smb_request_t structure from the kmem_cache.  Partially
1321 1439   * initialize the found/new request.
1322 1440   *
1323      - * Returns pointer to a request
     1441 + * Returns pointer to a request, or NULL if the session state is
     1442 + * one in which new requests are no longer allowed.
1324 1443   */
1325 1444  smb_request_t *
1326 1445  smb_request_alloc(smb_session_t *session, int req_length)
1327 1446  {
1328 1447          smb_request_t   *sr;
1329 1448  
1330 1449          ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1331 1450          ASSERT(req_length <= session->cmd_max_bytes);
1332 1451  
1333 1452          sr = kmem_cache_alloc(smb_cache_request, KM_SLEEP);
1334 1453  
1335 1454          /*
1336 1455           * Future:  Use constructor to pre-initialize some fields.  For now
1337 1456           * there are so many fields that it is easiest just to zero the
1338 1457           * whole thing and start over.
1339 1458           */
1340 1459          bzero(sr, sizeof (smb_request_t));
1341 1460  
1342 1461          mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL);
1343      -        cv_init(&sr->sr_ncr.nc_cv, NULL, CV_DEFAULT, NULL);
1344 1462          smb_srm_init(sr);
1345 1463          sr->session = session;
1346 1464          sr->sr_server = session->s_server;
1347 1465          sr->sr_gmtoff = session->s_server->si_gmtoff;
1348 1466          sr->sr_cfg = &session->s_cfg;
1349 1467          sr->command.max_bytes = req_length;
1350 1468          sr->reply.max_bytes = session->reply_max_bytes;
1351 1469          sr->sr_req_length = req_length;
1352 1470          if (req_length)
1353 1471                  sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP);
1354 1472          sr->sr_magic = SMB_REQ_MAGIC;
1355 1473          sr->sr_state = SMB_REQ_STATE_INITIALIZING;
1356      -        smb_slist_insert_tail(&session->s_req_list, sr);
     1474 +
     1475 +        /*
     1476 +         * Only allow new SMB requests in some states.
     1477 +         */
     1478 +        smb_rwx_rwenter(&session->s_lock, RW_WRITER);
     1479 +        switch (session->s_state) {
     1480 +        case SMB_SESSION_STATE_CONNECTED:
     1481 +        case SMB_SESSION_STATE_INITIALIZED:
     1482 +        case SMB_SESSION_STATE_ESTABLISHED:
     1483 +        case SMB_SESSION_STATE_NEGOTIATED:
     1484 +                smb_slist_insert_tail(&session->s_req_list, sr);
     1485 +                break;
     1486 +
     1487 +        default:
     1488 +                ASSERT(0);
     1489 +                /* FALLTHROUGH */
     1490 +        case SMB_SESSION_STATE_DISCONNECTED:
     1491 +        case SMB_SESSION_STATE_SHUTDOWN:
     1492 +        case SMB_SESSION_STATE_TERMINATED:
     1493 +                /* Disallow new requests in these states. */
     1494 +                if (sr->sr_request_buf)
     1495 +                        kmem_free(sr->sr_request_buf, sr->sr_req_length);
     1496 +                sr->session = NULL;
     1497 +                sr->sr_magic = 0;
     1498 +                mutex_destroy(&sr->sr_mutex);
     1499 +                kmem_cache_free(smb_cache_request, sr);
     1500 +                sr = NULL;
     1501 +                break;
     1502 +        }
     1503 +        smb_rwx_rwexit(&session->s_lock);
     1504 +
1357 1505          return (sr);
1358 1506  }
1359 1507  
1360 1508  /*
1361 1509   * smb_request_free
1362 1510   *
1363 1511   * release the memories which have been allocated for a smb request.
1364 1512   */
1365 1513  void
1366 1514  smb_request_free(smb_request_t *sr)
1367 1515  {
1368 1516          ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1369 1517          ASSERT(sr->session);
1370 1518          ASSERT(sr->r_xa == NULL);
1371      -        ASSERT(sr->sr_ncr.nc_fname == NULL);
1372 1519  
1373 1520          if (sr->fid_ofile != NULL) {
1374      -                smb_ofile_request_complete(sr->fid_ofile);
1375 1521                  smb_ofile_release(sr->fid_ofile);
1376 1522          }
1377 1523  
1378 1524          if (sr->tid_tree != NULL)
1379 1525                  smb_tree_release(sr->tid_tree);
1380 1526  
1381 1527          if (sr->uid_user != NULL)
1382 1528                  smb_user_release(sr->uid_user);
1383 1529  
     1530 +        if (sr->tform_ssn != NULL)
     1531 +                smb_user_release(sr->tform_ssn);
     1532 +
     1533 +        /*
     1534 +         * The above may have left work on the delete queues
     1535 +         */
     1536 +        smb_llist_flush(&sr->session->s_tree_list);
     1537 +        smb_llist_flush(&sr->session->s_user_list);
     1538 +
1384 1539          smb_slist_remove(&sr->session->s_req_list, sr);
1385 1540  
1386 1541          sr->session = NULL;
1387 1542  
1388 1543          smb_srm_fini(sr);
1389 1544  
1390 1545          if (sr->sr_request_buf)
1391 1546                  kmem_free(sr->sr_request_buf, sr->sr_req_length);
1392 1547          if (sr->command.chain)
1393 1548                  m_freem(sr->command.chain);
1394 1549          if (sr->reply.chain)
1395 1550                  m_freem(sr->reply.chain);
1396 1551          if (sr->raw_data.chain)
1397 1552                  m_freem(sr->raw_data.chain);
1398 1553  
1399 1554          sr->sr_magic = 0;
1400      -        cv_destroy(&sr->sr_ncr.nc_cv);
1401 1555          mutex_destroy(&sr->sr_mutex);
1402 1556          kmem_cache_free(smb_cache_request, sr);
1403 1557  }
1404 1558  
1405 1559  boolean_t
1406 1560  smb_session_oplocks_enable(smb_session_t *session)
1407 1561  {
1408 1562          SMB_SESSION_VALID(session);
1409 1563          if (session->s_cfg.skc_oplock_enable == 0)
1410 1564                  return (B_FALSE);
1411 1565          else
1412 1566                  return (B_TRUE);
1413 1567  }
1414 1568  
1415 1569  boolean_t
1416 1570  smb_session_levelII_oplocks(smb_session_t *session)
1417 1571  {
1418 1572          SMB_SESSION_VALID(session);
1419 1573  
1420      -        /* Clients using SMB2 and later always know about oplocks. */
1421      -        if (session->dialect > NT_LM_0_12)
1422      -                return (B_TRUE);
1423      -
1424 1574          /* Older clients only do Level II oplocks if negotiated. */
1425 1575          if ((session->capabilities & CAP_LEVEL_II_OPLOCKS) != 0)
1426 1576                  return (B_TRUE);
1427 1577  
1428 1578          return (B_FALSE);
1429 1579  }
1430 1580  
1431      -/*
1432      - * smb_session_oplock_break
1433      - *
1434      - * Send an oplock break request to the client,
1435      - * recalling some cache delegation.
1436      - */
1437      -void
1438      -smb_session_oplock_break(smb_request_t *sr, uint8_t brk)
1439      -{
1440      -        smb_session_t   *session = sr->session;
1441      -        mbuf_chain_t    *mbc = &sr->reply;
1442      -
1443      -        SMB_SESSION_VALID(session);
1444      -
1445      -        /*
1446      -         * Build the break message in sr->reply and then send it.
1447      -         * The mbc is free'd later, in smb_request_free().
1448      -         */
1449      -        mbc->max_bytes = MLEN;
1450      -        if (session->dialect <= NT_LM_0_12) {
1451      -                smb1_oplock_break_notification(sr, brk);
1452      -        } else {
1453      -                smb2_oplock_break_notification(sr, brk);
1454      -        }
1455      -
1456      -        (void) smb_session_send(session, 0, mbc);
1457      -}
1458      -
1459 1581  static void
1460 1582  smb_session_genkey(smb_session_t *session)
1461 1583  {
1462 1584          uint8_t         tmp_key[SMB_CHALLENGE_SZ];
1463 1585  
1464 1586          (void) random_get_pseudo_bytes(tmp_key, SMB_CHALLENGE_SZ);
1465 1587          bcopy(tmp_key, &session->challenge_key, SMB_CHALLENGE_SZ);
1466 1588          session->challenge_len = SMB_CHALLENGE_SZ;
1467 1589  
1468 1590          (void) random_get_pseudo_bytes(tmp_key, 4);
1469 1591          session->sesskey = tmp_key[0] | tmp_key[1] << 8 |
1470 1592              tmp_key[2] << 16 | tmp_key[3] << 24;
1471 1593  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX