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;