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)