Print this page
NEX-17669 SMB shares missing after CA share import
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@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-17095 illumos 8935 SMB ioctl fixes incomplete
8935 SMB ioctl fixes incomplete
Reviewed by: Alex Wilson <alex.wilson@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Rui Loura <rui.loura@joyent.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Dominik Hassler <hasslerd@gmx.li>
Approved by: Garrett D'Amore <garrett@damore.org>
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-10019 SMB server min_protocol setting
Reviewed by: Gordon Ross <gordon.ross@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-6096 Enable compile warnings re. parentheses in smbsrv
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@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-4541 SMB server listener stops after a SYN-ACK flood (fksmbd noise)
NEX-4541 SMB server listener stops after a SYN-ACK flood (lint fix)
NEX-5983 remove post-merge cruft in usr/src/uts/intel/io/vmxnet3s
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-4541 SMB server listener stops after a SYN-ACK flood
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-3553 SMB2/3 durable handles
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-3776 SMB should handle PreviousSessionID
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-4811 SMB needs to export a header for kstats
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Jeffry Molanus <jeffry.molanus@nexenta.com>
NEX-2522 svcadm disable network/smb/server may hang
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4083 Upstream changes from illumos 5917 and 5995
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-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-3620 need upstream cleanups for smbsrv
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
NEX-3611 CLONE NEX-3550 Replace smb2_enable with max_protocol
Reviewed by: Yuri Pankov <Yuri.Pankov@nexenta.com>
NEX-2485 SMB authentication flood handled poorly
SUP-866 smbd lwps stuck in libsocket recv() for no apparent reason
NEX-1050 enable_smb2 should be smb2_enable
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-39 Use AF_UNIX pipes for RPC (fix a leak)
SMB-75 smb_session_timers way too frequent
SMB-74 Process oplock breaks as session requests
SMB-69 read-raw, write-raw are dead code
SMB-50 User-mode SMB server (oops)
SMB-56 extended security NTLMSSP, inbound
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())
SUP-694 panic on bad mutex in smb_event_wait()
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-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
SMB-64 smbsrv workers run at excessively high priority
SMB-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
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 #9812 rb3153 System panic'd with assertion failed: sl->sl_count == 0 in smb_slist_destructor after hostname change, smbd restart and attempts to rejoin active directory domain
re #6813 rb1757 port 2976 Child folder visibility through shares
re #6812 rb1753 backport illumos 1604 smbd print_enable doesn't really work
re #6811 rb1752 backport illumos 1603 smbsrv raw mode is ill-advised

