From: Miklos Szeredi Date: Tue, 17 Mar 2026 11:08:00 +0000 (+0100) Subject: fuse: move fuse_iqueue to fuse_chan X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b88fb2b92b24b3eee0ea87001c8d9fbf5ba54bb7;p=thirdparty%2Fkernel%2Flinux.git fuse: move fuse_iqueue to fuse_chan Move the 'fiq' member from fuse_conn to fuse_chan. Move iqueue related structure definitions and function declarations from "fuse_i.h" to "fuse_dev_i.h". Add a fuse_dev_chan_new() helper, that returns a fuse_chan initialized with the fuse_dev_fiq_ops. Add a fuse_chan_release() function, that calls fiq->ops->release(). Signed-off-by: Miklos Szeredi --- diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index e0616604d81ae..36215a6b3e3ae 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c @@ -505,7 +505,7 @@ static int cuse_channel_open(struct inode *inode, struct file *file) { struct fuse_dev *fud; struct cuse_conn *cc; - struct fuse_chan *fch __free(fuse_chan_free) = fuse_chan_new(); + struct fuse_chan *fch __free(fuse_chan_free) = fuse_dev_chan_new(); int rc; if (!fch) @@ -520,9 +520,7 @@ static int cuse_channel_open(struct inode *inode, struct file *file) * Limit the cuse channel to requests that can * be represented in file->f_cred->user_ns. */ - fuse_conn_init(&cc->fc, &cc->fm, file->f_cred->user_ns, - &fuse_dev_fiq_ops, NULL, no_free_ptr(fch)); - + fuse_conn_init(&cc->fc, &cc->fm, file->f_cred->user_ns, no_free_ptr(fch)); cc->fc.release = cuse_fc_release; fud = fuse_dev_alloc_install(&cc->fc); fuse_conn_put(&cc->fc); diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index c3d7eb4819743..0c0906a2372af 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -314,12 +314,32 @@ static void fuse_dev_queue_req(struct fuse_iqueue *fiq, struct fuse_req *req) } } -const struct fuse_iqueue_ops fuse_dev_fiq_ops = { +static const struct fuse_iqueue_ops fuse_dev_fiq_ops = { .send_forget = fuse_dev_queue_forget, .send_interrupt = fuse_dev_queue_interrupt, .send_req = fuse_dev_queue_req, }; -EXPORT_SYMBOL_GPL(fuse_dev_fiq_ops); + +void fuse_iqueue_init(struct fuse_iqueue *fiq, const struct fuse_iqueue_ops *ops, void *priv) +{ + spin_lock_init(&fiq->lock); + init_waitqueue_head(&fiq->waitq); + INIT_LIST_HEAD(&fiq->pending); + INIT_LIST_HEAD(&fiq->interrupts); + fiq->forget_list_tail = &fiq->forget_list_head; + fiq->connected = 1; + fiq->ops = ops; + fiq->priv = priv; +} +EXPORT_SYMBOL_GPL(fuse_iqueue_init); + +void fuse_chan_release(struct fuse_chan *fch) +{ + struct fuse_iqueue *fiq = &fch->iq; + + if (fiq->ops->release) + fiq->ops->release(fiq); +} void fuse_chan_free(struct fuse_chan *fch) { @@ -333,6 +353,18 @@ struct fuse_chan *fuse_chan_new(void) } EXPORT_SYMBOL_GPL(fuse_chan_new); +struct fuse_chan *fuse_dev_chan_new(void) +{ + struct fuse_chan *fch = fuse_chan_new(); + if (!fch) + return NULL; + + fuse_iqueue_init(&fch->iq, &fuse_dev_fiq_ops, NULL); + + return fch; +} +EXPORT_SYMBOL_GPL(fuse_dev_chan_new); + static void fuse_send_one(struct fuse_iqueue *fiq, struct fuse_req *req) { req->in.h.len = sizeof(struct fuse_in_header) + @@ -344,7 +376,7 @@ static void fuse_send_one(struct fuse_iqueue *fiq, struct fuse_req *req) void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, u64 nodeid, u64 nlookup) { - struct fuse_iqueue *fiq = &fc->iq; + struct fuse_iqueue *fiq = &fc->chan->iq; forget->forget_one.nodeid = nodeid; forget->forget_one.nlookup = nlookup; @@ -354,7 +386,7 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, static void flush_bg_queue(struct fuse_conn *fc) { - struct fuse_iqueue *fiq = &fc->iq; + struct fuse_iqueue *fiq = &fc->chan->iq; while (fc->active_background < fc->max_background && !list_empty(&fc->bg_queue)) { @@ -402,7 +434,7 @@ void fuse_request_end(struct fuse_req *req) { struct fuse_mount *fm = req->fm; struct fuse_conn *fc = fm->fc; - struct fuse_iqueue *fiq = &fc->iq; + struct fuse_iqueue *fiq = &fc->chan->iq; if (test_and_set_bit(FR_FINISHED, &req->flags)) goto put_request; @@ -439,7 +471,7 @@ EXPORT_SYMBOL_GPL(fuse_request_end); static int queue_interrupt(struct fuse_req *req) { - struct fuse_iqueue *fiq = &req->fm->fc->iq; + struct fuse_iqueue *fiq = &req->fm->fc->chan->iq; /* Check for we've sent request to interrupt this req */ if (unlikely(!test_bit(FR_INTERRUPTED, &req->flags))) @@ -471,7 +503,7 @@ bool fuse_remove_pending_req(struct fuse_req *req, spinlock_t *lock) static void request_wait_answer(struct fuse_req *req) { struct fuse_conn *fc = req->fm->fc; - struct fuse_iqueue *fiq = &fc->iq; + struct fuse_iqueue *fiq = &fc->chan->iq; int err; if (!fc->no_interrupt) { @@ -519,7 +551,7 @@ static void request_wait_answer(struct fuse_req *req) static void __fuse_request_send(struct fuse_req *req) { - struct fuse_iqueue *fiq = &req->fm->fc->iq; + struct fuse_iqueue *fiq = &req->fm->fc->chan->iq; BUG_ON(test_bit(FR_BACKGROUND, &req->flags)); @@ -638,7 +670,7 @@ ssize_t __fuse_simple_request(struct mnt_idmap *idmap, static bool fuse_request_queue_background_uring(struct fuse_conn *fc, struct fuse_req *req) { - struct fuse_iqueue *fiq = &fc->iq; + struct fuse_iqueue *fiq = &fc->chan->iq; req->in.h.len = sizeof(struct fuse_in_header) + fuse_len_args(req->args->in_numargs, @@ -717,7 +749,7 @@ static int fuse_simple_notify_reply(struct fuse_mount *fm, struct fuse_args *args, u64 unique) { struct fuse_req *req; - struct fuse_iqueue *fiq = &fm->fc->iq; + struct fuse_iqueue *fiq = &fm->fc->chan->iq; req = fuse_get_req(&invalid_mnt_idmap, fm, false); if (IS_ERR(req)) @@ -1331,7 +1363,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, { ssize_t err; struct fuse_conn *fc = fud->fc; - struct fuse_iqueue *fiq = &fc->iq; + struct fuse_iqueue *fiq = &fc->chan->iq; struct fuse_pqueue *fpq = &fud->pq; struct fuse_req *req; struct fuse_args *args; @@ -1915,7 +1947,7 @@ static void fuse_resend(struct fuse_conn *fc) { struct fuse_dev *fud; struct fuse_req *req, *next; - struct fuse_iqueue *fiq = &fc->iq; + struct fuse_iqueue *fiq = &fc->chan->iq; LIST_HEAD(to_queue); unsigned int i; @@ -2327,7 +2359,7 @@ static __poll_t fuse_dev_poll(struct file *file, poll_table *wait) if (IS_ERR(fud)) return EPOLLERR; - fiq = &fud->fc->iq; + fiq = &fud->fc->chan->iq; poll_wait(file, &fiq->waitq, wait); spin_lock(&fiq->lock); @@ -2388,7 +2420,7 @@ static void end_polls(struct fuse_conn *fc) */ void fuse_abort_conn(struct fuse_conn *fc) { - struct fuse_iqueue *fiq = &fc->iq; + struct fuse_iqueue *fiq = &fc->chan->iq; spin_lock(&fc->lock); if (fc->connected) { @@ -2496,7 +2528,7 @@ int fuse_dev_release(struct inode *inode, struct file *file) spin_unlock(&fc->lock); if (last) { - WARN_ON(fc->iq.fasync != NULL); + WARN_ON(fc->chan->iq.fasync != NULL); fuse_abort_conn(fc); } fuse_conn_put(fc); @@ -2514,7 +2546,7 @@ static int fuse_dev_fasync(int fd, struct file *file, int on) return PTR_ERR(fud); /* No locking - fasync_helper does its own locking */ - return fasync_helper(fd, file, on, &fud->fc->iq.fasync); + return fasync_helper(fd, file, on, &fud->fc->chan->iq.fasync); } static long fuse_dev_ioctl_clone(struct file *file, __u32 __user *argp) diff --git a/fs/fuse/dev.h b/fs/fuse/dev.h index 70e4a75e6942c..d5ccfae80115f 100644 --- a/fs/fuse/dev.h +++ b/fs/fuse/dev.h @@ -9,6 +9,8 @@ struct fuse_conn; struct fuse_chan; struct fuse_chan *fuse_chan_new(void); +struct fuse_chan *fuse_dev_chan_new(void); +void fuse_chan_release(struct fuse_chan *fch); void fuse_chan_free(struct fuse_chan *fch); DEFINE_FREE(fuse_chan_free, struct fuse_chan *, if (_T) fuse_chan_free(_T)) diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c index 8fe788b8ecbaa..02b138727c9bb 100644 --- a/fs/fuse/dev_uring.c +++ b/fs/fuse/dev_uring.c @@ -1006,7 +1006,7 @@ static int fuse_uring_do_register(struct fuse_ring_ent *ent, struct fuse_ring_queue *queue = ent->queue; struct fuse_ring *ring = queue->ring; struct fuse_conn *fc = ring->fc; - struct fuse_iqueue *fiq = &fc->iq; + struct fuse_iqueue *fiq = &fc->chan->iq; spin_lock(&fc->lock); /* abort teardown path is running or has run */ diff --git a/fs/fuse/dev_uring_i.h b/fs/fuse/dev_uring_i.h index 054ad4fdd7491..e60057b5dbf83 100644 --- a/fs/fuse/dev_uring_i.h +++ b/fs/fuse/dev_uring_i.h @@ -8,6 +8,7 @@ #define _FS_FUSE_DEV_URING_I_H #include "fuse_i.h" +#include "fuse_dev_i.h" #ifdef CONFIG_FUSE_IO_URING diff --git a/fs/fuse/fuse_dev_i.h b/fs/fuse/fuse_dev_i.h index 256d973aa6c01..7c607a49b1bed 100644 --- a/fs/fuse/fuse_dev_i.h +++ b/fs/fuse/fuse_dev_i.h @@ -21,8 +21,75 @@ struct fuse_req; struct fuse_iqueue; struct fuse_forget_link; +/** + * Input queue callbacks + * + * Input queue signalling is device-specific. For example, the /dev/fuse file + * uses fiq->waitq and fasync to wake processes that are waiting on queue + * readiness. These callbacks allow other device types to respond to input + * queue activity. + */ +struct fuse_iqueue_ops { + /** + * Send one forget + */ + void (*send_forget)(struct fuse_iqueue *fiq, struct fuse_forget_link *link); + + /** + * Send interrupt for request + */ + void (*send_interrupt)(struct fuse_iqueue *fiq, struct fuse_req *req); + + /** + * Send one request + */ + void (*send_req)(struct fuse_iqueue *fiq, struct fuse_req *req); + + /** + * Clean up when fuse_iqueue is destroyed + */ + void (*release)(struct fuse_iqueue *fiq); +}; + +struct fuse_iqueue { + /** Connection established */ + unsigned connected; + + /** Lock protecting accesses to members of this structure */ + spinlock_t lock; + + /** Readers of the connection are waiting on this */ + wait_queue_head_t waitq; + + /** The next unique request id */ + u64 reqctr; + + /** The list of pending requests */ + struct list_head pending; + + /** Pending interrupts */ + struct list_head interrupts; + + /** Queue of pending forgets */ + struct fuse_forget_link forget_list_head; + struct fuse_forget_link *forget_list_tail; + + /** Batching of FORGET requests (positive indicates FORGET batch) */ + int forget_batch; + + /** O_ASYNC requests */ + struct fasync_struct *fasync; + + /** Device-specific callbacks */ + const struct fuse_iqueue_ops *ops; + + /** Device-specific state */ + void *priv; +}; + struct fuse_chan { - /* will move stuff from struct fuse_conn */ + /** Input queue */ + struct fuse_iqueue iq; }; struct fuse_copy_state { @@ -75,6 +142,8 @@ static inline struct fuse_dev *__fuse_get_dev(struct file *file) return fud; } +void fuse_iqueue_init(struct fuse_iqueue *fiq, const struct fuse_iqueue_ops *ops, void *priv); + struct fuse_dev *fuse_get_dev(struct file *file); unsigned int fuse_req_hash(u64 unique); @@ -98,5 +167,15 @@ bool fuse_remove_pending_req(struct fuse_req *req, spinlock_t *lock); bool fuse_request_expired(struct fuse_conn *fc, struct list_head *list); +/** + * Assign a unique id to a fuse request + */ +void fuse_request_assign_unique(struct fuse_iqueue *fiq, struct fuse_req *req); + +/** + * Get the next unique ID for a request + */ +u64 fuse_get_unique(struct fuse_iqueue *fiq); + #endif diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index deaffe2452844..29126f5cb66cf 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -469,77 +469,6 @@ struct fuse_req { unsigned long create_time; }; -struct fuse_iqueue; - -/** - * Input queue callbacks - * - * Input queue signalling is device-specific. For example, the /dev/fuse file - * uses fiq->waitq and fasync to wake processes that are waiting on queue - * readiness. These callbacks allow other device types to respond to input - * queue activity. - */ -struct fuse_iqueue_ops { - /** - * Send one forget - */ - void (*send_forget)(struct fuse_iqueue *fiq, struct fuse_forget_link *link); - - /** - * Send interrupt for request - */ - void (*send_interrupt)(struct fuse_iqueue *fiq, struct fuse_req *req); - - /** - * Send one request - */ - void (*send_req)(struct fuse_iqueue *fiq, struct fuse_req *req); - - /** - * Clean up when fuse_iqueue is destroyed - */ - void (*release)(struct fuse_iqueue *fiq); -}; - -/** /dev/fuse input queue operations */ -extern const struct fuse_iqueue_ops fuse_dev_fiq_ops; - -struct fuse_iqueue { - /** Connection established */ - unsigned connected; - - /** Lock protecting accesses to members of this structure */ - spinlock_t lock; - - /** Readers of the connection are waiting on this */ - wait_queue_head_t waitq; - - /** The next unique request id */ - u64 reqctr; - - /** The list of pending requests */ - struct list_head pending; - - /** Pending interrupts */ - struct list_head interrupts; - - /** Queue of pending forgets */ - struct fuse_forget_link forget_list_head; - struct fuse_forget_link *forget_list_tail; - - /** Batching of FORGET requests (positive indicates FORGET batch) */ - int forget_batch; - - /** O_ASYNC requests */ - struct fasync_struct *fasync; - - /** Device-specific callbacks */ - const struct fuse_iqueue_ops *ops; - - /** Device-specific state */ - void *priv; -}; - #define FUSE_PQ_HASH_BITS 8 #define FUSE_PQ_HASH_SIZE (1 << FUSE_PQ_HASH_BITS) @@ -665,9 +594,6 @@ struct fuse_conn { /** Constrain ->max_pages to this value during feature negotiation */ unsigned int max_pages_limit; - /** Input queue */ - struct fuse_iqueue iq; - /* transport layer object */ struct fuse_chan *chan; @@ -1259,11 +1185,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); -/** - * Assign a unique id to a fuse request - */ -void fuse_request_assign_unique(struct fuse_iqueue *fiq, struct fuse_req *req); - /** * End a finished request */ @@ -1315,9 +1236,7 @@ void fuse_pqueue_init(struct fuse_pqueue *fpq); * Initialize fuse_conn */ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm, - struct user_namespace *user_ns, - const struct fuse_iqueue_ops *fiq_ops, void *fiq_priv, - struct fuse_chan *fch); + struct user_namespace *user_ns, struct fuse_chan *fch); /** * Release reference to fuse_conn @@ -1484,10 +1403,6 @@ int fuse_readdir(struct file *file, struct dir_context *ctx); */ unsigned int fuse_len_args(unsigned int numargs, struct fuse_arg *args); -/** - * Get the next unique ID for a request - */ -u64 fuse_get_unique(struct fuse_iqueue *fiq); void fuse_free_conn(struct fuse_conn *fc); /* dax.c */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 65f11108c81a1..2ee9320964faa 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -969,21 +969,6 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root) return 0; } -static void fuse_iqueue_init(struct fuse_iqueue *fiq, - const struct fuse_iqueue_ops *ops, - void *priv) -{ - memset(fiq, 0, sizeof(struct fuse_iqueue)); - spin_lock_init(&fiq->lock); - init_waitqueue_head(&fiq->waitq); - INIT_LIST_HEAD(&fiq->pending); - INIT_LIST_HEAD(&fiq->interrupts); - fiq->forget_list_tail = &fiq->forget_list_head; - fiq->connected = 1; - fiq->ops = ops; - fiq->priv = priv; -} - void fuse_pqueue_init(struct fuse_pqueue *fpq) { unsigned int i; @@ -996,8 +981,7 @@ void fuse_pqueue_init(struct fuse_pqueue *fpq) } void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm, - struct user_namespace *user_ns, - const struct fuse_iqueue_ops *fiq_ops, void *fiq_priv, struct fuse_chan *fch) + struct user_namespace *user_ns, struct fuse_chan *fch) { memset(fc, 0, sizeof(*fc)); spin_lock_init(&fc->lock); @@ -1007,7 +991,6 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm, atomic_set(&fc->epoch, 1); INIT_WORK(&fc->epoch_work, fuse_epoch_work); init_waitqueue_head(&fc->blocked_waitq); - fuse_iqueue_init(&fc->iq, fiq_ops, fiq_priv); INIT_LIST_HEAD(&fc->bg_queue); INIT_LIST_HEAD(&fc->entry); INIT_LIST_HEAD(&fc->devices); @@ -1052,7 +1035,6 @@ static void delayed_release(struct rcu_head *p) void fuse_conn_put(struct fuse_conn *fc) { - struct fuse_iqueue *fiq = &fc->iq; struct fuse_sync_bucket *bucket; if (!refcount_dec_and_test(&fc->count)) @@ -1063,8 +1045,7 @@ void fuse_conn_put(struct fuse_conn *fc) if (fc->timeout.req_timeout) cancel_delayed_work_sync(&fc->timeout.work); cancel_work_sync(&fc->epoch_work); - if (fiq->ops->release) - fiq->ops->release(fiq); + fuse_chan_release(fc->chan); put_pid_ns(fc->pid_ns); bucket = rcu_dereference_protected(fc->curr_bucket, 1); if (bucket) { @@ -1985,7 +1966,7 @@ static int fuse_get_tree(struct fs_context *fsc) struct fuse_conn *fc; struct fuse_mount *fm; struct super_block *sb; - struct fuse_chan *fch __free(fuse_chan_free) = fuse_chan_new(); + struct fuse_chan *fch __free(fuse_chan_free) = fuse_dev_chan_new(); int err; if (!fch) @@ -2001,7 +1982,7 @@ static int fuse_get_tree(struct fs_context *fsc) return -ENOMEM; } - fuse_conn_init(fc, fm, fsc->user_ns, &fuse_dev_fiq_ops, NULL, no_free_ptr(fch)); + fuse_conn_init(fc, fm, fsc->user_ns, no_free_ptr(fch)); fc->release = fuse_free_conn; fsc->s_fs_info = fm; diff --git a/fs/fuse/req_timeout.c b/fs/fuse/req_timeout.c index 64d9b503e6c58..5357a2d63b3f0 100644 --- a/fs/fuse/req_timeout.c +++ b/fs/fuse/req_timeout.c @@ -69,7 +69,7 @@ static void fuse_check_timeout(struct work_struct *work) struct delayed_work *dwork = to_delayed_work(work); struct fuse_conn *fc = container_of(dwork, struct fuse_conn, timeout.work); - struct fuse_iqueue *fiq = &fc->iq; + struct fuse_iqueue *fiq = &fc->chan->iq; struct fuse_dev *fud; struct fuse_pqueue *fpq; bool expired = false; diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index f6d41b760210b..d688a2a95753e 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -1563,7 +1563,7 @@ static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc) { struct fuse_mount *fm = get_fuse_mount_super(sb); struct fuse_conn *fc = fm->fc; - struct virtio_fs *fs = fc->iq.priv; + struct virtio_fs *fs = fc->chan->iq.priv; struct fuse_fs_context *ctx = fsc->fs_private; unsigned int i; int err; @@ -1626,7 +1626,7 @@ err: static void virtio_fs_conn_destroy(struct fuse_mount *fm) { struct fuse_conn *fc = fm->fc; - struct virtio_fs *vfs = fc->iq.priv; + struct virtio_fs *vfs = fc->chan->iq.priv; struct virtio_fs_vq *fsvq = &vfs->vqs[VQ_HIPRIO]; /* Stop dax worker. Soon evict_inodes() will be called which @@ -1674,7 +1674,7 @@ static int virtio_fs_test_super(struct super_block *sb, struct fuse_mount *fsc_fm = fsc->s_fs_info; struct fuse_mount *sb_fm = get_fuse_mount_super(sb); - return fsc_fm->fc->iq.priv == sb_fm->fc->iq.priv; + return fsc_fm->fc->chan->iq.priv == sb_fm->fc->chan->iq.priv; } static int virtio_fs_get_tree(struct fs_context *fsc) @@ -1694,7 +1694,7 @@ static int virtio_fs_get_tree(struct fs_context *fsc) return invalf(fsc, "No source specified"); /* 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() + * in chan->iq->priv. Once fuse_conn is going away, it calls ->put() * to drop the reference to this object. */ fs = virtio_fs_find_instance(fsc->source); @@ -1716,7 +1716,8 @@ static int virtio_fs_get_tree(struct fs_context *fsc) if (!fm) goto out_err; - fuse_conn_init(fc, fm, fsc->user_ns, &virtio_fs_fiq_ops, fs, no_free_ptr(fch)); + fuse_iqueue_init(&fch->iq, &virtio_fs_fiq_ops, fs); + fuse_conn_init(fc, fm, fsc->user_ns, no_free_ptr(fch)); fc->release = fuse_free_conn; fc->delete_stale = true;