Re: [PATCH v3 3/3] smb/server: stop new async work when closing connection

Namjae Jeon <[email protected]> Thu, 23 Jul 2026 15:49:22 +0900
Newsgroups org.kernel.vger.linux-cifs
Message-ID <CAKYAXd_X5JSh8YGk5Z8-gx2A=PDcmW74jKK8co=z=9Zxty5xSg@mail.gmail.com>
On Thu, Jul 23, 2026 at 1:12 PM ChenXiaoSong
<[email protected]> wrote:
>
> From: ChenXiaoSong <[email protected]>
>
> A new async request may be added while a connection is closing.
> The close code may miss this request and wait forever.
>
> Check the connection state before adding the request. Return an error
> and release the async ID if the connection is closing.
>
> Signed-off-by: ChenXiaoSong <[email protected]>
I would like to apply the attached patch instead of this one, so
please check it.

Thanks!
0001-smb-server-avoid-registering-async-requests-during-c.patch (text/x-patch, 3.4 KB)
From cf7802b09d66448f2fd8c5f89ab1a3994b0f7190 Mon Sep 17 00:00:00 2001
From: Namjae Jeon <[email protected]>
Date: Thu, 23 Jul 2026 15:24:10 +0900
Subject: [PATCH] smb/server: avoid registering async requests during
 connection close

A connection-close scan can miss the synthetic CHANGE_NOTIFY work item
because smb2_notify() registers it directly after setup_async_work()
has returned. Link both regular and synthetic async work through one
helper that checks the connection state under request_lock.

If the connection is already closing, release a newly allocated async
ID or complete the synthetic notify work immediately.

Co-developed-by: ChenXiaoSong <[email protected]>
Signed-off-by: ChenXiaoSong <[email protected]>
Signed-off-by: Namjae Jeon <[email protected]>
---
 fs/smb/server/smb2pdu.c | 53 +++++++++++++++++++++++++++++++----------
 1 file changed, 41 insertions(+), 12 deletions(-)

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 9c93a39f3588..2038de315fbc 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -991,6 +991,24 @@ smb2_get_name(const char *src, const int maxlen, struct nls_table *local_nls)
 	return name;
 }
 
+/* Link a fully initialized async work item unless the connection is closing. */
+static bool ksmbd_conn_link_async_request(struct ksmbd_conn *conn,
+					  struct ksmbd_work *work)
+{
+	bool linked = false;
+
+	spin_lock(&conn->request_lock);
+	if (!ksmbd_conn_exiting(conn) && !ksmbd_conn_releasing(conn)) {
+		if (list_empty(&work->async_request_entry))
+			list_add_tail(&work->async_request_entry,
+				      &conn->async_requests);
+		linked = true;
+	}
+	spin_unlock(&conn->request_lock);
+
+	return linked;
+}
+
 int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
 {
 	struct ksmbd_conn *conn = work->conn;
@@ -1003,20 +1021,22 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
 	}
 	work->asynchronous = true;
 	work->async_id = id;
-
-	ksmbd_debug(SMB,
-		    "Send interim Response to inform async request id : %d\n",
-		    work->async_id);
-
 	work->cancel_fn = fn;
 	work->cancel_argv = arg;
 
-	if (list_empty(&work->async_request_entry)) {
-		spin_lock(&conn->request_lock);
-		list_add_tail(&work->async_request_entry, &conn->async_requests);
-		spin_unlock(&conn->request_lock);
+	if (!ksmbd_conn_link_async_request(conn, work)) {
+		work->asynchronous = false;
+		work->async_id = 0;
+		work->cancel_fn = NULL;
+		work->cancel_argv = NULL;
+		ksmbd_release_id(&conn->async_ida, id);
+		return -ESHUTDOWN;
 	}
 
+	ksmbd_debug(SMB,
+		    "Send interim Response to inform async request id : %d\n",
+		    work->async_id);
+
 	return 0;
 }
 
@@ -11075,9 +11095,18 @@ int smb2_notify(struct ksmbd_work *work)
 		in_work->cancel_argv[1] = fp;
 		in_work->cancel_fn = smb2_notify_cancel_fn;
 	}
-	spin_lock(&work->conn->request_lock);
-	list_add_tail(&in_work->async_request_entry, &work->conn->async_requests);
-	spin_unlock(&work->conn->request_lock);
+
+	if (!ksmbd_conn_link_async_request(work->conn, in_work)) {
+		kfree(in_work->cancel_argv);
+		in_work->cancel_argv = NULL;
+		in_work->cancel_fn = NULL;
+		in_work->asynchronous = false;
+		ksmbd_fd_put(work, fp);
+		ksmbd_conn_write(in_work);
+		ksmbd_free_work_struct(in_work);
+		work->send_no_response = 1;
+		return 0;
+	}
 
 	spin_lock(&fp->f_lock);
 	list_add_tail(&in_work->notify_entry, &fp->notify_pendings);
-- 
2.34.1