*** 18,29 **** * * CDDL HEADER END */ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2017 by Delphix. All rights reserved. */ /* * General Structures Layout * ------------------------- --- 18,29 ---- * * CDDL HEADER END */ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017 by Delphix. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* * General Structures Layout * -------------------------
*** 217,233 **** #include <smbsrv/smb_fsops.h> #include <smbsrv/smb_share.h> #include <smbsrv/smb_door.h> #include <smbsrv/smb_kstat.h> - extern void smb_reply_notify_change_request(smb_request_t *); - - typedef struct { - smb_listener_daemon_t *ra_listener; - smb_session_t *ra_session; - } smb_receiver_arg_t; - static void smb_server_kstat_init(smb_server_t *); static void smb_server_kstat_fini(smb_server_t *); static void smb_server_timers(smb_thread_t *, void *); static void smb_server_store_cfg(smb_server_t *, smb_ioc_cfg_t *); static void smb_server_shutdown(smb_server_t *); --- 217,226 ----
*** 234,249 **** static int smb_server_fsop_start(smb_server_t *); static void smb_server_fsop_stop(smb_server_t *); static void smb_event_cancel(smb_server_t *, uint32_t); static uint32_t smb_event_alloc_txid(void); ! static void smb_server_disconnect_share(smb_llist_t *, const char *); ! static void smb_server_enum_users(smb_llist_t *, smb_svcenum_t *); ! static void smb_server_enum_trees(smb_llist_t *, smb_svcenum_t *); ! static int smb_server_session_disconnect(smb_llist_t *, const char *, const char *); ! static int smb_server_fclose(smb_llist_t *, uint32_t); static int smb_server_kstat_update(kstat_t *, int); static int smb_server_legacy_kstat_update(kstat_t *, int); static void smb_server_listener_init(smb_server_t *, smb_listener_daemon_t *, char *, in_port_t, int); static void smb_server_listener_destroy(smb_listener_daemon_t *); --- 227,242 ---- static int smb_server_fsop_start(smb_server_t *); static void smb_server_fsop_stop(smb_server_t *); static void smb_event_cancel(smb_server_t *, uint32_t); static uint32_t smb_event_alloc_txid(void); ! static void smb_server_disconnect_share(smb_server_t *, const char *); ! static void smb_server_enum_users(smb_server_t *, smb_svcenum_t *); ! static void smb_server_enum_trees(smb_server_t *, smb_svcenum_t *); ! static int smb_server_session_disconnect(smb_server_t *, const char *, const char *); ! static int smb_server_fclose(smb_server_t *, uint32_t); static int smb_server_kstat_update(kstat_t *, int); static int smb_server_legacy_kstat_update(kstat_t *, int); static void smb_server_listener_init(smb_server_t *, smb_listener_daemon_t *, char *, in_port_t, int); static void smb_server_listener_destroy(smb_listener_daemon_t *);
*** 250,265 **** static int smb_server_listener_start(smb_listener_daemon_t *); static void smb_server_listener_stop(smb_listener_daemon_t *); static void smb_server_listener(smb_thread_t *, void *); static void smb_server_receiver(void *); static void smb_server_create_session(smb_listener_daemon_t *, ksocket_t); ! static void smb_server_destroy_session(smb_listener_daemon_t *, ! smb_session_t *); static uint16_t smb_spool_get_fid(smb_server_t *); static boolean_t smb_spool_lookup_doc_byfid(smb_server_t *, uint16_t, smb_kspooldoc_t *); int smb_event_debug = 0; static smb_llist_t smb_servers; kmem_cache_t *smb_cache_request; --- 243,271 ---- static int smb_server_listener_start(smb_listener_daemon_t *); static void smb_server_listener_stop(smb_listener_daemon_t *); static void smb_server_listener(smb_thread_t *, void *); static void smb_server_receiver(void *); static void smb_server_create_session(smb_listener_daemon_t *, ksocket_t); ! static void smb_server_destroy_session(smb_session_t *); static uint16_t smb_spool_get_fid(smb_server_t *); static boolean_t smb_spool_lookup_doc_byfid(smb_server_t *, uint16_t, smb_kspooldoc_t *); + /* + * How many "buckets" should our hash tables use? On a "real" server, + * make them much larger than the number of CPUs we're likely to have. + * On "fksmbd" make it smaller so dtrace logs are shorter. + * These must be powers of two. + */ + #ifdef _KERNEL + #define DEFAULT_HASH_NBUCKETS 256 /* real server */ + #else + #define DEFAULT_HASH_NBUCKETS 16 /* for "fksmbd" */ + #endif + uint32_t SMB_OFILE_HASH_NBUCKETS = DEFAULT_HASH_NBUCKETS; + uint32_t SMB_LEASE_HASH_NBUCKETS = DEFAULT_HASH_NBUCKETS; + int smb_event_debug = 0; static smb_llist_t smb_servers; kmem_cache_t *smb_cache_request;
*** 268,277 **** --- 274,284 ---- kmem_cache_t *smb_cache_tree; kmem_cache_t *smb_cache_ofile; kmem_cache_t *smb_cache_odir; kmem_cache_t *smb_cache_opipe; kmem_cache_t *smb_cache_event; + kmem_cache_t *smb_cache_lock; /* * ***************************************************************************** * **************** Functions called from the device interface ***************** * *****************************************************************************
*** 306,315 **** --- 313,323 ---- smb_kshare_g_init(); smb_codepage_init(); smb_mbc_init(); /* smb_mbc_cache */ smb_node_init(); /* smb_node_cache, lists */ + smb2_lease_init(); smb_cache_request = kmem_cache_create("smb_request_cache", sizeof (smb_request_t), 8, NULL, NULL, NULL, NULL, NULL, 0); smb_cache_session = kmem_cache_create("smb_session_cache", sizeof (smb_session_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
*** 323,332 **** --- 331,342 ---- sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0); smb_cache_opipe = kmem_cache_create("smb_opipe_cache", sizeof (smb_opipe_t), 8, NULL, NULL, NULL, NULL, NULL, 0); smb_cache_event = kmem_cache_create("smb_event_cache", sizeof (smb_event_t), 8, NULL, NULL, NULL, NULL, NULL, 0); + smb_cache_lock = kmem_cache_create("smb_lock_cache", + sizeof (smb_lock_t), 8, NULL, NULL, NULL, NULL, NULL, 0); smb_llist_init(); smb_llist_constructor(&smb_servers, sizeof (smb_server_t), offsetof(smb_server_t, sv_lnd));
*** 358,368 **** --- 368,380 ---- kmem_cache_destroy(smb_cache_tree); kmem_cache_destroy(smb_cache_ofile); kmem_cache_destroy(smb_cache_odir); kmem_cache_destroy(smb_cache_opipe); kmem_cache_destroy(smb_cache_event); + kmem_cache_destroy(smb_cache_lock); + smb2_lease_fini(); smb_node_fini(); smb_mbc_fini(); smb_codepage_fini(); smb_kshare_g_fini();
*** 406,415 **** --- 418,436 ---- mutex_init(&sv->sv_mutex, NULL, MUTEX_DEFAULT, NULL); cv_init(&sv->sv_cv, NULL, CV_DEFAULT, NULL); cv_init(&sv->sp_info.sp_cv, NULL, CV_DEFAULT, NULL); + sv->sv_persistid_ht = smb_hash_create(sizeof (smb_ofile_t), + offsetof(smb_ofile_t, f_dh_lnd), SMB_OFILE_HASH_NBUCKETS); + + sv->sv_lease_ht = smb_hash_create(sizeof (smb_lease_t), + offsetof(smb_lease_t, ls_lnd), SMB_LEASE_HASH_NBUCKETS); + + smb_llist_constructor(&sv->sv_session_list, sizeof (smb_session_t), + offsetof(smb_session_t, s_lnd)); + smb_llist_constructor(&sv->sv_event_list, sizeof (smb_event_t), offsetof(smb_event_t, se_lnd)); smb_llist_constructor(&sv->sp_info.sp_list, sizeof (smb_kspooldoc_t), offsetof(smb_kspooldoc_t, sd_lnd));
*** 450,468 **** * * This function will delete the server passed in. It will make sure that all * activity associated that server has ceased before destroying it. */ int ! smb_server_delete(void) { - smb_server_t *sv; - int rc; - rc = smb_server_lookup(&sv); - if (rc != 0) - return (rc); - mutex_enter(&sv->sv_mutex); switch (sv->sv_state) { case SMB_SERVER_STATE_RUNNING: sv->sv_state = SMB_SERVER_STATE_STOPPING; mutex_exit(&sv->sv_mutex); --- 471,483 ---- * * This function will delete the server passed in. It will make sure that all * activity associated that server has ceased before destroying it. */ int ! smb_server_delete(smb_server_t *sv) { mutex_enter(&sv->sv_mutex); switch (sv->sv_state) { case SMB_SERVER_STATE_RUNNING: sv->sv_state = SMB_SERVER_STATE_STOPPING; mutex_exit(&sv->sv_mutex);
*** 506,515 **** --- 521,531 ---- rw_destroy(&sv->sv_cfg_lock); smb_server_kstat_fini(sv); smb_kshare_fini(sv); smb_kdoor_fini(sv); smb_llist_destructor(&sv->sv_event_list); + smb_llist_destructor(&sv->sv_session_list); kmem_free(sv->sv_disp_stats1, SMB_COM_NUM * sizeof (smb_disp_stats_t)); kmem_free(sv->sv_disp_stats2,
*** 517,526 **** --- 533,544 ---- smb_srqueue_destroy(&sv->sv_srqueue); smb_thread_destroy(&sv->si_thread_timers); mutex_destroy(&sv->sv_mutex); + smb_hash_destroy(sv->sv_lease_ht); + smb_hash_destroy(sv->sv_persistid_ht); cv_destroy(&sv->sv_cv); sv->sv_magic = 0; kmem_free(sv, sizeof (smb_server_t)); return (0);
*** 582,591 **** --- 600,610 ---- smb_server_start(smb_ioc_start_t *ioc) { int rc = 0; int family; smb_server_t *sv; + cred_t *ucr; rc = smb_server_lookup(&sv); if (rc) return (rc);
*** 594,603 **** --- 613,647 ---- case SMB_SERVER_STATE_CONFIGURED: if ((rc = smb_server_fsop_start(sv)) != 0) break; + /* + * Note: smb_kshare_start needs sv_session. + */ + sv->sv_session = smb_session_create(NULL, 0, sv, 0); + if (sv->sv_session == NULL) { + rc = ENOMEM; + break; + } + + /* + * Create a logon on the server session, + * used when importing CA shares. + */ + sv->sv_rootuser = smb_user_new(sv->sv_session); + ucr = smb_kcred_create(); + rc = smb_user_logon(sv->sv_rootuser, ucr, "", "root", + SMB_USER_FLAG_ADMIN, 0, 0); + crfree(ucr); + ucr = NULL; + if (rc != 0) { + cmn_err(CE_NOTE, "smb_server_start: " + "failed to create root user"); + break; + } + if ((rc = smb_kshare_start(sv)) != 0) break; /* * NB: the proc passed here has to be a "system" one.
*** 611,642 **** sv->sv_receiver_pool = taskq_create_proc("smb_receivers", sv->sv_cfg.skc_maxconnections, smbsrv_receive_pri, sv->sv_cfg.skc_maxconnections, INT_MAX, curzone->zone_zsched, TASKQ_DYNAMIC); ! sv->sv_session = smb_session_create(NULL, 0, sv, 0); ! ! if (sv->sv_worker_pool == NULL || sv->sv_session == NULL) { rc = ENOMEM; break; } #ifdef _KERNEL ASSERT(sv->sv_lmshrd == NULL); sv->sv_lmshrd = smb_kshare_door_init(ioc->lmshrd); if (sv->sv_lmshrd == NULL) break; ! if (rc = smb_kdoor_open(sv, ioc->udoor)) { cmn_err(CE_WARN, "Cannot open smbd door"); break; } #else /* _KERNEL */ /* Fake kernel does not use the kshare_door */ fksmb_kdoor_open(sv, ioc->udoor_func); #endif /* _KERNEL */ ! if (rc = smb_thread_start(&sv->si_thread_timers)) break; family = AF_INET; smb_server_listener_init(sv, &sv->sv_nbt_daemon, "smb_nbt_listener", IPPORT_NETBIOS_SSN, family); --- 655,685 ---- sv->sv_receiver_pool = taskq_create_proc("smb_receivers", sv->sv_cfg.skc_maxconnections, smbsrv_receive_pri, sv->sv_cfg.skc_maxconnections, INT_MAX, curzone->zone_zsched, TASKQ_DYNAMIC); ! if (sv->sv_worker_pool == NULL || ! sv->sv_receiver_pool == NULL) { rc = ENOMEM; break; } #ifdef _KERNEL ASSERT(sv->sv_lmshrd == NULL); sv->sv_lmshrd = smb_kshare_door_init(ioc->lmshrd); if (sv->sv_lmshrd == NULL) break; ! if ((rc = smb_kdoor_open(sv, ioc->udoor)) != 0) { cmn_err(CE_WARN, "Cannot open smbd door"); break; } #else /* _KERNEL */ /* Fake kernel does not use the kshare_door */ fksmb_kdoor_open(sv, ioc->udoor_func); #endif /* _KERNEL */ ! if ((rc = smb_thread_start(&sv->si_thread_timers)) != 0) break; family = AF_INET; smb_server_listener_init(sv, &sv->sv_nbt_daemon, "smb_nbt_listener", IPPORT_NETBIOS_SSN, family);
*** 862,882 **** svcenum->se_bused = 0; svcenum->se_nitems = 0; switch (svcenum->se_type) { case SMB_SVCENUM_TYPE_USER: ! smb_server_enum_users(&sv->sv_nbt_daemon.ld_session_list, ! svcenum); ! smb_server_enum_users(&sv->sv_tcp_daemon.ld_session_list, ! svcenum); break; case SMB_SVCENUM_TYPE_TREE: case SMB_SVCENUM_TYPE_FILE: ! smb_server_enum_trees(&sv->sv_nbt_daemon.ld_session_list, ! svcenum); ! smb_server_enum_trees(&sv->sv_tcp_daemon.ld_session_list, ! svcenum); break; default: rc = EINVAL; } --- 905,919 ---- svcenum->se_bused = 0; svcenum->se_nitems = 0; switch (svcenum->se_type) { case SMB_SVCENUM_TYPE_USER: ! smb_server_enum_users(sv, svcenum); break; case SMB_SVCENUM_TYPE_TREE: case SMB_SVCENUM_TYPE_FILE: ! smb_server_enum_trees(sv, svcenum); break; default: rc = EINVAL; }
*** 888,915 **** * Look for sessions to disconnect by client and user name. */ int smb_server_session_close(smb_ioc_session_t *ioc) { - smb_llist_t *ll; smb_server_t *sv; ! int nbt_cnt; ! int tcp_cnt; int rc; if ((rc = smb_server_lookup(&sv)) != 0) return (rc); ! ll = &sv->sv_nbt_daemon.ld_session_list; ! nbt_cnt = smb_server_session_disconnect(ll, ioc->client, ioc->username); - ll = &sv->sv_tcp_daemon.ld_session_list; - tcp_cnt = smb_server_session_disconnect(ll, ioc->client, ioc->username); - smb_server_release(sv); ! if ((nbt_cnt == 0) && (tcp_cnt == 0)) return (ENOENT); return (0); } /* --- 925,946 ---- * Look for sessions to disconnect by client and user name. */ int smb_server_session_close(smb_ioc_session_t *ioc) { smb_server_t *sv; ! int cnt; int rc; if ((rc = smb_server_lookup(&sv)) != 0) return (rc); ! cnt = smb_server_session_disconnect(sv, ioc->client, ioc->username); smb_server_release(sv); ! if (cnt == 0) return (ENOENT); return (0); } /*
*** 917,941 **** */ int smb_server_file_close(smb_ioc_fileid_t *ioc) { uint32_t uniqid = ioc->uniqid; - smb_llist_t *ll; smb_server_t *sv; int rc; if ((rc = smb_server_lookup(&sv)) != 0) return (rc); ! ll = &sv->sv_nbt_daemon.ld_session_list; ! rc = smb_server_fclose(ll, uniqid); - if (rc == ENOENT) { - ll = &sv->sv_tcp_daemon.ld_session_list; - rc = smb_server_fclose(ll, uniqid); - } - smb_server_release(sv); return (rc); } /* --- 948,965 ---- */ int smb_server_file_close(smb_ioc_fileid_t *ioc) { uint32_t uniqid = ioc->uniqid; smb_server_t *sv; int rc; if ((rc = smb_server_lookup(&sv)) != 0) return (rc); ! rc = smb_server_fclose(sv, uniqid); smb_server_release(sv); return (rc); } /*
*** 945,972 **** uint32_t smb_server_get_session_count(smb_server_t *sv) { uint32_t counter = 0; ! counter = smb_llist_get_count(&sv->sv_nbt_daemon.ld_session_list); ! counter += smb_llist_get_count(&sv->sv_tcp_daemon.ld_session_list); return (counter); } /* ! * Gets the vnode of the specified share path. ! * ! * A hold on the returned vnode pointer is taken so the caller ! * must call VN_RELE. */ int ! smb_server_sharevp(smb_server_t *sv, const char *shr_path, vnode_t **vp) { smb_request_t *sr; smb_node_t *fnode = NULL; ! smb_node_t *dnode; char last_comp[MAXNAMELEN]; int rc = 0; ASSERT(shr_path); --- 969,994 ---- uint32_t smb_server_get_session_count(smb_server_t *sv) { uint32_t counter = 0; ! counter = smb_llist_get_count(&sv->sv_session_list); return (counter); } /* ! * Gets the smb_node of the specified share path. ! * Node is returned held (caller must rele.) */ int ! smb_server_share_lookup(smb_server_t *sv, const char *shr_path, ! smb_node_t **nodepp) { smb_request_t *sr; smb_node_t *fnode = NULL; ! smb_node_t *dnode = NULL; char last_comp[MAXNAMELEN]; int rc = 0; ASSERT(shr_path);
*** 979,989 **** return (ENOTACTIVE); } mutex_exit(&sv->sv_mutex); if ((sr = smb_request_alloc(sv->sv_session, 0)) == NULL) { ! return (ENOMEM); } sr->user_cr = zone_kcred(); rc = smb_pathname_reduce(sr, sr->user_cr, shr_path, NULL, NULL, &dnode, last_comp); --- 1001,1011 ---- return (ENOTACTIVE); } mutex_exit(&sv->sv_mutex); if ((sr = smb_request_alloc(sv->sv_session, 0)) == NULL) { ! return (ENOTCONN); } sr->user_cr = zone_kcred(); rc = smb_pathname_reduce(sr, sr->user_cr, shr_path, NULL, NULL, &dnode, last_comp);
*** 999,1013 **** if (rc != 0) return (rc); ASSERT(fnode->vp && fnode->vp->v_vfsp); ! VN_HOLD(fnode->vp); ! *vp = fnode->vp; - smb_node_release(fnode); - return (0); } #ifdef _KERNEL /* --- 1021,1032 ---- if (rc != 0) return (rc); ASSERT(fnode->vp && fnode->vp->v_vfsp); ! *nodepp = fnode; return (0); } #ifdef _KERNEL /*
*** 1044,1054 **** int smb_server_unshare(const char *sharename) { smb_server_t *sv; - smb_llist_t *ll; int rc; if ((rc = smb_server_lookup(&sv))) return (rc); --- 1063,1072 ----
*** 1062,1104 **** smb_server_release(sv); return (ENOTACTIVE); } mutex_exit(&sv->sv_mutex); ! ll = &sv->sv_nbt_daemon.ld_session_list; ! smb_server_disconnect_share(ll, sharename); - ll = &sv->sv_tcp_daemon.ld_session_list; - smb_server_disconnect_share(ll, sharename); - smb_server_release(sv); return (0); } /* * Disconnect the specified share. * Typically called when a share has been removed. */ static void ! smb_server_disconnect_share(smb_llist_t *ll, const char *sharename) { smb_session_t *session; smb_llist_enter(ll, RW_READER); session = smb_llist_head(ll); while (session) { SMB_SESSION_VALID(session); smb_rwx_rwenter(&session->s_lock, RW_READER); switch (session->s_state) { case SMB_SESSION_STATE_NEGOTIATED: smb_session_disconnect_share(session, sharename); break; default: break; } - smb_rwx_rwexit(&session->s_lock); session = smb_llist_next(ll, session); } smb_llist_exit(ll); } --- 1080,1121 ---- smb_server_release(sv); return (ENOTACTIVE); } mutex_exit(&sv->sv_mutex); ! smb_server_disconnect_share(sv, sharename); smb_server_release(sv); return (0); } /* * Disconnect the specified share. * Typically called when a share has been removed. */ static void ! smb_server_disconnect_share(smb_server_t *sv, const char *sharename) { + smb_llist_t *ll; smb_session_t *session; + ll = &sv->sv_session_list; smb_llist_enter(ll, RW_READER); session = smb_llist_head(ll); while (session) { SMB_SESSION_VALID(session); smb_rwx_rwenter(&session->s_lock, RW_READER); switch (session->s_state) { case SMB_SESSION_STATE_NEGOTIATED: + smb_rwx_rwexit(&session->s_lock); smb_session_disconnect_share(session, sharename); break; default: + smb_rwx_rwexit(&session->s_lock); break; } session = smb_llist_next(ll, session); } smb_llist_exit(ll); }
*** 1239,1254 **** smb_server_t *sv = (smb_server_t *)arg; ASSERT(sv != NULL); /* ! * This just kills old inactive sessions. No urgency. ! * The session code expects one call per minute. */ while (smb_thread_continue_timedwait(thread, 60 /* Seconds */)) { ! smb_session_timers(&sv->sv_nbt_daemon.ld_session_list); ! smb_session_timers(&sv->sv_tcp_daemon.ld_session_list); } } /* * smb_server_kstat_init --- 1256,1272 ---- smb_server_t *sv = (smb_server_t *)arg; ASSERT(sv != NULL); /* ! * This kills old inactive sessions and expired durable ! * handles. The session code expects one call per minute. */ while (smb_thread_continue_timedwait(thread, 60 /* Seconds */)) { ! if (sv->sv_cfg.skc_keepalive != 0) ! smb_session_timers(sv); ! smb2_durable_timers(sv); } } /* * smb_server_kstat_init
*** 1321,1330 **** --- 1339,1354 ---- smb2_dispatch_stats_fini(sv); } } /* + * Verify the defines in smb_kstat.h used by ks_reqs1 ks_reqs2 + */ + CTASSERT(SMBSRV_KS_NREQS1 == SMB_COM_NUM); + CTASSERT(SMBSRV_KS_NREQS2 == SMB2__NCMDS); + + /* * smb_server_kstat_update */ static int smb_server_kstat_update(kstat_t *ksp, int rw) {
*** 1405,1414 **** --- 1429,1442 ---- * smb_server_shutdown */ static void smb_server_shutdown(smb_server_t *sv) { + smb_llist_t *sl = &sv->sv_session_list; + smb_session_t *session; + clock_t time; + SMB_SERVER_VALID(sv); /* * Stop the listeners first, so we don't get any more * new work while we're trying to shut down.
*** 1415,1424 **** --- 1443,1461 ---- */ smb_server_listener_stop(&sv->sv_nbt_daemon); smb_server_listener_stop(&sv->sv_tcp_daemon); smb_thread_stop(&sv->si_thread_timers); + /* Disconnect all of the sessions */ + smb_llist_enter(sl, RW_READER); + session = smb_llist_head(sl); + while (session != NULL) { + smb_session_disconnect(session); + session = smb_llist_next(sl, session); + } + smb_llist_exit(sl); + /* * Wake up any threads we might have blocked. * Must precede kdoor_close etc. because those will * wait for such threads to get out. */
*** 1425,1451 **** smb_event_cancel(sv, 0); smb_threshold_wake_all(&sv->sv_ssetup_ct); smb_threshold_wake_all(&sv->sv_tcon_ct); smb_threshold_wake_all(&sv->sv_opipe_ct); smb_kdoor_close(sv); #ifdef _KERNEL smb_kshare_door_fini(sv->sv_lmshrd); #endif /* _KERNEL */ sv->sv_lmshrd = NULL; smb_export_stop(sv); - if (sv->sv_session != NULL) { /* ! * smb_kshare_export may have a request on here. ! * Normal sessions do this in smb_session_cancel() ! * but this is a "fake" session used only for the ! * requests used by the kshare thread(s). */ smb_slist_wait_for_empty(&sv->sv_session->s_req_list); smb_session_delete(sv->sv_session); sv->sv_session = NULL; } if (sv->sv_receiver_pool != NULL) { --- 1462,1533 ---- smb_event_cancel(sv, 0); smb_threshold_wake_all(&sv->sv_ssetup_ct); smb_threshold_wake_all(&sv->sv_tcon_ct); smb_threshold_wake_all(&sv->sv_opipe_ct); + /* + * Wait for the session list to empty. + * (cv_signal in smb_server_destroy_session) + * + * This should not take long, but if there are any leaked + * references to ofiles, trees, or users, there could be a + * session hanging around. If that happens, the ll_count + * never gets to zero and we'll never get the sv_signal. + * Defend against that problem using timed wait, then + * complain if we find sessions left over and continue + * with shutdown in spite of any leaked sessions. + * That's better than a server that won't reboot. + */ + time = SEC_TO_TICK(10) + ddi_get_lbolt(); + mutex_enter(&sv->sv_mutex); + while (sv->sv_session_list.ll_count != 0) { + if (cv_timedwait(&sv->sv_cv, &sv->sv_mutex, time) < 0) + break; + } + mutex_exit(&sv->sv_mutex); + #ifdef DEBUG + if (sv->sv_session_list.ll_count != 0) { + cmn_err(CE_NOTE, "shutdown leaked sessions"); + debug_enter("shutdown leaked sessions"); + } + #endif + + /* + * Clean out any durable handles. After this we should + * have no ofiles remaining (and no more oplock breaks). + */ + smb2_dh_shutdown(sv); + smb_kdoor_close(sv); #ifdef _KERNEL smb_kshare_door_fini(sv->sv_lmshrd); #endif /* _KERNEL */ sv->sv_lmshrd = NULL; smb_export_stop(sv); + smb_kshare_stop(sv); /* ! * Both kshare and the oplock break sub-systems may have ! * taskq jobs on the spcial "server" session, until we've ! * closed all ofiles and stopped the kshare exporter. ! * Now it's safe to destroy the server session, but first ! * wait for any requests on it to finish. Note that for ! * normal sessions, this happens in smb_session_cancel, ! * but that's not called for the server session. */ + if (sv->sv_rootuser != NULL) { + smb_user_logoff(sv->sv_rootuser); + smb_user_release(sv->sv_rootuser); + sv->sv_rootuser = NULL; + } + if (sv->sv_session != NULL) { smb_slist_wait_for_empty(&sv->sv_session->s_req_list); + /* Just in case import left users and trees */ + smb_session_logoff(sv->sv_session); + smb_session_delete(sv->sv_session); sv->sv_session = NULL; } if (sv->sv_receiver_pool != NULL) {
*** 1456,1466 **** if (sv->sv_worker_pool != NULL) { taskq_destroy(sv->sv_worker_pool); sv->sv_worker_pool = NULL; } - smb_kshare_stop(sv); smb_server_fsop_stop(sv); } /* * smb_server_listener_init --- 1538,1547 ----
*** 1492,1503 **** ld->ld_sin6.sin6_port = htons(port); (void) memset(&ld->ld_sin6.sin6_addr.s6_addr, 0, sizeof (ld->ld_sin6.sin6_addr.s6_addr)); } - smb_llist_constructor(&ld->ld_session_list, sizeof (smb_session_t), - offsetof(smb_session_t, s_lnd)); smb_thread_init(&ld->ld_thread, name, smb_server_listener, ld, smbsrv_listen_pri); ld->ld_magic = SMB_LISTENER_MAGIC; } --- 1573,1582 ----
*** 1517,1527 **** return; SMB_LISTENER_VALID(ld); ASSERT(ld->ld_so == NULL); smb_thread_destroy(&ld->ld_thread); - smb_llist_destructor(&ld->ld_session_list); ld->ld_magic = 0; } /* * smb_server_listener_start --- 1596,1605 ----
*** 1615,1625 **** static void smb_server_listener(smb_thread_t *thread, void *arg) { _NOTE(ARGUNUSED(thread)) smb_listener_daemon_t *ld; - smb_session_t *session; ksocket_t s_so; int on; int txbuf_size; ld = (smb_listener_daemon_t *)arg; --- 1693,1702 ----
*** 1626,1637 **** SMB_LISTENER_VALID(ld); DTRACE_PROBE1(so__wait__accept, struct sonode *, ld->ld_so); ! while (ksocket_accept(ld->ld_so, NULL, NULL, &s_so, CRED()) ! == 0) { DTRACE_PROBE1(so__accept, struct sonode *, s_so); on = 1; (void) ksocket_setsockopt(s_so, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on), CRED()); --- 1703,1730 ---- SMB_LISTENER_VALID(ld); DTRACE_PROBE1(so__wait__accept, struct sonode *, ld->ld_so); ! for (;;) { ! int ret = ksocket_accept(ld->ld_so, NULL, NULL, &s_so, CRED()); ! ! switch (ret) { ! case 0: ! break; ! case ECONNABORTED: ! continue; ! case EINTR: ! case EBADF: /* libfakekernel */ ! goto out; ! default: ! cmn_err(CE_WARN, ! "smb_server_listener: ksocket_accept(%d)", ! ret); ! goto out; ! } ! DTRACE_PROBE1(so__accept, struct sonode *, s_so); on = 1; (void) ksocket_setsockopt(s_so, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on), CRED());
*** 1647,1683 **** /* * Create a session for this connection. */ smb_server_create_session(ld, s_so); } ! /* Disconnect all the sessions this listener created. */ ! smb_llist_enter(&ld->ld_session_list, RW_READER); ! session = smb_llist_head(&ld->ld_session_list); ! while (session != NULL) { ! smb_session_disconnect(session); ! session = smb_llist_next(&ld->ld_session_list, session); ! } ! smb_llist_exit(&ld->ld_session_list); ksocket_rele(ld->ld_so); } /* * smb_server_receiver * * Entry point of the receiver threads. */ static void smb_server_receiver(void *arg) { - smb_listener_daemon_t *ld; smb_session_t *session; ! ld = ((smb_receiver_arg_t *)arg)->ra_listener; ! session = ((smb_receiver_arg_t *)arg)->ra_session; ! smb_mem_free(arg); smb_session_receiver(session); ! smb_server_destroy_session(ld, session); } /* * smb_server_lookup * --- 1740,1771 ---- /* * Create a session for this connection. */ smb_server_create_session(ld, s_so); } ! out: ksocket_rele(ld->ld_so); } /* * smb_server_receiver * * Entry point of the receiver threads. + * Also does cleanup when socket disconnected. */ static void smb_server_receiver(void *arg) { smb_session_t *session; ! session = (smb_session_t *)arg; ! ! /* We stay in here until socket disconnect. */ smb_session_receiver(session); ! ! ASSERT(session->s_state == SMB_SESSION_STATE_SHUTDOWN); ! smb_server_destroy_session(session); } /* * smb_server_lookup *
*** 1736,1747 **** /* * Enumerate the users associated with a session list. */ static void ! smb_server_enum_users(smb_llist_t *ll, smb_svcenum_t *svcenum) { smb_session_t *sn; smb_llist_t *ulist; smb_user_t *user; int rc = 0; --- 1824,1836 ---- /* * Enumerate the users associated with a session list. */ static void ! smb_server_enum_users(smb_server_t *sv, smb_svcenum_t *svcenum) { + smb_llist_t *ll = &sv->sv_session_list; smb_session_t *sn; smb_llist_t *ulist; smb_user_t *user; int rc = 0;
*** 1778,1789 **** /* * Enumerate the trees/files associated with a session list. */ static void ! smb_server_enum_trees(smb_llist_t *ll, smb_svcenum_t *svcenum) { smb_session_t *sn; smb_llist_t *tlist; smb_tree_t *tree; int rc = 0; --- 1867,1879 ---- /* * Enumerate the trees/files associated with a session list. */ static void ! smb_server_enum_trees(smb_server_t *sv, smb_svcenum_t *svcenum) { + smb_llist_t *ll = &sv->sv_session_list; smb_session_t *sn; smb_llist_t *tlist; smb_tree_t *tree; int rc = 0;
*** 1821,1878 **** /* * Disconnect sessions associated with the specified client and username. * Empty strings are treated as wildcards. */ static int ! smb_server_session_disconnect(smb_llist_t *ll, const char *client, const char *name) { smb_session_t *sn; smb_llist_t *ulist; smb_user_t *user; - boolean_t match; int count = 0; smb_llist_enter(ll, RW_READER); - sn = smb_llist_head(ll); ! while (sn != NULL) { SMB_SESSION_VALID(sn); ! if ((*client != '\0') && (!smb_session_isclient(sn, client))) { ! sn = smb_llist_next(ll, sn); continue; - } ulist = &sn->s_user_list; smb_llist_enter(ulist, RW_READER); - user = smb_llist_head(ulist); ! while (user != NULL) { ! if (smb_user_hold(user)) { ! match = (*name == '\0'); ! if (!match) ! match = smb_user_namecmp(user, name); ! if (match) { ! smb_llist_exit(ulist); ! smb_user_logoff(user); ! ++count; ! smb_user_release(user); ! smb_llist_enter(ulist, RW_READER); ! user = smb_llist_head(ulist); continue; - } smb_user_release(user); } - - user = smb_llist_next(ulist, user); } smb_llist_exit(ulist); - sn = smb_llist_next(ll, sn); } smb_llist_exit(ll); return (count); } --- 1911,1958 ---- /* * Disconnect sessions associated with the specified client and username. * Empty strings are treated as wildcards. */ static int ! smb_server_session_disconnect(smb_server_t *sv, const char *client, const char *name) { + smb_llist_t *ll = &sv->sv_session_list; smb_session_t *sn; smb_llist_t *ulist; smb_user_t *user; int count = 0; smb_llist_enter(ll, RW_READER); ! for (sn = smb_llist_head(ll); ! sn != NULL; ! sn = smb_llist_next(ll, sn)) { SMB_SESSION_VALID(sn); ! if (*client != '\0' && !smb_session_isclient(sn, client)) continue; ulist = &sn->s_user_list; smb_llist_enter(ulist, RW_READER); ! for (user = smb_llist_head(ulist); ! user != NULL; ! user = smb_llist_next(ulist, user)) { ! SMB_USER_VALID(user); ! if (*name != '\0' && !smb_user_namecmp(user, name)) continue; + if (smb_user_hold(user)) { + smb_user_logoff(user); smb_user_release(user); + count++; } } smb_llist_exit(ulist); } smb_llist_exit(ll); return (count); }
*** 1879,1895 **** /* * Close a file by its unique id. */ static int ! smb_server_fclose(smb_llist_t *ll, uint32_t uniqid) { smb_session_t *sn; smb_llist_t *tlist; smb_tree_t *tree; int rc = ENOENT; smb_llist_enter(ll, RW_READER); sn = smb_llist_head(ll); while ((sn != NULL) && (rc == ENOENT)) { SMB_SESSION_VALID(sn); --- 1959,1977 ---- /* * Close a file by its unique id. */ static int ! smb_server_fclose(smb_server_t *sv, uint32_t uniqid) { + smb_llist_t *ll; smb_session_t *sn; smb_llist_t *tlist; smb_tree_t *tree; int rc = ENOENT; + ll = &sv->sv_session_list; smb_llist_enter(ll, RW_READER); sn = smb_llist_head(ll); while ((sn != NULL) && (rc == ENOENT)) { SMB_SESSION_VALID(sn);
*** 1912,1932 **** smb_llist_exit(ll); return (rc); } /* See also: libsmb smb_kmod_setcfg */ static void smb_server_store_cfg(smb_server_t *sv, smb_ioc_cfg_t *ioc) { if (ioc->maxconnections == 0) ioc->maxconnections = 0xFFFFFFFF; ! smb_session_correct_keep_alive_values( ! &sv->sv_nbt_daemon.ld_session_list, ioc->keepalive); ! smb_session_correct_keep_alive_values( ! &sv->sv_tcp_daemon.ld_session_list, ioc->keepalive); sv->sv_cfg.skc_maxworkers = ioc->maxworkers; sv->sv_cfg.skc_maxconnections = ioc->maxconnections; sv->sv_cfg.skc_keepalive = ioc->keepalive; sv->sv_cfg.skc_restrict_anon = ioc->restrict_anon; --- 1994,2074 ---- smb_llist_exit(ll); return (rc); } + /* + * This is used by SMB2 session setup to find a previous session, + * so it can force a logoff that we haven't noticed yet. + * This is not called frequently, so we just walk the list of + * connections searching for the user. + */ + smb_user_t * + smb_server_lookup_ssnid(smb_server_t *sv, uint64_t ssnid) + { + smb_llist_t *sl; + smb_session_t *sess; + smb_user_t *user = NULL; + + sl = &sv->sv_session_list; + smb_llist_enter(sl, RW_READER); + + for (sess = smb_llist_head(sl); + sess != NULL; + sess = smb_llist_next(sl, sess)) { + + SMB_SESSION_VALID(sess); + + if (sess->dialect < SMB_VERS_2_BASE) + continue; + + /* + * Only look in sessions that are still active. + * Avoid doing an smb_rwx_rwenter sess->s_lock + * on every session here, but re-check below + * with s_lock held. + */ + if (sess->s_state != SMB_SESSION_STATE_NEGOTIATED) + continue; + + user = smb_session_lookup_ssnid(sess, ssnid); + if (user != NULL) { + break; + } + } + + smb_llist_exit(sl); + + /* The sess check is warning avoidance. */ + if (user != NULL && sess != NULL) { + /* + * Re-check the state with s_lock held. + */ + smb_rwx_rwenter(&sess->s_lock, RW_READER); + if (sess->s_state != SMB_SESSION_STATE_NEGOTIATED) { + smb_user_release(user); + user = NULL; + } + smb_rwx_rwexit(&sess->s_lock); + } + + return (user); + } + /* See also: libsmb smb_kmod_setcfg */ static void smb_server_store_cfg(smb_server_t *sv, smb_ioc_cfg_t *ioc) { if (ioc->maxconnections == 0) ioc->maxconnections = 0xFFFFFFFF; ! if (ioc->encrypt == SMB_CONFIG_REQUIRED && ! ioc->max_protocol < SMB_VERS_3_0) { ! cmn_err(CE_WARN, "Server set to require encryption; " ! "forcing max_protocol to 3.0"); ! ioc->max_protocol = SMB_VERS_3_0; ! } sv->sv_cfg.skc_maxworkers = ioc->maxworkers; sv->sv_cfg.skc_maxconnections = ioc->maxconnections; sv->sv_cfg.skc_keepalive = ioc->keepalive; sv->sv_cfg.skc_restrict_anon = ioc->restrict_anon;
*** 1938,1947 **** --- 2080,2091 ---- sv->sv_cfg.skc_netbios_enable = ioc->netbios_enable; sv->sv_cfg.skc_ipv6_enable = ioc->ipv6_enable; sv->sv_cfg.skc_print_enable = ioc->print_enable; sv->sv_cfg.skc_traverse_mounts = ioc->traverse_mounts; sv->sv_cfg.skc_max_protocol = ioc->max_protocol; + sv->sv_cfg.skc_min_protocol = ioc->min_protocol; + sv->sv_cfg.skc_encrypt = ioc->encrypt; sv->sv_cfg.skc_execflags = ioc->exec_flags; sv->sv_cfg.skc_negtok_len = ioc->negtok_len; sv->sv_cfg.skc_version = ioc->version; sv->sv_cfg.skc_initial_credits = ioc->initial_credits; sv->sv_cfg.skc_maximum_credits = ioc->maximum_credits;
*** 2321,2372 **** */ static void smb_server_create_session(smb_listener_daemon_t *ld, ksocket_t s_so) { smb_session_t *session; - smb_receiver_arg_t *rarg; taskqid_t tqid; ! session = smb_session_create(s_so, ld->ld_port, ld->ld_sv, ld->ld_family); if (session == NULL) { smb_soshutdown(s_so); smb_sodestroy(s_so); cmn_err(CE_WARN, "SMB Session: alloc failed"); return; } ! smb_llist_enter(&ld->ld_session_list, RW_WRITER); ! smb_llist_insert_tail(&ld->ld_session_list, session); ! smb_llist_exit(&ld->ld_session_list); - rarg = (smb_receiver_arg_t *)smb_mem_alloc( - sizeof (smb_receiver_arg_t)); - rarg->ra_listener = ld; - rarg->ra_session = session; - /* * These taskq entries must run independently of one another, * so TQ_NOQUEUE. TQ_SLEEP (==0) just for clarity. */ ! tqid = taskq_dispatch(ld->ld_sv->sv_receiver_pool, ! smb_server_receiver, rarg, TQ_NOQUEUE | TQ_SLEEP); if (tqid == 0) { - smb_mem_free(rarg); smb_session_disconnect(session); ! smb_server_destroy_session(ld, session); cmn_err(CE_WARN, "SMB Session: taskq_dispatch failed"); return; } /* handy for debugging */ session->s_receiver_tqid = tqid; } static void ! smb_server_destroy_session(smb_listener_daemon_t *ld, smb_session_t *session) { ! smb_llist_enter(&ld->ld_session_list, RW_WRITER); ! smb_llist_remove(&ld->ld_session_list, session); ! smb_llist_exit(&ld->ld_session_list); smb_session_delete(session); } --- 2465,2543 ---- */ static void smb_server_create_session(smb_listener_daemon_t *ld, ksocket_t s_so) { smb_session_t *session; taskqid_t tqid; + smb_llist_t *sl; + smb_server_t *sv = ld->ld_sv; ! session = smb_session_create(s_so, ld->ld_port, sv, ld->ld_family); if (session == NULL) { smb_soshutdown(s_so); smb_sodestroy(s_so); cmn_err(CE_WARN, "SMB Session: alloc failed"); return; } ! sl = &sv->sv_session_list; ! smb_llist_enter(sl, RW_WRITER); ! smb_llist_insert_tail(sl, session); ! smb_llist_exit(sl); /* * These taskq entries must run independently of one another, * so TQ_NOQUEUE. TQ_SLEEP (==0) just for clarity. */ ! tqid = taskq_dispatch(sv->sv_receiver_pool, ! smb_server_receiver, session, TQ_NOQUEUE | TQ_SLEEP); if (tqid == 0) { smb_session_disconnect(session); ! smb_server_destroy_session(session); cmn_err(CE_WARN, "SMB Session: taskq_dispatch failed"); return; } /* handy for debugging */ session->s_receiver_tqid = tqid; } static void ! smb_server_destroy_session(smb_session_t *session) { ! smb_server_t *sv; ! smb_llist_t *ll; ! uint32_t count; ! ! ASSERT(session->s_server != NULL); ! sv = session->s_server; ! ll = &sv->sv_session_list; ! ! smb_llist_flush(&session->s_tree_list); ! smb_llist_flush(&session->s_user_list); ! ! /* ! * The user and tree lists should be empty now. ! */ ! #ifdef DEBUG ! if (session->s_user_list.ll_count != 0) { ! cmn_err(CE_WARN, "user list not empty?"); ! debug_enter("s_user_list"); ! } ! if (session->s_tree_list.ll_count != 0) { ! cmn_err(CE_WARN, "tree list not empty?"); ! debug_enter("s_tree_list"); ! } ! #endif ! ! smb_llist_enter(ll, RW_WRITER); ! smb_llist_remove(ll, session); ! count = ll->ll_count; ! smb_llist_exit(ll); ! smb_session_delete(session); + if (count == 0) { + /* See smb_server_shutdown */ + cv_signal(&sv->sv_cv); + } }