From f495154703cbcc0050cfd53469bd56965791616b Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 13 Jul 2026 10:09:27 +0900 Subject: [PATCH] ksmbd: retain connection for pending notify work Deferred CHANGE_NOTIFY work keeps an async message ID after the original request work is released. A durable handle can outlive its connection, so the connection teardown can destroy its async IDA before the handle close releases the pending notify work. Give the synthetic deferred work a connection reference. Release it after the async ID in ksmbd_free_work_struct(). This keeps the async IDA alive until the deferred work is released, even when the original connection has already left the connection list. During server shutdown there is no client to receive a cleanup response. Skip the write and only release the pending work. Signed-off-by: Namjae Jeon --- fs/smb/server/ksmbd_work.c | 2 ++ fs/smb/server/ksmbd_work.h | 2 ++ fs/smb/server/smb2pdu.c | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/smb/server/ksmbd_work.c b/fs/smb/server/ksmbd_work.c index 97502273a49c..c3f8915c3952 100644 --- a/fs/smb/server/ksmbd_work.c +++ b/fs/smb/server/ksmbd_work.c @@ -86,6 +86,8 @@ void ksmbd_free_work_struct(struct ksmbd_work *work) if (work->async_id) ksmbd_release_id(&work->conn->async_ida, work->async_id); + if (work->owns_conn_ref) + ksmbd_conn_put(work->conn); kmem_cache_free(work_cache, work); } diff --git a/fs/smb/server/ksmbd_work.h b/fs/smb/server/ksmbd_work.h index 50c4aa779647..e35a40d764d6 100644 --- a/fs/smb/server/ksmbd_work.h +++ b/fs/smb/server/ksmbd_work.h @@ -90,6 +90,8 @@ struct ksmbd_work { bool compress_response:1; /* Is this SYNC or ASYNC ksmbd_work */ bool asynchronous:1; + /* Work owns a reference to @conn. */ + bool owns_conn_ref:1; bool need_invalidate_rkey:1; unsigned int remote_key; diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index d5fcb1108898..ca208a686f86 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -10510,7 +10510,9 @@ int smb2_notify(struct ksmbd_work *work) smb2_send_interim_resp(work, STATUS_PENDING); - in_work->conn = work->conn; + /* Keep the async IDA alive until the deferred work is released. */ + in_work->conn = ksmbd_conn_get(work->conn); + in_work->owns_conn_ref = true; in_hdr = smb_get_msg(in_work->response_buf); memcpy(in_hdr, ksmbd_resp_buf_next(work), __SMB2_HEADER_STRUCTURE_SIZE); in_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;