]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ksmbd: delete asynchronous work from list
authorNamjae Jeon <linkinjeon@kernel.org>
Sun, 31 Dec 2023 07:12:32 +0000 (16:12 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Jan 2024 14:18:28 +0000 (15:18 +0100)
[ Upstream commit 3a9b557f44ea8f216aab515a7db20e23f0eb51b9 ]

When smb2_lock request is canceled by smb2_cancel or smb2_close(),
ksmbd is missing deleting async_request_entry async_requests list.
Because calling init_smb2_rsp_hdr() in smb2_lock() mark ->synchronous
as true and then it will not be deleted in
ksmbd_conn_try_dequeue_request(). This patch add release_async_work() to
release the ones allocated for async work.

Cc: stable@vger.kernel.org
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/smb/server/connection.c
fs/smb/server/ksmbd_work.h
fs/smb/server/smb2pdu.c
fs/smb/server/smb2pdu.h

index ffbf14d0241916fbd50885b35358363c5b647f5f..00a87b4acd5c52080fbcae12fad1418e3c251eba 100644 (file)
@@ -114,10 +114,8 @@ void ksmbd_conn_enqueue_request(struct ksmbd_work *work)
        struct ksmbd_conn *conn = work->conn;
        struct list_head *requests_queue = NULL;
 
-       if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE) {
+       if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE)
                requests_queue = &conn->requests;
-               work->synchronous = true;
-       }
 
        if (requests_queue) {
                atomic_inc(&conn->req_running);
@@ -138,14 +136,14 @@ int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
 
        if (!work->multiRsp)
                atomic_dec(&conn->req_running);
-       spin_lock(&conn->request_lock);
        if (!work->multiRsp) {
+               spin_lock(&conn->request_lock);
                list_del_init(&work->request_entry);
-               if (!work->synchronous)
-                       list_del_init(&work->async_request_entry);
+               spin_unlock(&conn->request_lock);
+               if (work->asynchronous)
+                       release_async_work(work);
                ret = 0;
        }
-       spin_unlock(&conn->request_lock);
 
        wake_up_all(&conn->req_running_q);
        return ret;
index 3234f2cf6327cf22ac227c64e4be8afb376073ef..f8ae6144c0aea6ba8724fbed3b48f0d1e719d6a1 100644 (file)
@@ -68,7 +68,7 @@ struct ksmbd_work {
        /* Request is encrypted */
        bool                            encrypted:1;
        /* Is this SYNC or ASYNC ksmbd_work */
-       bool                            synchronous:1;
+       bool                            asynchronous:1;
        bool                            need_invalidate_rkey:1;
 
        unsigned int                    remote_key;
index d3939fd481497269b47d8f980c21ef97fa6f648b..ee128f5d38c354e2df6f8210ba5daabec51889c5 100644 (file)
@@ -508,12 +508,6 @@ int init_smb2_rsp_hdr(struct ksmbd_work *work)
        rsp_hdr->SessionId = rcv_hdr->SessionId;
        memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16);
 
-       work->synchronous = true;
-       if (work->async_id) {
-               ksmbd_release_id(&conn->async_ida, work->async_id);
-               work->async_id = 0;
-       }
-
        return 0;
 }
 
@@ -671,7 +665,7 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
                pr_err("Failed to alloc async message id\n");
                return id;
        }
-       work->synchronous = false;
+       work->asynchronous = true;
        work->async_id = id;
        rsp_hdr->Id.AsyncId = cpu_to_le64(id);
 
@@ -691,6 +685,24 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
        return 0;
 }
 
+void release_async_work(struct ksmbd_work *work)
+{
+       struct ksmbd_conn *conn = work->conn;
+
+       spin_lock(&conn->request_lock);
+       list_del_init(&work->async_request_entry);
+       spin_unlock(&conn->request_lock);
+
+       work->asynchronous = 0;
+       work->cancel_fn = NULL;
+       kfree(work->cancel_argv);
+       work->cancel_argv = NULL;
+       if (work->async_id) {
+               ksmbd_release_id(&conn->async_ida, work->async_id);
+               work->async_id = 0;
+       }
+}
+
 void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)
 {
        struct smb2_hdr *rsp_hdr;
@@ -7153,13 +7165,9 @@ skip:
 
                                ksmbd_vfs_posix_lock_wait(flock);
 
-                               spin_lock(&work->conn->request_lock);
                                spin_lock(&fp->f_lock);
                                list_del(&work->fp_entry);
-                               work->cancel_fn = NULL;
-                               kfree(argv);
                                spin_unlock(&fp->f_lock);
-                               spin_unlock(&work->conn->request_lock);
 
                                if (work->state != KSMBD_WORK_ACTIVE) {
                                        list_del(&smb_lock->llist);
@@ -7177,6 +7185,7 @@ skip:
                                                work->send_no_response = 1;
                                                goto out;
                                        }
+
                                        init_smb2_rsp_hdr(work);
                                        smb2_set_err_rsp(work);
                                        rsp->hdr.Status =
@@ -7189,7 +7198,7 @@ skip:
                                spin_lock(&work->conn->llist_lock);
                                list_del(&smb_lock->clist);
                                spin_unlock(&work->conn->llist_lock);
-
+                               release_async_work(work);
                                goto retry;
                        } else if (!rc) {
                                spin_lock(&work->conn->llist_lock);
index f13bd65993ccc8b45aae35c2abcfaa408ef39257..59e3de95961c16c3e1b893a5fb7364cd837bb040 100644 (file)
@@ -488,6 +488,7 @@ int find_matching_smb2_dialect(int start_index, __le16 *cli_dialects,
 struct file_lock *smb_flock_init(struct file *f);
 int setup_async_work(struct ksmbd_work *work, void (*fn)(void **),
                     void **arg);
+void release_async_work(struct ksmbd_work *work);
 void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status);
 struct channel *lookup_chann_list(struct ksmbd_session *sess,
                                  struct ksmbd_conn *conn);