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