From: Namjae Jeon <linkinjeon@kernel.org>
To: linux-cifs@vger.kernel.org
Cc: senozhatsky@chromium.org, tom@talpey.com,
atteh.mailbox@gmail.com, chenxiaosong@chenxiaosong.com,
chenxiaosong@kylinos.cn, Namjae Jeon <linkinjeon@kernel.org>,
Pan Guihua <pan.guihua@datatom.com>
Subject: [PATCH 01/22] ksmbd: release connection lock while draining old session
Date: Sat, 17 Oct 2026 10:03:23 +0900 [thread overview]
Message-ID: <20261017010344.11478-1-linkinjeon@kernel.org> (raw)
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
next reply other threads:[~2026-10-17 1:03 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-17 1:03 Namjae Jeon [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261017010344.11478-1-linkinjeon@kernel.org \
--to=linkinjeon@kernel.org \
--cc=atteh.mailbox@gmail.com \
--cc=chenxiaosong@chenxiaosong.com \
--cc=chenxiaosong@kylinos.cn \
--cc=linux-cifs@vger.kernel.org \
--cc=pan.guihua@datatom.com \
--cc=senozhatsky@chromium.org \
--cc=tom@talpey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox