Print this page
NEX-18761 panic in smb_ofile_free with vdbench
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-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-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-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-6858 Non-admin users unable to mount CIFS shares
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6276 SMB sparse file support
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5737 mutex_enter: bad mutex in smb2 causes panic in mutex_vector_enter
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-3553 SMB2/3 durable handles
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-5537 Want reference counts for users, trees...
Reviewed by: Gordon Ross <gwr@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-3863 Would like an SMB share property to enable/disable quotas
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-3441 CLONE - PORT NEX-3398 Restore SMB map/unmap upcall feature
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-74 Process oplock breaks as session requests (part two)
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-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
re #13470 rb4432 Sync some SMB differences from illumos
re #6813 rb1757 port 2976 Child folder visibility through shares
re #6812 rb1753 backport illumos 1604 smbd print_enable doesn't really work

*** 19,29 **** * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2013 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved. */ /* * General Structures Layout --- 19,29 ---- * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2018 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved. */ /* * General Structures Layout
*** 120,133 **** * * This transition occurs in smb_tree_disconnect(). * * Transition T2 * * This transition occurs in smb_tree_release(). The resources associated * with the tree are freed as well as the tree structure. For the transition ! * to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED state and ! * the reference count be zero. * * Comments * -------- * * The state machine of the tree structures is controlled by 3 elements: --- 120,137 ---- * * This transition occurs in smb_tree_disconnect(). * * Transition T2 * + * This transition occurs in smb_tree_disconnect() + * + * Transition T3 + * * This transition occurs in smb_tree_release(). The resources associated * with the tree are freed as well as the tree structure. For the transition ! * to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED and the ! * reference count must be zero. * * Comments * -------- * * The state machine of the tree structures is controlled by 3 elements:
*** 142,152 **** * the tree from it, the lock must be entered in RW_WRITER mode. * * Rules of access to a tree structure: * * 1) In order to avoid deadlocks, when both (mutex and lock of the user ! * list) have to be entered, the lock must be entered first. * * 2) All actions applied to a tree require a reference count. * * 3) There are 2 ways of getting a reference count: when a tree is * connected and when a tree is looked up. --- 146,160 ---- * the tree from it, the lock must be entered in RW_WRITER mode. * * Rules of access to a tree structure: * * 1) In order to avoid deadlocks, when both (mutex and lock of the user ! * list) have to be entered, the lock must be entered first. Additionally, ! * when both the (mutex and lock of the ofile list) have to be entered, ! * the mutex must be entered first. However, the ofile list lock must NOT ! * be dropped while the mutex is held in such a way that the ofile deleteq ! * is flushed. * * 2) All actions applied to a tree require a reference count. * * 3) There are 2 ways of getting a reference count: when a tree is * connected and when a tree is looked up.
*** 174,195 **** uint32_t smb_tree_connect_core(smb_request_t *); uint32_t smb_tree_connect_disk(smb_request_t *, smb_arg_tcon_t *); uint32_t smb_tree_connect_printq(smb_request_t *, smb_arg_tcon_t *); uint32_t smb_tree_connect_ipc(smb_request_t *, smb_arg_tcon_t *); ! static smb_tree_t *smb_tree_alloc(smb_request_t *, const smb_kshare_t *, ! smb_node_t *, uint32_t, uint32_t); static boolean_t smb_tree_is_connected_locked(smb_tree_t *); - static boolean_t smb_tree_is_disconnected(smb_tree_t *); static char *smb_tree_get_sharename(char *); static int smb_tree_getattr(const smb_kshare_t *, smb_node_t *, smb_tree_t *); static void smb_tree_get_volname(vfs_t *, smb_tree_t *); static void smb_tree_get_flags(const smb_kshare_t *, vfs_t *, smb_tree_t *); static void smb_tree_log(smb_request_t *, const char *, const char *, ...); ! static void smb_tree_close_odirs(smb_tree_t *, uint16_t); ! static smb_ofile_t *smb_tree_get_ofile(smb_tree_t *, smb_ofile_t *); ! static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *); static void smb_tree_set_execinfo(smb_tree_t *, smb_shr_execinfo_t *, int); static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *); static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *); static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *); static void smb_tree_netinfo_fini(smb_netconnectinfo_t *); --- 182,199 ---- uint32_t smb_tree_connect_core(smb_request_t *); uint32_t smb_tree_connect_disk(smb_request_t *, smb_arg_tcon_t *); uint32_t smb_tree_connect_printq(smb_request_t *, smb_arg_tcon_t *); uint32_t smb_tree_connect_ipc(smb_request_t *, smb_arg_tcon_t *); ! static void smb_tree_dealloc(void *); static boolean_t smb_tree_is_connected_locked(smb_tree_t *); static char *smb_tree_get_sharename(char *); static int smb_tree_getattr(const smb_kshare_t *, smb_node_t *, smb_tree_t *); static void smb_tree_get_volname(vfs_t *, smb_tree_t *); static void smb_tree_get_flags(const smb_kshare_t *, vfs_t *, smb_tree_t *); static void smb_tree_log(smb_request_t *, const char *, const char *, ...); ! static void smb_tree_close_odirs(smb_tree_t *, uint32_t); static void smb_tree_set_execinfo(smb_tree_t *, smb_shr_execinfo_t *, int); static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *); static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *); static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *); static void smb_tree_netinfo_fini(smb_netconnectinfo_t *);
*** 250,259 **** --- 254,282 ---- /* NB: name points into tcon->path - don't free it. */ tcon->name = name; sr->sr_tcon.si = si; + /* + * [MS-SMB2] 3.3.5.7 Receiving an SMB2 TREE_CONNECT Request + * + * If we support 3.x, RejectUnencryptedAccess is TRUE, + * if Tcon.EncryptData is TRUE or global EncryptData is TRUE, + * and the connection doesn't support encryption, + * return ACCESS_DENIED. + * + * If RejectUnencryptedAccess is TRUE, we force max_protocol + * to at least 3.0. Additionally, if the tree requires encryption, + * we don't care what we support, we still enforce encryption. + */ + if ((sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED || + si->shr_encrypt == SMB_CONFIG_REQUIRED) && + (sr->session->srv_cap & SMB2_CAP_ENCRYPTION) == 0) { + status = NT_STATUS_ACCESS_DENIED; + goto out; + } + switch (si->shr_type & STYPE_MASK) { case STYPE_DISKTREE: status = smb_tree_connect_disk(sr, &sr->sr_tcon); break; case STYPE_IPC:
*** 265,321 **** default: status = NT_STATUS_BAD_DEVICE_TYPE; break; } smb_kshare_release(sr->sr_server, si); sr->sr_tcon.si = NULL; return (status); } /* * Disconnect a tree. */ void smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec) { smb_shr_execinfo_t execinfo; ASSERT(tree->t_magic == SMB_TREE_MAGIC); mutex_enter(&tree->t_mutex); ASSERT(tree->t_refcnt); ! if (smb_tree_is_connected_locked(tree)) { /* * Indicate that the disconnect process has started. */ tree->t_state = SMB_TREE_STATE_DISCONNECTING; mutex_exit(&tree->t_mutex); - if (do_exec) { /* * The files opened under this tree are closed. */ ! smb_ofile_close_all(tree); /* * The directories opened under this tree are closed. */ smb_tree_close_odirs(tree, 0); - } ! mutex_enter(&tree->t_mutex); ! tree->t_state = SMB_TREE_STATE_DISCONNECTED; ! smb_server_dec_trees(tree->t_server); ! } ! ! mutex_exit(&tree->t_mutex); ! ! if (do_exec && (tree->t_state == SMB_TREE_STATE_DISCONNECTED) && ! (tree->t_execflags & SMB_EXEC_UNMAP)) { ! smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_UNMAP); (void) smb_kshare_exec(tree->t_server, &execinfo); } } --- 288,352 ---- default: status = NT_STATUS_BAD_DEVICE_TYPE; break; } + out: + /* + * On return from smb_tree_connect_* sr->tid_tree is filled in + * and valid for all share types. We can't call smb_kshare_release + * until we disconnect the tree or we will invalidate the reference + * we have here. + */ + if (sr->tid_tree != NULL) { + sr->tid_tree->t_kshare = si; + } else { smb_kshare_release(sr->sr_server, si); + } + sr->sr_tcon.si = NULL; return (status); } /* * Disconnect a tree. + * + * The "do_exec" arg is obsolete and ignored. */ void smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec) { + _NOTE(ARGUNUSED(do_exec)) smb_shr_execinfo_t execinfo; ASSERT(tree->t_magic == SMB_TREE_MAGIC); mutex_enter(&tree->t_mutex); ASSERT(tree->t_refcnt); ! if (!smb_tree_is_connected_locked(tree)) { ! mutex_exit(&tree->t_mutex); ! return; ! } ! /* * Indicate that the disconnect process has started. */ tree->t_state = SMB_TREE_STATE_DISCONNECTING; mutex_exit(&tree->t_mutex); /* * The files opened under this tree are closed. */ ! smb_ofile_close_all(tree, 0); /* * The directories opened under this tree are closed. */ smb_tree_close_odirs(tree, 0); ! if ((tree->t_execflags & SMB_EXEC_UNMAP) != 0) { smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_UNMAP); (void) smb_kshare_exec(tree->t_server, &execinfo); } }
*** 369,416 **** smb_tree_release( smb_tree_t *tree) { SMB_TREE_VALID(tree); - mutex_enter(&tree->t_mutex); - ASSERT(tree->t_refcnt); - tree->t_refcnt--; - /* flush the ofile and odir lists' delete queues */ smb_llist_flush(&tree->t_ofile_list); smb_llist_flush(&tree->t_odir_list); ! if (smb_tree_is_disconnected(tree) && (tree->t_refcnt == 0)) ! smb_session_post_tree(tree->t_session, tree); mutex_exit(&tree->t_mutex); } - void - smb_tree_post_ofile(smb_tree_t *tree, smb_ofile_t *of) - { - SMB_TREE_VALID(tree); - SMB_OFILE_VALID(of); - ASSERT(of->f_refcnt == 0); - ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED); - ASSERT(of->f_tree == tree); - - smb_llist_post(&tree->t_ofile_list, of, smb_ofile_delete); - } - - void - smb_tree_post_odir(smb_tree_t *tree, smb_odir_t *od) - { - SMB_TREE_VALID(tree); - SMB_ODIR_VALID(od); - ASSERT(od->d_refcnt == 0); - ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED); - ASSERT(od->d_tree == tree); - - smb_llist_post(&tree->t_odir_list, od, smb_odir_delete); - } - /* * Close ofiles and odirs that match pid. */ void smb_tree_close_pid( --- 400,436 ---- smb_tree_release( smb_tree_t *tree) { SMB_TREE_VALID(tree); /* flush the ofile and odir lists' delete queues */ smb_llist_flush(&tree->t_ofile_list); smb_llist_flush(&tree->t_odir_list); ! mutex_enter(&tree->t_mutex); ! ASSERT(tree->t_refcnt); ! tree->t_refcnt--; + switch (tree->t_state) { + case SMB_TREE_STATE_DISCONNECTING: + if (tree->t_refcnt == 0) { + smb_session_t *ssn = tree->t_session; + tree->t_state = SMB_TREE_STATE_DISCONNECTED; + smb_llist_post(&ssn->s_tree_list, tree, + smb_tree_dealloc); + } + break; + case SMB_TREE_STATE_CONNECTED: + break; + default: + ASSERT(0); + break; + } + mutex_exit(&tree->t_mutex); } /* * Close ofiles and odirs that match pid. */ void smb_tree_close_pid(
*** 418,428 **** uint32_t pid) { ASSERT(tree); ASSERT(tree->t_magic == SMB_TREE_MAGIC); ! smb_ofile_close_all_by_pid(tree, pid); smb_tree_close_odirs(tree, pid); } /* * Check whether or not a tree supports the features identified by flags. --- 438,448 ---- uint32_t pid) { ASSERT(tree); ASSERT(tree->t_magic == SMB_TREE_MAGIC); ! smb_ofile_close_all(tree, pid); smb_tree_close_odirs(tree, pid); } /* * Check whether or not a tree supports the features identified by flags.
*** 443,476 **** * This function should be called with a hold on the tree. */ int smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum) { smb_ofile_t *of; - smb_ofile_t *next; int rc = 0; - ASSERT(tree); - ASSERT(tree->t_magic == SMB_TREE_MAGIC); - if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE) return (smb_tree_enum_private(tree, svcenum)); ! of = smb_tree_get_ofile(tree, NULL); ! while (of) { ! ASSERT(of->f_tree == tree); rc = smb_ofile_enum(of, svcenum); - if (rc != 0) { smb_ofile_release(of); break; } ! next = smb_tree_get_ofile(tree, of); ! smb_ofile_release(of); ! of = next; ! } return (rc); } /* --- 463,494 ---- * This function should be called with a hold on the tree. */ int smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum) { + smb_llist_t *of_list; smb_ofile_t *of; int rc = 0; if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE) return (smb_tree_enum_private(tree, svcenum)); ! of_list = &tree->t_ofile_list; ! smb_llist_enter(of_list, RW_READER); + of = smb_llist_head(of_list); + while (of) { + if (smb_ofile_hold(of)) { rc = smb_ofile_enum(of, svcenum); smb_ofile_release(of); + } + if (rc != 0) break; + of = smb_llist_next(of_list, of); } ! smb_llist_exit(of_list); return (rc); } /*
*** 482,491 **** --- 500,514 ---- smb_ofile_t *of; ASSERT(tree); ASSERT(tree->t_magic == SMB_TREE_MAGIC); + /* + * Note that ORPHANED ofiles aren't fclosable, as they have + * no session, user, or tree by which they might be found. + * They will eventually expire. + */ if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL) return (ENOENT); if (smb_ofile_disallow_fclose(of)) { smb_ofile_release(of);
*** 637,664 **** } return (access); } /* * Connect a share for use with files and directories. */ uint32_t smb_tree_connect_disk(smb_request_t *sr, smb_arg_tcon_t *tcon) { char *sharename = tcon->path; const char *any = "?????"; smb_user_t *user = sr->uid_user; - smb_node_t *dnode = NULL; smb_node_t *snode = NULL; smb_kshare_t *si = tcon->si; char *service = tcon->service; - char last_component[MAXNAMELEN]; smb_tree_t *tree; int rc; uint32_t access; smb_shr_execinfo_t execinfo; ASSERT(user); ASSERT(user->u_cred); if (service != NULL && --- 660,689 ---- } return (access); } + /* How long should tree connect wait for DH import to complete? */ + int smb_tcon_import_wait = 20; /* sec. */ + /* * Connect a share for use with files and directories. */ uint32_t smb_tree_connect_disk(smb_request_t *sr, smb_arg_tcon_t *tcon) { char *sharename = tcon->path; const char *any = "?????"; smb_user_t *user = sr->uid_user; smb_node_t *snode = NULL; smb_kshare_t *si = tcon->si; char *service = tcon->service; smb_tree_t *tree; int rc; uint32_t access; smb_shr_execinfo_t execinfo; + clock_t time; ASSERT(user); ASSERT(user->u_cred); if (service != NULL &&
*** 669,702 **** } /* * Check that the shared directory exists. */ ! rc = smb_pathname_reduce(sr, user->u_cred, si->shr_path, 0, 0, &dnode, ! last_component); ! if (rc == 0) { ! rc = smb_fsop_lookup(sr, user->u_cred, SMB_FOLLOW_LINKS, ! sr->sr_server->si_root_smb_node, dnode, last_component, ! &snode); ! ! smb_node_release(dnode); ! } ! ! if (rc) { ! if (snode) ! smb_node_release(snode); ! smb_tree_log(sr, sharename, "bad path: %s", si->shr_path); return (NT_STATUS_BAD_NETWORK_NAME); } if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) { - smb_node_release(snode); return (NT_STATUS_ACCESS_DENIED); } /* * Set up the OptionalSupport for this share. */ tcon->optional_support = SMB_SUPPORT_SEARCH_BITS; switch (si->shr_flags & SMB_SHRF_CSC_MASK) { --- 694,730 ---- } /* * Check that the shared directory exists. */ ! snode = si->shr_root_node; ! if (snode == NULL) { smb_tree_log(sr, sharename, "bad path: %s", si->shr_path); return (NT_STATUS_BAD_NETWORK_NAME); } if ((access = smb_tree_chkaccess(sr, si, snode->vp)) == 0) { return (NT_STATUS_ACCESS_DENIED); } /* + * Wait for DH import of persistent handles to finish. + * If we timeout, it's not clear what status to return, + * but as the share is not really availale yet, let's + * return the status for "no such share". + */ + time = SEC_TO_TICK(smb_tcon_import_wait) + ddi_get_lbolt(); + mutex_enter(&si->shr_mutex); + while (si->shr_import_busy != NULL) { + if (cv_timedwait(&si->shr_cv, &si->shr_mutex, time) < 0) { + mutex_exit(&si->shr_mutex); + return (NT_STATUS_BAD_NETWORK_NAME); + } + } + mutex_exit(&si->shr_mutex); + + /* * Set up the OptionalSupport for this share. */ tcon->optional_support = SMB_SUPPORT_SEARCH_BITS; switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
*** 729,750 **** if (!smb_shortnames) sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME; tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags); - smb_node_release(snode); - if (tree == NULL) return (NT_STATUS_INSUFF_SERVER_RESOURCES); if (tree->t_execflags & SMB_EXEC_MAP) { smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_MAP); rc = smb_kshare_exec(tree->t_server, &execinfo); if ((rc != 0) && (tree->t_execflags & SMB_EXEC_TERM)) { ! smb_tree_disconnect(tree, B_FALSE); smb_tree_release(tree); return (NT_STATUS_ACCESS_DENIED); } } --- 757,786 ---- if (!smb_shortnames) sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME; tree = smb_tree_alloc(sr, si, snode, access, sr->sr_cfg->skc_execflags); if (tree == NULL) return (NT_STATUS_INSUFF_SERVER_RESOURCES); if (tree->t_execflags & SMB_EXEC_MAP) { smb_tree_set_execinfo(tree, &execinfo, SMB_EXEC_MAP); rc = smb_kshare_exec(tree->t_server, &execinfo); if ((rc != 0) && (tree->t_execflags & SMB_EXEC_TERM)) { ! /* ! * Inline parts of: smb_tree_disconnect() ! * Not using smb_tree_disconnect() for cleanup ! * here because: we don't want an exec up-call, ! * and there can't be any opens as we never ! * returned this TID to the client. ! */ ! mutex_enter(&tree->t_mutex); ! tree->t_state = SMB_TREE_STATE_DISCONNECTING; ! mutex_enter(&tree->t_mutex); ! smb_tree_release(tree); return (NT_STATUS_ACCESS_DENIED); } }
*** 872,882 **** } /* * Allocate a tree. */ ! static smb_tree_t * smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si, smb_node_t *snode, uint32_t access, uint32_t execflags) { smb_session_t *session = sr->session; smb_tree_t *tree; --- 908,918 ---- } /* * Allocate a tree. */ ! smb_tree_t * smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si, smb_node_t *snode, uint32_t access, uint32_t execflags) { smb_session_t *session = sr->session; smb_tree_t *tree;
*** 916,926 **** kmem_cache_free(smb_cache_tree, tree); return (NULL); } smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t), ! offsetof(smb_ofile_t, f_lnd)); smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t), offsetof(smb_odir_t, d_lnd)); (void) strlcpy(tree->t_sharename, si->shr_name, --- 952,962 ---- kmem_cache_free(smb_cache_tree, tree); return (NULL); } smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t), ! offsetof(smb_ofile_t, f_tree_lnd)); smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t), offsetof(smb_odir_t, d_lnd)); (void) strlcpy(tree->t_sharename, si->shr_name,
*** 962,993 **** * empty. * * Remove the tree from the user's tree list before freeing resources * associated with the tree. */ ! void smb_tree_dealloc(void *arg) { smb_session_t *session; smb_tree_t *tree = (smb_tree_t *)arg; SMB_TREE_VALID(tree); ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); ASSERT(tree->t_refcnt == 0); session = tree->t_session; smb_llist_enter(&session->s_tree_list, RW_WRITER); smb_llist_remove(&session->s_tree_list, tree); smb_idpool_free(&session->s_tid_pool, tree->t_tid); atomic_dec_32(&session->s_tree_cnt); smb_llist_exit(&session->s_tree_list); mutex_enter(&tree->t_mutex); mutex_exit(&tree->t_mutex); tree->t_magic = (uint32_t)~SMB_TREE_MAGIC; if (tree->t_snode) smb_node_release(tree->t_snode); mutex_destroy(&tree->t_mutex); smb_llist_destructor(&tree->t_ofile_list); --- 998,1043 ---- * empty. * * Remove the tree from the user's tree list before freeing resources * associated with the tree. */ ! static void smb_tree_dealloc(void *arg) { smb_session_t *session; smb_tree_t *tree = (smb_tree_t *)arg; SMB_TREE_VALID(tree); ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); ASSERT(tree->t_refcnt == 0); + smb_server_dec_trees(tree->t_server); + session = tree->t_session; smb_llist_enter(&session->s_tree_list, RW_WRITER); smb_llist_remove(&session->s_tree_list, tree); smb_idpool_free(&session->s_tid_pool, tree->t_tid); atomic_dec_32(&session->s_tree_cnt); smb_llist_exit(&session->s_tree_list); + /* + * This tree is no longer on s_tree_list, however... + * + * This is called via smb_llist_post, which means it may run + * BEFORE smb_tree_release drops t_mutex (if another thread + * flushes the delete queue before we do). Synchronize. + */ mutex_enter(&tree->t_mutex); mutex_exit(&tree->t_mutex); tree->t_magic = (uint32_t)~SMB_TREE_MAGIC; + if (tree->t_kshare != NULL) { + smb_kshare_release(tree->t_server, tree->t_kshare); + tree->t_kshare = NULL; + } + if (tree->t_snode) smb_node_release(tree->t_snode); mutex_destroy(&tree->t_mutex); smb_llist_destructor(&tree->t_ofile_list);
*** 1013,1023 **** return (B_TRUE); case SMB_TREE_STATE_DISCONNECTING: case SMB_TREE_STATE_DISCONNECTED: /* ! * The tree exists but being diconnected or destroyed. */ return (B_FALSE); default: ASSERT(0); --- 1063,1073 ---- return (B_TRUE); case SMB_TREE_STATE_DISCONNECTING: case SMB_TREE_STATE_DISCONNECTED: /* ! * The tree exists but is being disconnected or destroyed. */ return (B_FALSE); default: ASSERT(0);
*** 1024,1054 **** return (B_FALSE); } } /* - * Determine whether or not a tree is disconnected. - * This function must be called with the tree mutex held. - */ - static boolean_t - smb_tree_is_disconnected(smb_tree_t *tree) - { - switch (tree->t_state) { - case SMB_TREE_STATE_DISCONNECTED: - return (B_TRUE); - - case SMB_TREE_STATE_CONNECTED: - case SMB_TREE_STATE_DISCONNECTING: - return (B_FALSE); - - default: - ASSERT(0); - return (B_FALSE); - } - } - - /* * Return a pointer to the share name within a share resource path. * * The share path may be a Uniform Naming Convention (UNC) string * (\\server\share) or simply the share name. We validate the UNC * format but we don't look at the server name. --- 1074,1083 ----
*** 1084,1102 **** --- 1113,1145 ---- */ static int smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree) { vfs_t *vfsp = SMB_NODE_VFS(node); + smb_cfg_val_t srv_encrypt; ASSERT(vfsp); if (getvfs(&vfsp->vfs_fsid) != vfsp) return (ESTALE); smb_tree_get_volname(vfsp, tree); smb_tree_get_flags(si, vfsp, tree); + srv_encrypt = tree->t_session->s_server->sv_cfg.skc_encrypt; + if (tree->t_session->dialect >= SMB_VERS_3_0) { + if (si->shr_encrypt == SMB_CONFIG_REQUIRED || + srv_encrypt == SMB_CONFIG_REQUIRED) + tree->t_encrypt = SMB_CONFIG_REQUIRED; + else if (si->shr_encrypt == SMB_CONFIG_ENABLED || + srv_encrypt == SMB_CONFIG_ENABLED) + tree->t_encrypt = SMB_CONFIG_ENABLED; + else + tree->t_encrypt = SMB_CONFIG_DISABLED; + } else + tree->t_encrypt = SMB_CONFIG_DISABLED; + VFS_RELE(vfsp); return (0); } /*
*** 1145,1154 **** --- 1188,1201 ---- size_t mt_namelen; uint32_t mt_flags; } smb_mtype_t; static smb_mtype_t smb_mtype[] = { + #ifdef _FAKE_KERNEL + /* See libfksmbsrv:fake_vfs.c */ + { "fake", 3, SMB_TREE_SPARSE}, + #endif /* _FAKE_KERNEL */ { "zfs", 3, SMB_TREE_QUOTA | SMB_TREE_SPARSE}, { "ufs", 3, 0 }, { "nfs", 3, SMB_TREE_NFS_MOUNTED }, { "tmpfs", 5, SMB_TREE_NO_EXPORT } };
*** 1166,1175 **** --- 1213,1228 ---- flags |= SMB_TREE_CATIA; if (si->shr_flags & SMB_SHRF_ABE) flags |= SMB_TREE_ABE; + if (si->shr_flags & SMB_SHRF_CA) + flags |= SMB_TREE_CA; + + if (si->shr_flags & SMB_SHRF_FSO) + flags |= SMB_TREE_FORCE_L2_OPLOCK; + if (ssn->s_cfg.skc_oplock_enable) { /* if 'smb' zfs property: oplocks=enabled */ flags |= SMB_TREE_OPLOCKS; }
*** 1199,1208 **** --- 1252,1268 ---- mtype = &smb_mtype[i]; if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0) flags |= mtype->mt_flags; } + /* + * SMB_TREE_QUOTA will be on here if the FS is ZFS. We want to + * turn it OFF when the share property says false. + */ + if ((si->shr_flags & SMB_SHRF_QUOTAS) == 0) + flags &= ~SMB_TREE_QUOTA; + (void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN); (void) smb_strupr((char *)tree->t_typename); if (vfs_has_feature(vfsp, VFSFT_XVATTR)) flags |= SMB_TREE_XVATTR;
*** 1318,1430 **** mutex_exit(&tree->t_mutex); return (rb); } /* ! * Get the next open ofile in the list. A reference is taken on ! * the ofile, which can be released later with smb_ofile_release(). * ! * If the specified ofile is NULL, search from the beginning of the ! * list. Otherwise, the search starts just after that ofile. ! * ! * Returns NULL if there are no open files in the list. */ ! static smb_ofile_t * ! smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of) { - smb_llist_t *ofile_list; - - ASSERT(tree); - ASSERT(tree->t_magic == SMB_TREE_MAGIC); - - ofile_list = &tree->t_ofile_list; - smb_llist_enter(ofile_list, RW_READER); - - if (of) { - ASSERT(of->f_magic == SMB_OFILE_MAGIC); - of = smb_llist_next(ofile_list, of); - } else { - of = smb_llist_head(ofile_list); - } - - while (of) { - if (smb_ofile_hold(of)) - break; - - of = smb_llist_next(ofile_list, of); - } - - smb_llist_exit(ofile_list); - return (of); - } - - /* - * smb_tree_get_odir - * - * Find the next odir in the tree's list of odirs, and obtain a - * hold on it. - * If the specified odir is NULL the search starts at the beginning - * of the tree's odir list, otherwise the search starts after the - * specified odir. - */ - static smb_odir_t * - smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od) - { smb_llist_t *od_list; ASSERT(tree); ASSERT(tree->t_magic == SMB_TREE_MAGIC); od_list = &tree->t_odir_list; smb_llist_enter(od_list, RW_READER); ! if (od) { ! ASSERT(od->d_magic == SMB_ODIR_MAGIC); ! od = smb_llist_next(od_list, od); ! } else { ! od = smb_llist_head(od_list); ! } - while (od) { ASSERT(od->d_magic == SMB_ODIR_MAGIC); - - if (smb_odir_hold(od)) - break; - od = smb_llist_next(od_list, od); - } - - smb_llist_exit(od_list); - return (od); - } - - /* - * smb_tree_close_odirs - * - * Close all open odirs in the tree's list which were opened by - * the process identified by pid. - * If pid is zero, close all open odirs in the tree's list. - */ - static void - smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid) - { - smb_odir_t *od, *next_od; - - ASSERT(tree); - ASSERT(tree->t_magic == SMB_TREE_MAGIC); - - od = smb_tree_get_odir(tree, NULL); - while (od) { - ASSERT(od->d_magic == SMB_ODIR_MAGIC); ASSERT(od->d_tree == tree); ! next_od = smb_tree_get_odir(tree, od); ! if ((pid == 0) || (od->d_opened_by_pid == pid)) smb_odir_close(od); smb_odir_release(od); - - od = next_od; } } static void smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec, int exec_type) --- 1378,1422 ---- mutex_exit(&tree->t_mutex); return (rb); } /* ! * smb_tree_close_odirs * ! * Close all open odirs in the tree's list which were opened by ! * the process identified by pid. ! * If pid is zero, close all open odirs in the tree's list. */ ! static void ! smb_tree_close_odirs(smb_tree_t *tree, uint32_t pid) { smb_llist_t *od_list; + smb_odir_t *od; ASSERT(tree); ASSERT(tree->t_magic == SMB_TREE_MAGIC); od_list = &tree->t_odir_list; smb_llist_enter(od_list, RW_READER); ! for (od = smb_llist_head(od_list); ! od != NULL; ! od = smb_llist_next(od_list, od)) { ASSERT(od->d_magic == SMB_ODIR_MAGIC); ASSERT(od->d_tree == tree); ! if (pid != 0 && od->d_opened_by_pid != pid) ! continue; ! ! if (smb_odir_hold(od)) { smb_odir_close(od); smb_odir_release(od); } + } + + smb_llist_exit(od_list); } static void smb_tree_set_execinfo(smb_tree_t *tree, smb_shr_execinfo_t *exec, int exec_type)