Linux CIFS filesystem development
 help / color / mirror / Atom feed
* [PATCH 01/22] ksmbd: release connection lock while draining old session
@ 2026-10-17  1:03 Namjae Jeon
  2026-10-17  1:03 ` [PATCH 02/22] ksmbd: serialize oplock break ACK state updates Namjae Jeon
                   ` (20 more replies)
  0 siblings, 21 replies; 22+ messages in thread
From: Namjae Jeon @ 2026-10-17  1:03 UTC (permalink / raw)
  To: linux-cifs
  Cc: senozhatsky, tom, atteh.mailbox, chenxiaosong, chenxiaosong,
	Namjae Jeon, Pan Guihua

Previous-session teardown waits for requests on the old channels. Holding
srv_mutex during that wait can block their responses and prevent the drain
from completing.

Record the previous session ID during authentication, finish using the
request's authentication state, and release srv_mutex while the old
session drains. Keep the response binding decision in the work item because
signing and preauthentication hashing run after the drain.

Reported-by: Pan Guihua <pan.guihua@datatom.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
---
 fs/smb/server/ksmbd_work.h        |  2 ++
 fs/smb/server/mgmt/user_session.c | 15 +++++++++
 fs/smb/server/smb2pdu.c           | 56 ++++++++++++++++++-------------
 3 files changed, 49 insertions(+), 24 deletions(-)

