]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 18 Apr 2023 10:32:33 +0000 (12:32 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 18 Apr 2023 10:32:33 +0000 (12:32 +0200)
added patches:
virtiofs-clean-up-error-handling-in-virtio_fs_get_tree.patch
virtiofs-split-requests-that-exceed-virtqueue-size.patch

queue-5.10/series
queue-5.10/virtiofs-clean-up-error-handling-in-virtio_fs_get_tree.patch [new file with mode: 0644]
queue-5.10/virtiofs-split-requests-that-exceed-virtqueue-size.patch [new file with mode: 0644]

index 24702d5c9461f20c372d1c9cb313c061fd6d5c8e..7265cc859b8643593185c1c36f0d9b9ebb5212ec 100644 (file)
@@ -121,3 +121,5 @@ riscv-handle-zicsr-zifencei-issues-between-clang-and-binutils.patch
 kexec-move-locking-into-do_kexec_load.patch
 kexec-turn-all-kexec_mutex-acquisitions-into-trylocks.patch
 panic-kexec-make-__crash_kexec-nmi-safe.patch
+virtiofs-clean-up-error-handling-in-virtio_fs_get_tree.patch
+virtiofs-split-requests-that-exceed-virtqueue-size.patch
diff --git a/queue-5.10/virtiofs-clean-up-error-handling-in-virtio_fs_get_tree.patch b/queue-5.10/virtiofs-clean-up-error-handling-in-virtio_fs_get_tree.patch
new file mode 100644 (file)
index 0000000..91bb32b
--- /dev/null
@@ -0,0 +1,62 @@
+From 833c5a42e28beeefa1f9bd476a63fe8050c1e8ca Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Wed, 11 Nov 2020 17:22:32 +0100
+Subject: virtiofs: clean up error handling in virtio_fs_get_tree()
+
+From: Miklos Szeredi <mszeredi@redhat.com>
+
+commit 833c5a42e28beeefa1f9bd476a63fe8050c1e8ca upstream.
+
+Avoid duplicating error cleanup.
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Yang Bo <yb203166@antfin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/fuse/virtio_fs.c |   25 ++++++++++++-------------
+ 1 file changed, 12 insertions(+), 13 deletions(-)
+
+--- a/fs/fuse/virtio_fs.c
++++ b/fs/fuse/virtio_fs.c
+@@ -1440,22 +1440,14 @@ static int virtio_fs_get_tree(struct fs_
+               return -EINVAL;
+       }
++      err = -ENOMEM;
+       fc = kzalloc(sizeof(struct fuse_conn), GFP_KERNEL);
+-      if (!fc) {
+-              mutex_lock(&virtio_fs_mutex);
+-              virtio_fs_put(fs);
+-              mutex_unlock(&virtio_fs_mutex);
+-              return -ENOMEM;
+-      }
++      if (!fc)
++              goto out_err;
+       fm = kzalloc(sizeof(struct fuse_mount), GFP_KERNEL);
+-      if (!fm) {
+-              mutex_lock(&virtio_fs_mutex);
+-              virtio_fs_put(fs);
+-              mutex_unlock(&virtio_fs_mutex);
+-              kfree(fc);
+-              return -ENOMEM;
+-      }
++      if (!fm)
++              goto out_err;
+       fuse_conn_init(fc, fm, fsc->user_ns, &virtio_fs_fiq_ops, fs);
+       fc->release = fuse_free_conn;
+@@ -1483,6 +1475,13 @@ static int virtio_fs_get_tree(struct fs_
+       WARN_ON(fsc->root);
+       fsc->root = dget(sb->s_root);
+       return 0;
++
++out_err:
++      kfree(fc);
++      mutex_lock(&virtio_fs_mutex);
++      virtio_fs_put(fs);
++      mutex_unlock(&virtio_fs_mutex);
++      return err;
+ }
+ static const struct fs_context_operations virtio_fs_context_ops = {
diff --git a/queue-5.10/virtiofs-split-requests-that-exceed-virtqueue-size.patch b/queue-5.10/virtiofs-split-requests-that-exceed-virtqueue-size.patch
new file mode 100644 (file)
index 0000000..0516ee0
--- /dev/null
@@ -0,0 +1,122 @@
+From a7f0d7aab0b4f3f0780b1f77356e2fe7202ac0cb Mon Sep 17 00:00:00 2001
+From: Connor Kuehl <ckuehl@redhat.com>
+Date: Thu, 18 Mar 2021 08:52:22 -0500
+Subject: virtiofs: split requests that exceed virtqueue size
+
+From: Connor Kuehl <ckuehl@redhat.com>
+
+commit a7f0d7aab0b4f3f0780b1f77356e2fe7202ac0cb upstream.
+
+If an incoming FUSE request can't fit on the virtqueue, the request is
+placed onto a workqueue so a worker can try to resubmit it later where
+there will (hopefully) be space for it next time.
+
+This is fine for requests that aren't larger than a virtqueue's maximum
+capacity.  However, if a request's size exceeds the maximum capacity of the
+virtqueue (even if the virtqueue is empty), it will be doomed to a life of
+being placed on the workqueue, removed, discovered it won't fit, and placed
+on the workqueue yet again.
+
+Furthermore, from section 2.6.5.3.1 (Driver Requirements: Indirect
+Descriptors) of the virtio spec:
+
+  "A driver MUST NOT create a descriptor chain longer than the Queue
+  Size of the device."
+
+To fix this, limit the number of pages FUSE will use for an overall
+request.  This way, each request can realistically fit on the virtqueue
+when it is decomposed into a scattergather list and avoid violating section
+2.6.5.3.1 of the virtio spec.
+
+Signed-off-by: Connor Kuehl <ckuehl@redhat.com>
+Reviewed-by: Vivek Goyal <vgoyal@redhat.com>
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Yang Bo <yb203166@antfin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/fuse/fuse_i.h    |    3 +++
+ fs/fuse/inode.c     |    3 ++-
+ fs/fuse/virtio_fs.c |   19 +++++++++++++++++--
+ 3 files changed, 22 insertions(+), 3 deletions(-)
+
+--- a/fs/fuse/fuse_i.h
++++ b/fs/fuse/fuse_i.h
+@@ -556,6 +556,9 @@ struct fuse_conn {
+       /** Maxmum number of pages that can be used in a single request */
+       unsigned int max_pages;
++      /** Constrain ->max_pages to this value during feature negotiation */
++      unsigned int max_pages_limit;
++
+       /** Input queue */
+       struct fuse_iqueue iq;
+--- a/fs/fuse/inode.c
++++ b/fs/fuse/inode.c
+@@ -710,6 +710,7 @@ void fuse_conn_init(struct fuse_conn *fc
+       fc->pid_ns = get_pid_ns(task_active_pid_ns(current));
+       fc->user_ns = get_user_ns(user_ns);
+       fc->max_pages = FUSE_DEFAULT_MAX_PAGES_PER_REQ;
++      fc->max_pages_limit = FUSE_MAX_MAX_PAGES;
+       INIT_LIST_HEAD(&fc->mounts);
+       list_add(&fm->fc_entry, &fc->mounts);
+@@ -1056,7 +1057,7 @@ static void process_init_reply(struct fu
+                               fc->abort_err = 1;
+                       if (arg->flags & FUSE_MAX_PAGES) {
+                               fc->max_pages =
+-                                      min_t(unsigned int, FUSE_MAX_MAX_PAGES,
++                                      min_t(unsigned int, fc->max_pages_limit,
+                                       max_t(unsigned int, arg->max_pages, 1));
+                       }
+                       if (IS_ENABLED(CONFIG_FUSE_DAX) &&
+--- a/fs/fuse/virtio_fs.c
++++ b/fs/fuse/virtio_fs.c
+@@ -18,6 +18,12 @@
+ #include <linux/uio.h>
+ #include "fuse_i.h"
++/* Used to help calculate the FUSE connection's max_pages limit for a request's
++ * size. Parts of the struct fuse_req are sliced into scattergather lists in
++ * addition to the pages used, so this can help account for that overhead.
++ */
++#define FUSE_HEADER_OVERHEAD    4
++
+ /* List of virtio-fs device instances and a lock for the list. Also provides
+  * mutual exclusion in device removal and mounting path
+  */
+@@ -1426,9 +1432,10 @@ static int virtio_fs_get_tree(struct fs_
+ {
+       struct virtio_fs *fs;
+       struct super_block *sb;
+-      struct fuse_conn *fc;
++      struct fuse_conn *fc = NULL;
+       struct fuse_mount *fm;
+-      int err;
++      unsigned int virtqueue_size;
++      int err = -EIO;
+       /* This gets a reference on virtio_fs object. This ptr gets installed
+        * in fc->iq->priv. Once fuse_conn is going away, it calls ->put()
+@@ -1440,6 +1447,10 @@ static int virtio_fs_get_tree(struct fs_
+               return -EINVAL;
+       }
++      virtqueue_size = virtqueue_get_vring_size(fs->vqs[VQ_REQUEST].vq);
++      if (WARN_ON(virtqueue_size <= FUSE_HEADER_OVERHEAD))
++              goto out_err;
++
+       err = -ENOMEM;
+       fc = kzalloc(sizeof(struct fuse_conn), GFP_KERNEL);
+       if (!fc)
+@@ -1454,6 +1465,10 @@ static int virtio_fs_get_tree(struct fs_
+       fc->delete_stale = true;
+       fc->auto_submounts = true;
++      /* Tell FUSE to split requests that exceed the virtqueue's size */
++      fc->max_pages_limit = min_t(unsigned int, fc->max_pages_limit,
++                                  virtqueue_size - FUSE_HEADER_OVERHEAD);
++
+       fsc->s_fs_info = fm;
+       sb = sget_fc(fsc, virtio_fs_test_super, virtio_fs_set_super);
+       fuse_mount_put(fm);