]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
fuse: simplify fuse_dev_ioctl_clone()
authorMiklos Szeredi <mszeredi@redhat.com>
Thu, 2 Apr 2026 20:57:49 +0000 (22:57 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Mon, 15 Jun 2026 12:06:18 +0000 (14:06 +0200)
Don't need to check if the new device file is already initialized, since
fuse_dev_install_with_pq() will do that anyway.

Make fuse_dev_install_with_pq() return a boolean value indicating success so
that fuse_dev_ioctl_clone() can return an error in case of failure.

Move aborting the connection (setting fc->connected to zero) to
fuse_dev_install(), because it is not needed when the clone ioctl fails.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/dev.c

index fd0b86ea5691083b78d269446562854bf1860726..9feecbd2532ad5764d241641defdee536c9c8c7a 100644 (file)
@@ -454,12 +454,15 @@ struct fuse_dev *fuse_dev_alloc(void)
 }
 EXPORT_SYMBOL_GPL(fuse_dev_alloc);
 
-static void fuse_dev_install_with_pq(struct fuse_dev *fud, struct fuse_chan *fch,
+/*
+ * Installs @fch into @fud, return true on success.  "Consumes" @pq in either case.
+ */
+static bool fuse_dev_install_with_pq(struct fuse_dev *fud, struct fuse_chan *fch,
                                     struct list_head *pq)
 {
        struct fuse_chan *old_fch;
 
-       spin_lock(&fch->lock);
+       guard(spinlock)(&fch->lock);
        /*
         * Pairs with:
         *  - xchg() in fuse_dev_release()
@@ -472,18 +475,17 @@ static void fuse_dev_install_with_pq(struct fuse_dev *fud, struct fuse_chan *fch
                 *  - it was already set to a different fc
                 *  - it was set to disconneted
                 */
-               fch->connected = 0;
                kfree(pq);
-       } else {
-               if (pq) {
-                       WARN_ON(fud->pq.processing);
-                       fud->pq.processing = pq;
-               }
-               list_add_tail(&fud->entry, &fch->devices);
-               fuse_conn_get(fch->conn);
-               wake_up_all(&fuse_dev_waitq);
+               return false;
        }
-       spin_unlock(&fch->lock);
+       if (pq) {
+               WARN_ON(fud->pq.processing);
+               fud->pq.processing = pq;
+       }
+       list_add_tail(&fud->entry, &fch->devices);
+       fuse_conn_get(fch->conn);
+       wake_up_all(&fuse_dev_waitq);
+       return true;
 }
 
 void fuse_dev_install(struct fuse_dev *fud, struct fuse_chan *fch)
@@ -491,7 +493,10 @@ void fuse_dev_install(struct fuse_dev *fud, struct fuse_chan *fch)
        struct list_head *pq = fch->pq_prealloc;
 
        fch->pq_prealloc = NULL;
-       fuse_dev_install_with_pq(fud, fch, pq);
+       if (!fuse_dev_install_with_pq(fud, fch, pq)) {
+               /* Channel is not usable without a dev */
+               fuse_chan_abort(fch, false);
+       }
 }
 EXPORT_SYMBOL_GPL(fuse_dev_install);
 
@@ -2297,15 +2302,13 @@ static long fuse_dev_ioctl_clone(struct file *file, __u32 __user *argp)
        if (IS_ERR(fud))
                return PTR_ERR(fud);
 
-       new_fud = fuse_file_to_fud(file);
-       if (fuse_dev_chan_get(new_fud))
-               return -EINVAL;
-
        pq = fuse_pqueue_alloc();
        if (!pq)
                return -ENOMEM;
 
-       fuse_dev_install_with_pq(new_fud, fud->chan, pq);
+       new_fud = fuse_file_to_fud(file);
+       if (!fuse_dev_install_with_pq(new_fud, fud->chan, pq))
+               return -EINVAL;
 
        return 0;
 }