diff --git a/fs/smb/server/ksmbd_work.h b/fs/smb/server/ksmbd_work.h
index 3a14e4d69aa1..40f70a5d08b5 100644
--- a/fs/smb/server/ksmbd_work.h
+++ b/fs/smb/server/ksmbd_work.h
@@ -94,6 +94,8 @@ struct ksmbd_work {
 	bool                            need_invalidate_rkey:1;
 	bool				request_open_chseq_tracked:1;
 	bool				session_setup_reauth:1;
+	/* Retain the binding decision for response signing and preauth hashing. */
+	bool				session_setup_binding:1;
 
 	unsigned int                    remote_key;
 	/* cancel works */
diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
index 1321cd6c84e7..d814a99ff519 100644
--- a/fs/smb/server/mgmt/user_session.c
+++ b/fs/smb/server/mgmt/user_session.c
@@ -759,6 +759,7 @@ void destroy_previous_session(struct ksmbd_conn *conn,
 {
 	struct ksmbd_session *prev_sess;
 	struct ksmbd_user *prev_user;
+	bool pinned = false;
 	int err;
 
 	down_write(&sessions_table_lock);
@@ -781,9 +782,21 @@ void destroy_previous_session(struct ksmbd_conn *conn,
 	}
 	prev_sess->tearing_down = true;
 	up_write(&prev_sess->chann_lock);
+	ksmbd_user_session_get(prev_sess);
+	pinned = true;
+	up_write(&conn->session_lock);
+	up_write(&sessions_table_lock);
 
 	ksmbd_all_conn_set_status(prev_sess, KSMBD_SESS_NEED_RECONNECT);
+	/*
+	 * The caller has finished using the connection's authentication state.
+	 * Drop srv_mutex so drained requests can write their responses.
+	 */
+	ksmbd_conn_unlock(conn);
 	err = ksmbd_conn_wait_idle_sess(conn, prev_sess);
+	ksmbd_conn_lock(conn);
+	down_write(&sessions_table_lock);
+	down_write(&conn->session_lock);
 	if (err) {
 		down_write(&prev_sess->chann_lock);
 		prev_sess->tearing_down = false;
@@ -800,6 +813,8 @@ void destroy_previous_session(struct ksmbd_conn *conn,
 out:
 	up_write(&conn->session_lock);
 	up_write(&sessions_table_lock);
+	if (pinned)
+		ksmbd_user_session_put(prev_sess);
 }
 
 static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 2da6163ee776..aca51f54a38d 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2206,14 +2206,14 @@ static struct ksmbd_user *session_user(struct ksmbd_conn *conn,
 
 static int ntlm_authenticate(struct ksmbd_work *work,
 			     struct smb2_sess_setup_req *req,
-			     struct smb2_sess_setup_rsp *rsp)
+			     struct smb2_sess_setup_rsp *rsp,
+			     u64 *previous_session_id)
 {
 	struct ksmbd_conn *conn = work->conn;
 	struct ksmbd_session *sess = work->sess;
 	struct ksmbd_user *user;
 	char channel_key[CIFS_KEY_SIZE] = {};
 	char *auth_key = conn->binding ? channel_key : sess->sess_key;
-	u64 prev_id;
 	bool binding = conn->binding;
 	int sz, rc;
 
@@ -2278,9 +2278,7 @@ static int ntlm_authenticate(struct ksmbd_work *work,
 		}
 	}
 
-	prev_id = le64_to_cpu(req->PreviousSessionId);
-	if (prev_id && prev_id != sess->id)
-		destroy_previous_session(conn, sess->user, prev_id);
+	*previous_session_id = le64_to_cpu(req->PreviousSessionId);
 
 	/*
 	 * If session state is SMB2_SESSION_VALID, We can assume
@@ -2342,7 +2340,8 @@ static int ntlm_authenticate(struct ksmbd_work *work,
 #ifdef CONFIG_SMB_SERVER_KERBEROS5
 static int krb5_authenticate(struct ksmbd_work *work,
 			     struct smb2_sess_setup_req *req,
-			     struct smb2_sess_setup_rsp *rsp)
+			     struct smb2_sess_setup_rsp *rsp,
+			     u64 *previous_session_id)
 {
 	struct ksmbd_conn *conn = work->conn;
 	struct ksmbd_session *sess = work->sess;
@@ -2351,7 +2350,6 @@ static int krb5_authenticate(struct ksmbd_work *work,
 	char reauth_key[CIFS_KEY_SIZE] = {};
 	char *auth_key = conn->binding ? channel_key :
 		(work->session_setup_reauth ? reauth_key : sess->sess_key);
-	u64 prev_sess_id;
 	bool binding = conn->binding;
 	int in_len, out_len;
 	int retval;
@@ -2373,10 +2371,7 @@ static int krb5_authenticate(struct ksmbd_work *work,
 		goto out;
 	}
 
-	/* Check previous session */
-	prev_sess_id = le64_to_cpu(req->PreviousSessionId);
-	if (prev_sess_id && prev_sess_id != sess->id)
-		destroy_previous_session(conn, sess->user, prev_sess_id);
+	*previous_session_id = le64_to_cpu(req->PreviousSessionId);
 
 	rsp->SecurityBufferLength = cpu_to_le16(out_len);
 
@@ -2445,7 +2440,8 @@ static int krb5_authenticate(struct ksmbd_work *work,
 #else
 static int krb5_authenticate(struct ksmbd_work *work,
 			     struct smb2_sess_setup_req *req,
-			     struct smb2_sess_setup_rsp *rsp)
+			     struct smb2_sess_setup_rsp *rsp,
+			     u64 *previous_session_id)
 {
 	return -EOPNOTSUPP;
 }
@@ -2459,6 +2455,8 @@ int smb2_sess_setup(struct ksmbd_work *work)
 	struct ksmbd_session *sess = NULL;
 	struct negotiate_message *negblob;
 	unsigned int negblob_len, negblob_off;
+	u64 previous_session_id = 0;
+	bool authenticated = false;
 	int rc = 0;
 
 	ksmbd_debug(SMB, "Received smb2 session setup request\n");
@@ -2648,14 +2646,11 @@ int smb2_sess_setup(struct ksmbd_work *work)
 
 		if (conn->preferred_auth_mech &
 				(KSMBD_AUTH_KRB5 | KSMBD_AUTH_MSKRB5)) {
-			rc = krb5_authenticate(work, req, rsp);
+			rc = krb5_authenticate(work, req, rsp, &previous_session_id);
 			if (rc)
 				goto out_err;
 
-			if (!ksmbd_conn_need_reconnect(conn)) {
-				ksmbd_conn_set_good(conn);
-				sess->state = SMB2_SESSION_VALID;
-			}
+			authenticated = true;
 		} else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) {
 			if (negblob->MessageType == NtLmNegotiate) {
 				rc = ntlm_negotiate(work, negblob, negblob_len, rsp);
@@ -2664,14 +2659,12 @@ int smb2_sess_setup(struct ksmbd_work *work)
 				rsp->hdr.Status =
 					STATUS_MORE_PROCESSING_REQUIRED;
 			} else if (negblob->MessageType == NtLmAuthenticate) {
-				rc = ntlm_authenticate(work, req, rsp);
+				rc = ntlm_authenticate(work, req, rsp,
+						       &previous_session_id);
 				if (rc)
 					goto out_err;
 
-				if (!ksmbd_conn_need_reconnect(conn)) {
-					ksmbd_conn_set_good(conn);
-					sess->state = SMB2_SESSION_VALID;
-				}
+				authenticated = true;
 				if (conn->binding) {
 					struct preauth_session *preauth_sess;
 
@@ -2804,6 +2797,21 @@ int smb2_sess_setup(struct ksmbd_work *work)
 			rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
 	}
 
+	work->session_setup_binding = conn->binding;
+	if (authenticated) {
+		/*
+		 * Draining the previous session drops srv_mutex. Finish using the
+		 * connection's authentication state and free mechToken first, and
+		 * retain this request's binding decision for response processing.
+		 */
+		if (previous_session_id && previous_session_id != sess->id)
+			destroy_previous_session(conn, sess->user, previous_session_id);
+		if (!ksmbd_conn_need_reconnect(conn)) {
+			ksmbd_conn_set_good(conn);
+			sess->state = SMB2_SESSION_VALID;
+		}
+	}
+
 	ksmbd_conn_unlock(conn);
 	return rc;
 }
@@ -12478,7 +12486,7 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
 	command = le16_to_cpu(hdr->Command);
 
 	if (command == SMB2_SESSION_SETUP_HE &&
-	    (!conn->binding || hdr->Status != STATUS_SUCCESS)) {
+	    (!work->session_setup_binding || hdr->Status != STATUS_SUCCESS)) {
 		signing_key = work->sess->smb3signingkey;
 	} else {
 		chann = lookup_chann_list(work->sess, work->conn);
@@ -12527,7 +12535,7 @@ void smb3_preauth_hash_rsp(struct ksmbd_work *work)
 	if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && sess) {
 		ksmbd_conn_lock(conn);
 
-		if (conn->binding) {
+		if (work->session_setup_binding) {
 			struct preauth_session *preauth_sess;
 
 			preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2026-10-17  1:04 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-17  1:03 [PATCH 01/22] ksmbd: release connection lock while draining old session Namjae Jeon
2026-10-17  1:03 ` [PATCH 02/22] ksmbd: serialize oplock break ACK state updates Namjae Jeon
2026-10-17  1:03 ` [PATCH 03/22] ksmbd: track delivery of queued TCP writes Namjae Jeon
2026-10-17  1:03 ` [PATCH 04/22] ksmbd: retry break notifications on another connection Namjae Jeon
2026-10-17  1:03 ` [PATCH 05/22] ksmbd: keep lease tables until their last lease is closed Namjae Jeon
2026-10-17  1:03 ` [PATCH 06/22] ksmbd: index byte-range locks independently of their connection Namjae Jeon
2026-10-17  1:03 ` [PATCH 07/22] ksmbd: rebind completed CREATE replays without draining the old channel Namjae Jeon
2026-10-17  1:03 ` [PATCH 08/22] ksmbd: track SMB2 locks above OFFSET_MAX in server lock table Namjae Jeon
2026-10-17  1:03 ` [PATCH 09/22] ksmbd: expire unacknowledged oplock breaks Namjae Jeon
2026-10-17  1:03 ` [PATCH 10/22] ksmbd: expire unacknowledged lease breaks Namjae Jeon
2026-10-17  1:03 ` [PATCH 11/22] ksmbd: support SMB2 quota query and set information Namjae Jeon
2026-10-17  1:03 ` [PATCH 12/22] ksmbd: validate POSIX negotiate contexts Namjae Jeon
2026-10-17  1:03 ` [PATCH 13/22] ksmbd: validate POSIX create contexts Namjae Jeon
2026-10-17  1:03 ` [PATCH 14/22] ksmbd: enforce POSIX append-only writes Namjae Jeon
2026-10-17  1:03 ` [PATCH 15/22] ksmbd: apply byte-range lock checks per open Namjae Jeon
2026-10-17  1:03 ` [PATCH 16/22] ksmbd: use requested mode in POSIX creates Namjae Jeon
2026-10-17  1:03 ` [PATCH 17/22] ksmbd: apply POSIX mode ACEs in security updates Namjae Jeon
2026-10-17  1:03 ` [PATCH 18/22] ksmbd: correct POSIX file metadata in responses Namjae Jeon
2026-10-17  1:03 ` [PATCH 19/22] ksmbd: include filenames in POSIX query info Namjae Jeon
2026-10-17  1:03 ` [PATCH 20/22] ksmbd: require POSIX opens for file and directory queries Namjae Jeon
2026-10-17  1:03 ` [PATCH 21/22] ksmbd: query POSIX filesystem info through the open file Namjae Jeon
2026-10-17  1:03 ` [PATCH 22/22] ksmbd: correct POSIX filesystem block size and response length Namjae Jeon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox