summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_fsctl_sparse.c5
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_server.c76
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_user.c49
-rw-r--r--usr/src/uts/common/smbsrv/smb_kproto.h3
-rw-r--r--usr/src/uts/common/smbsrv/smb_ktypes.h2
7 files changed, 123 insertions, 16 deletions
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c
index fe748bbd62..6a9040a5db 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c
@@ -308,6 +308,8 @@ smb2_fsctl_odx_read(smb_request_t *sr, smb_fsctl_t *fsctl)
*/
data = in_file_off;
tok_type = STORAGE_OFFLOAD_TOKEN_TYPE_NATIVE1;
+ if (sr->sr_state != SMB_REQ_STATE_ACTIVE)
+ return (NT_STATUS_SUCCESS);
rc = smb_fsop_next_alloc_range(ofile->f_cr, ofile->f_node,
&data, &hole);
switch (rc) {
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_sparse.c b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_sparse.c
index 90bb254670..91f13a150e 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_sparse.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_sparse.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
*/
/*
@@ -306,6 +306,9 @@ smb2_sparse_copy(
while (*residp > 0) {
+ if (sr->sr_state != SMB_REQ_STATE_ACTIVE)
+ break;
+
data = src_off;
rc = smb_fsop_next_alloc_range(src_ofile->f_cr,
src_ofile->f_node, &data, &hole);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_server.c b/usr/src/uts/common/fs/smbsrv/smb_server.c
index 7f86fd478d..63ca6343bc 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c
@@ -1998,6 +1998,10 @@ smb_server_fclose(smb_server_t *sv, uint32_t uniqid)
* 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.
+ *
+ * Note that this must wait for any durable handles (ofiles)
+ * owned by this user to become "orphaned", so that a reconnect
+ * that may immediately follow can find and use such ofiles.
*/
void
smb_server_logoff_ssnid(smb_request_t *sr, uint64_t ssnid)
@@ -2005,6 +2009,9 @@ smb_server_logoff_ssnid(smb_request_t *sr, uint64_t ssnid)
smb_server_t *sv = sr->sr_server;
smb_llist_t *sess_list;
smb_session_t *sess;
+ smb_user_t *user = NULL;
+
+ SMB_SERVER_VALID(sv);
if (sv->sv_state != SMB_SERVER_STATE_RUNNING)
return;
@@ -2016,38 +2023,77 @@ smb_server_logoff_ssnid(smb_request_t *sr, uint64_t ssnid)
sess != NULL;
sess = smb_llist_next(sess_list, sess)) {
- smb_user_t *user;
-
SMB_SESSION_VALID(sess);
if (sess->dialect < SMB_VERS_2_BASE)
continue;
- if (sess->s_state != SMB_SESSION_STATE_NEGOTIATED)
+ switch (sess->s_state) {
+ case SMB_SESSION_STATE_NEGOTIATED:
+ case SMB_SESSION_STATE_TERMINATED:
+ case SMB_SESSION_STATE_DISCONNECTED:
+ break;
+ default:
continue;
+ }
- user = smb_session_lookup_ssnid(sess, ssnid);
- if (user == NULL)
- continue;
+ /*
+ * Normal situation is to find a LOGGED_ON user.
+ */
+ user = smb_session_lookup_uid_st(sess, ssnid, 0,
+ SMB_USER_STATE_LOGGED_ON);
+ if (user != NULL) {
+
+ if (smb_is_same_user(user->u_cred, sr->user_cr)) {
+ /* Treat this as if we lost the connection */
+ user->preserve_opens = SMB2_DH_PRESERVE_SOME;
+ smb_user_logoff(user);
+ break;
+ }
+ smb_user_release(user);
+ user = NULL;
+ }
- if (!smb_is_same_user(user->u_cred, sr->user_cr)) {
+ /*
+ * If we raced with disconnect, may find LOGGING_OFF,
+ * in which case we want to just wait for it.
+ */
+ user = smb_session_lookup_uid_st(sess, ssnid, 0,
+ SMB_USER_STATE_LOGGING_OFF);
+ if (user != NULL) {
+ if (smb_is_same_user(user->u_cred, sr->user_cr))
+ break;
smb_user_release(user);
- continue;
+ user = NULL;
}
+ }
- /* Treat this as if we lost the connection */
- user->preserve_opens = SMB2_DH_PRESERVE_SOME;
- smb_user_logoff(user);
- smb_user_release(user);
+ smb_llist_exit(sess_list);
+ if (user != NULL) {
/*
- * The above may have left work on the delete queues
+ * Wait for durable handles to be orphaned.
+ * Note: not holding the sess list rwlock.
*/
+ smb_user_wait_trees(user);
+
+ /*
+ * Could be doing the last release on a user below,
+ * which can leave work on the delete queues for
+ * s_user_list or s_tree_list so flush those.
+ * Must hold the session list after the user release
+ * so that the session can't go away while we flush.
+ */
+ smb_llist_enter(sess_list, RW_READER);
+
+ sess = user->u_session;
+ smb_user_release(user);
+
smb_llist_flush(&sess->s_tree_list);
smb_llist_flush(&sess->s_user_list);
- }
- smb_llist_exit(sess_list);
+ smb_llist_exit(sess_list);
+ }
}
/* See also: libsmb smb_kmod_setcfg */
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c
index 45f381ffb1..2aadc3bf38 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c
@@ -963,6 +963,7 @@ smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si,
/* grab a ref for tree->t_owner */
smb_user_hold_internal(sr->uid_user);
+ smb_user_inc_trees(sr->uid_user);
tree->t_owner = sr->uid_user;
/* if FS is readonly, enforce that here */
@@ -1031,6 +1032,7 @@ smb_tree_dealloc(void *arg)
smb_idpool_destructor(&tree->t_odid_pool);
SMB_USER_VALID(tree->t_owner);
+ smb_user_dec_trees(tree->t_owner);
smb_user_release(tree->t_owner);
kmem_cache_free(smb_cache_tree, tree);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_user.c b/usr/src/uts/common/fs/smbsrv/smb_user.c
index 8934a213eb..a5dc57315f 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_user.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_user.c
@@ -662,6 +662,55 @@ smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
return (rc);
}
+/*
+ * Count references by trees this user owns,
+ * and allow waiting for them to go away.
+ */
+void
+smb_user_inc_trees(smb_user_t *user)
+{
+ mutex_enter(&user->u_mutex);
+ user->u_owned_tree_cnt++;
+ mutex_exit(&user->u_mutex);
+}
+
+void
+smb_user_dec_trees(smb_user_t *user)
+{
+ mutex_enter(&user->u_mutex);
+ user->u_owned_tree_cnt--;
+ if (user->u_owned_tree_cnt == 0)
+ cv_broadcast(&user->u_owned_tree_cv);
+ mutex_exit(&user->u_mutex);
+}
+
+int smb_user_wait_tree_tmo = 30;
+
+/*
+ * Wait (up to 30 sec.) for trees to go away.
+ * Should happen in less than a second.
+ */
+void
+smb_user_wait_trees(smb_user_t *user)
+{
+ clock_t time;
+
+ time = SEC_TO_TICK(smb_user_wait_tree_tmo) + ddi_get_lbolt();
+ mutex_enter(&user->u_mutex);
+ while (user->u_owned_tree_cnt != 0) {
+ if (cv_timedwait(&user->u_owned_tree_cv,
+ &user->u_mutex, time) < 0)
+ break;
+ }
+ mutex_exit(&user->u_mutex);
+#ifdef DEBUG
+ if (user->u_owned_tree_cnt != 0) {
+ cmn_err(CE_NOTE, "smb_user_wait_trees failed");
+ debug_enter("smb_user_wait_trees debug");
+ }
+#endif
+}
+
/* *************************** Static Functions ***************************** */
/*
diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h
index d830739802..f61b9aa9a2 100644
--- a/usr/src/uts/common/smbsrv/smb_kproto.h
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h
@@ -742,6 +742,9 @@ cred_t *smb_kcred_create(void);
void smb_user_setcred(smb_user_t *, cred_t *, uint32_t);
boolean_t smb_is_same_user(cred_t *, cred_t *);
boolean_t smb_user_has_security_priv(smb_user_t *, cred_t *);
+void smb_user_inc_trees(smb_user_t *);
+void smb_user_dec_trees(smb_user_t *);
+void smb_user_wait_trees(smb_user_t *);
/*
* SMB tree functions (file smb_tree.c)
diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h
index e105d297e3..89b057ff91 100644
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h
@@ -1077,6 +1077,8 @@ typedef struct smb_user {
uint32_t u_privileges;
uint16_t u_uid; /* unique per-session */
uint32_t u_audit_sid;
+ uint32_t u_owned_tree_cnt;
+ kcondvar_t u_owned_tree_cv;
uint32_t u_sign_flags;
struct smb_key u_sign_key; /* SMB2 signing */