From: Miklos Szeredi Date: Tue, 24 Mar 2026 15:12:28 +0000 (+0100) Subject: fuse: abort related layering cleanup X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4eeb5e6cb0fd89b343fcf755ae3aad76fdb5b2c2;p=thirdparty%2Fkernel%2Flinux.git fuse: abort related layering cleanup - rename fuse_abort_conn() to fuse_chan_abort(), pass fuse_chan pointer instead of fuse_conn - pass an abort_with_err argument that tells fuse_dev_(read|write) to return with ECONNABORTED instead of ENODEV - move fc->aborted to fch->abort_with_err - rename fuse_wait_aborted() to fuse_chan_wait_aborted() Signed-off-by: Miklos Szeredi --- diff --git a/fs/fuse/control.c b/fs/fuse/control.c index e6f513eb7d4a3..925a154884996 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -38,9 +38,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf, { struct fuse_conn *fc = fuse_ctl_file_conn_get(file); if (fc) { - if (fc->abort_err) - fc->aborted = true; - fuse_abort_conn(fc); + fuse_chan_abort(fc->chan, fc->abort_err); fuse_conn_put(fc); } return count; diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index 950c070ab3e96..321ba7af0ec51 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c @@ -426,7 +426,7 @@ err_unlock: err_region: unregister_chrdev_region(devt, 1); err: - fuse_abort_conn(fc); + fuse_chan_abort(fc->chan, false); goto out; } @@ -596,7 +596,7 @@ static ssize_t cuse_class_abort_store(struct device *dev, { struct cuse_conn *cc = dev_get_drvdata(dev); - fuse_abort_conn(&cc->fc); + fuse_chan_abort(cc->fc.chan, false); return count; } static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store); diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 586d6fe46e317..c4a6ee9482829 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -90,7 +90,7 @@ static void fuse_drop_waiting(struct fuse_conn *fc) { /* * lockess check of fc->chan->connected is okay, because atomic_dec_and_test() - * provides a memory barrier matched with the one in fuse_wait_aborted() + * provides a memory barrier matched with the one in fuse_chan_wait_aborted() * to ensure no wake-up is missed. */ if (atomic_dec_and_test(&fc->chan->num_waiting) && @@ -570,17 +570,17 @@ void fuse_chan_queue_forget(struct fuse_chan *fch, struct fuse_forget_link *forg fiq->ops->send_forget(fiq, forget); } -static void flush_bg_queue(struct fuse_conn *fc) +static void flush_bg_queue(struct fuse_chan *fch) { - struct fuse_iqueue *fiq = &fc->chan->iq; + struct fuse_iqueue *fiq = &fch->iq; - while (fc->chan->active_background < fc->chan->max_background && - !list_empty(&fc->chan->bg_queue)) { + while (fch->active_background < fch->max_background && + !list_empty(&fch->bg_queue)) { struct fuse_req *req; - req = list_first_entry(&fc->chan->bg_queue, struct fuse_req, list); + req = list_first_entry(&fch->bg_queue, struct fuse_req, list); list_del(&req->list); - fc->chan->active_background++; + fch->active_background++; fuse_send_one(fiq, req); } } @@ -641,7 +641,7 @@ void fuse_request_end(struct fuse_req *req) if (test_bit(FR_BACKGROUND, &req->flags)) { spin_lock(&fc->chan->bg_lock); fuse_request_bg_finish(fc->chan, req); - flush_bg_queue(fc); + flush_bg_queue(fc->chan); spin_unlock(&fc->chan->bg_lock); } else { /* Wake up waiter sleeping in request_wait_answer() */ @@ -716,7 +716,7 @@ static void request_wait_answer(struct fuse_req *req) return; if (req->args->abort_on_kill) { - fuse_abort_conn(fc); + fuse_chan_abort(fc->chan, false); return; } @@ -894,7 +894,7 @@ static int fuse_request_queue_background(struct fuse_req *req) if (fc->chan->num_background == fc->chan->max_background) fc->chan->blocked = 1; list_add_tail(&req->list, &fc->chan->bg_queue); - flush_bg_queue(fc); + flush_bg_queue(fc->chan); queued = true; } spin_unlock(&fc->chan->bg_lock); @@ -1590,7 +1590,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, } if (!fiq->connected) { - err = fc->aborted ? -ECONNABORTED : -ENODEV; + err = fc->chan->abort_with_err ? -ECONNABORTED : -ENODEV; goto err_unlock; } @@ -1628,7 +1628,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, spin_lock(&fpq->lock); /* * Must not put request on fpq->io queue after having been shut down by - * fuse_abort_conn() + * fuse_chan_abort() */ if (!fpq->connected) { req->out.h.error = err = -ECONNABORTED; @@ -1646,7 +1646,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, spin_lock(&fpq->lock); clear_bit(FR_LOCKED, &req->flags); if (!fpq->connected) { - err = fc->aborted ? -ECONNABORTED : -ENODEV; + err = fc->chan->abort_with_err ? -ECONNABORTED : -ENODEV; goto out_end; } if (err) { @@ -2606,27 +2606,29 @@ static void end_polls(struct fuse_conn *fc) * is OK, the request will in that case be removed from the list before we touch * it. */ -void fuse_abort_conn(struct fuse_conn *fc) +void fuse_chan_abort(struct fuse_chan *fch, bool abort_with_err) { - struct fuse_iqueue *fiq = &fc->chan->iq; + struct fuse_iqueue *fiq = &fch->iq; - spin_lock(&fc->chan->lock); - if (fc->chan->connected) { + fch->abort_with_err = abort_with_err; + + spin_lock(&fch->lock); + if (fch->connected) { struct fuse_dev *fud; struct fuse_req *req, *next; LIST_HEAD(to_end); unsigned int i; - if (fc->chan->timeout.req_timeout) - cancel_delayed_work(&fc->chan->timeout.work); + if (fch->timeout.req_timeout) + cancel_delayed_work(&fch->timeout.work); - /* Background queuing checks fc->chan->connected under bg_lock */ - spin_lock(&fc->chan->bg_lock); - fc->chan->connected = 0; - spin_unlock(&fc->chan->bg_lock); + /* Background queuing checks fch->connected under bg_lock */ + spin_lock(&fch->bg_lock); + fch->connected = 0; + spin_unlock(&fch->bg_lock); - fuse_chan_set_initialized(fc->chan); - list_for_each_entry(fud, &fc->chan->devices, entry) { + fuse_chan_set_initialized(fch); + list_for_each_entry(fud, &fch->devices, entry) { struct fuse_pqueue *fpq = &fud->pq; spin_lock(&fpq->lock); @@ -2647,11 +2649,11 @@ void fuse_abort_conn(struct fuse_conn *fc) &to_end); spin_unlock(&fpq->lock); } - spin_lock(&fc->chan->bg_lock); - fc->chan->blocked = 0; - fc->chan->max_background = UINT_MAX; - flush_bg_queue(fc); - spin_unlock(&fc->chan->bg_lock); + spin_lock(&fch->bg_lock); + fch->blocked = 0; + fch->max_background = UINT_MAX; + flush_bg_queue(fch); + spin_unlock(&fch->bg_lock); spin_lock(&fiq->lock); fiq->connected = 0; @@ -2663,30 +2665,30 @@ void fuse_abort_conn(struct fuse_conn *fc) wake_up_all(&fiq->waitq); spin_unlock(&fiq->lock); kill_fasync(&fiq->fasync, SIGIO, POLL_IN); - end_polls(fc); - wake_up_all(&fc->chan->blocked_waitq); - spin_unlock(&fc->chan->lock); + end_polls(fch->conn); + wake_up_all(&fch->blocked_waitq); + spin_unlock(&fch->lock); fuse_dev_end_requests(&to_end); /* - * fc->chan->lock must not be taken to avoid conflicts with io-uring + * fch->lock must not be taken to avoid conflicts with io-uring * locks */ - fuse_uring_abort(fc->chan); + fuse_uring_abort(fch); } else { - spin_unlock(&fc->chan->lock); + spin_unlock(&fch->lock); } } -EXPORT_SYMBOL_GPL(fuse_abort_conn); +EXPORT_SYMBOL_GPL(fuse_chan_abort); -void fuse_wait_aborted(struct fuse_conn *fc) +void fuse_chan_wait_aborted(struct fuse_chan *fch) { /* matches implicit memory barrier in fuse_drop_waiting() */ smp_mb(); - wait_event(fc->chan->blocked_waitq, fuse_chan_num_waiting(fc->chan) == 0); + wait_event(fch->blocked_waitq, fuse_chan_num_waiting(fch) == 0); - fuse_uring_wait_stopped_queues(fc->chan); + fuse_uring_wait_stopped_queues(fch); } int fuse_dev_release(struct inode *inode, struct file *file) @@ -2717,7 +2719,7 @@ int fuse_dev_release(struct inode *inode, struct file *file) if (last) { WARN_ON(fc->chan->iq.fasync != NULL); - fuse_abort_conn(fc); + fuse_chan_abort(fc->chan, false); } fuse_conn_put(fc); } diff --git a/fs/fuse/dev.h b/fs/fuse/dev.h index efdaf0bf6f0f3..a0c1212573d6c 100644 --- a/fs/fuse/dev.h +++ b/fs/fuse/dev.h @@ -42,7 +42,8 @@ struct fuse_dev *fuse_dev_grab(struct file *file); void fuse_init_server_timeout(struct fuse_chan *fch, unsigned int timeout); /* Abort all requests */ -void fuse_abort_conn(struct fuse_conn *fc); +void fuse_chan_abort(struct fuse_chan *fch, bool abort_with_err); +void fuse_chan_wait_aborted(struct fuse_chan *fch); #ifdef CONFIG_FUSE_IO_URING bool fuse_uring_enabled(void); diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c index 296da4ff233c7..71608a5beead9 100644 --- a/fs/fuse/dev_uring.c +++ b/fs/fuse/dev_uring.c @@ -1189,7 +1189,7 @@ int fuse_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) return -EOPNOTSUPP; } - if (fc->aborted) + if (fc->chan->abort_with_err) return -ECONNABORTED; if (!fc->chan->connected) return -ENOTCONN; diff --git a/fs/fuse/fuse_dev_i.h b/fs/fuse/fuse_dev_i.h index a0eb9cac9b2f4..34cf0ac411b78 100644 --- a/fs/fuse/fuse_dev_i.h +++ b/fs/fuse/fuse_dev_i.h @@ -238,6 +238,9 @@ struct fuse_chan { /* Use io_uring for communication */ unsigned int io_uring; + /** Connection aborted via sysfs, respond with ECONNABORTED on device I/O */ + bool abort_with_err; + #ifdef CONFIG_FUSE_IO_URING /** uring connection information*/ struct fuse_ring *ring; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index af8e05a403e54..b8655c3b48e25 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -483,9 +483,6 @@ struct fuse_conn { /** Number of background requests at which congestion starts */ unsigned congestion_threshold; - /** Connection aborted via sysfs */ - bool aborted; - /** Connection failed (version mismatch). Cannot race with setting other bitfields since it is only set once in INIT reply, before any other request, and never cleared */ @@ -996,8 +993,6 @@ static inline ssize_t fuse_simple_idmap_request(struct mnt_idmap *idmap, int fuse_simple_background(struct fuse_mount *fm, struct fuse_args *args, gfp_t gfp_flags); -void fuse_wait_aborted(struct fuse_conn *fc); - void fuse_dentry_tree_init(void); void fuse_dentry_tree_cleanup(void); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 5695a7dca0511..66e37af3a6dd4 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -612,7 +612,7 @@ static void fuse_umount_begin(struct super_block *sb) if (fc->no_force_umount) return; - fuse_abort_conn(fc); + fuse_chan_abort(fc->chan, false); // Only retire block-device-based superblocks. if (sb->s_bdev != NULL) @@ -1952,8 +1952,8 @@ void fuse_conn_destroy(struct fuse_mount *fm) if (fc->destroy) fuse_send_destroy(fm); - fuse_abort_conn(fc); - fuse_wait_aborted(fc); + fuse_chan_abort(fc->chan, false); + fuse_chan_wait_aborted(fc->chan); if (!list_empty(&fc->entry)) { mutex_lock(&fuse_mutex); diff --git a/fs/fuse/req_timeout.c b/fs/fuse/req_timeout.c index 9c48789b941a9..6cc6fc4913437 100644 --- a/fs/fuse/req_timeout.c +++ b/fs/fuse/req_timeout.c @@ -79,13 +79,13 @@ static void fuse_check_timeout(struct work_struct *work) expired = fuse_request_expired(fch, &fiq->pending); spin_unlock(&fiq->lock); if (expired) - goto abort_conn; + goto chan_abort; spin_lock(&fch->bg_lock); expired = fuse_request_expired(fch, &fch->bg_queue); spin_unlock(&fch->bg_lock); if (expired) - goto abort_conn; + goto chan_abort; spin_lock(&fch->lock); if (!fch->connected) { @@ -99,7 +99,7 @@ static void fuse_check_timeout(struct work_struct *work) fuse_fpq_processing_expired(fch, fpq->processing)) { spin_unlock(&fpq->lock); spin_unlock(&fch->lock); - goto abort_conn; + goto chan_abort; } spin_unlock(&fpq->lock); @@ -107,15 +107,15 @@ static void fuse_check_timeout(struct work_struct *work) spin_unlock(&fch->lock); if (fuse_uring_request_expired(fch)) - goto abort_conn; + goto chan_abort; out: queue_delayed_work(system_percpu_wq, &fch->timeout.work, fuse_timeout_timer_freq); return; -abort_conn: - fuse_abort_conn(fch->conn); +chan_abort: + fuse_chan_abort(fch, false); } static void set_request_timeout(struct fuse_chan *fch, unsigned int timeout)