From: Miklos Szeredi Date: Thu, 2 Apr 2026 20:57:49 +0000 (+0200) Subject: fuse: simplify fuse_dev_ioctl_clone() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a63607723108f8c4003c040ca7fd704c6340814b;p=thirdparty%2Fkernel%2Flinux.git fuse: simplify fuse_dev_ioctl_clone() 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 --- diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index fd0b86ea56910..9feecbd2532ad 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -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; }