ksmbd: reorganize ksmbd_iov_pin_rsp()
authorNamjae Jeon <linkinjeon@kernel.org>
Sun, 31 Dec 2023 07:19:02 +0000 (16:19 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Jan 2024 14:19:38 +0000 (15:19 +0100)
[ Upstream commit 1819a904299942b309f687cc0f08b123500aa178 ]

If ksmbd_iov_pin_rsp fail, io vertor should be rollback.
This patch moves memory allocations to before setting the io vector
to avoid rollbacks.

Fixes: e2b76ab8b5c9 ("ksmbd: add support for read compound")
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/ksmbd_work.c

index 51def3c..a2ed441 100644 (file)
@@ -95,11 +95,28 @@ bool ksmbd_queue_work(struct ksmbd_work *work)
        return queue_work(ksmbd_wq, &work->work);
 }
 
-static int ksmbd_realloc_iov_pin(struct ksmbd_work *work, void *ib,
-                                unsigned int ib_len)
+static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib,
+                                  unsigned int ib_len)
 {
+       work->iov[++work->iov_idx].iov_base = ib;
+       work->iov[work->iov_idx].iov_len = ib_len;
+       work->iov_cnt++;
+}
+
+static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
+                              void *aux_buf, unsigned int aux_size)
+{
+       struct aux_read *ar;
+       int need_iov_cnt = 1;
 
-       if (work->iov_alloc_cnt <= work->iov_cnt) {
+       if (aux_size) {
+               need_iov_cnt++;
+               ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL);
+               if (!ar)
+                       return -ENOMEM;
+       }
+
+       if (work->iov_alloc_cnt < work->iov_cnt + need_iov_cnt) {
                struct kvec *new;
 
                work->iov_alloc_cnt += 4;
@@ -111,16 +128,6 @@ static int ksmbd_realloc_iov_pin(struct ksmbd_work *work, void *ib,
                work->iov = new;
        }
 
-       work->iov[++work->iov_idx].iov_base = ib;
-       work->iov[work->iov_idx].iov_len = ib_len;
-       work->iov_cnt++;
-
-       return 0;
-}
-
-static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
-                              void *aux_buf, unsigned int aux_size)
-{
        /* Plus rfc_length size on first iov */
        if (!work->iov_idx) {
                work->iov[work->iov_idx].iov_base = work->response_buf;
@@ -129,19 +136,13 @@ static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
                work->iov_cnt++;
        }
 
-       ksmbd_realloc_iov_pin(work, ib, len);
+       __ksmbd_iov_pin(work, ib, len);
        inc_rfc1001_len(work->iov[0].iov_base, len);
 
        if (aux_size) {
-               struct aux_read *ar;
-
-               ksmbd_realloc_iov_pin(work, aux_buf, aux_size);
+               __ksmbd_iov_pin(work, aux_buf, aux_size);
                inc_rfc1001_len(work->iov[0].iov_base, aux_size);
 
-               ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL);
-               if (!ar)
-                       return -ENOMEM;
-
                ar->buf = aux_buf;
                list_add(&ar->entry, &work->aux_read_list);
        }