From: Miklos Szeredi Date: Thu, 19 Mar 2026 14:40:10 +0000 (+0100) Subject: fuse: don't access transport layer structs directly from the fs layer X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b6d83d4e3eff4532c4c93d958dec78099ea37f5a;p=thirdparty%2Flinux.git fuse: don't access transport layer structs directly from the fs layer Add helpers (get and set functions mainly) that cleanly separate the layers. Remove #include "fuse_dev_i.h" from: - inode.c - file.c - control.c Remove #include "dev_uring_i.h" from inode.c. [Li Wang: drop redundant initializer in process_init_limits()] Signed-off-by: Miklos Szeredi --- diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 228e1e7114b7a..e6f513eb7d4a3 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -7,7 +7,7 @@ */ #include "fuse_i.h" -#include "fuse_dev_i.h" +#include "dev.h" #include #include @@ -58,7 +58,7 @@ static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf, if (!fc) return 0; - value = atomic_read(&fc->chan->num_waiting); + value = fuse_chan_num_waiting(fc->chan); file->private_data = (void *)value; fuse_conn_put(fc); } @@ -112,7 +112,7 @@ static ssize_t fuse_conn_max_background_read(struct file *file, if (!fc) return 0; - val = READ_ONCE(fc->chan->max_background); + val = fuse_chan_max_background(fc->chan); fuse_conn_put(fc); return fuse_conn_limit_read(file, buf, len, ppos, val); @@ -130,12 +130,7 @@ static ssize_t fuse_conn_max_background_write(struct file *file, if (ret > 0) { struct fuse_conn *fc = fuse_ctl_file_conn_get(file); if (fc) { - spin_lock(&fc->chan->bg_lock); - fc->chan->max_background = val; - fc->chan->blocked = fc->chan->num_background >= fc->chan->max_background; - if (!fc->chan->blocked) - wake_up(&fc->chan->blocked_waitq); - spin_unlock(&fc->chan->bg_lock); + fuse_chan_max_background_set(fc->chan, val); fuse_conn_put(fc); } } diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 19b8cee3cff37..df851c2383e93 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -70,11 +70,12 @@ static void __fuse_put_request(struct fuse_req *req) refcount_dec(&req->count); } -void fuse_set_initialized(struct fuse_conn *fc) +void fuse_chan_set_initialized(struct fuse_chan *fch) { /* Make sure stores before this are seen on another CPU */ smp_wmb(); - fc->chan->initialized = 1; + fch->initialized = 1; + wake_up_all(&fch->blocked_waitq); } static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background) @@ -119,7 +120,7 @@ static struct fuse_req *fuse_get_req(struct mnt_idmap *idmap, (TASK_KILLABLE | TASK_FREEZABLE))) goto out; } - /* Matches smp_wmb() in fuse_set_initialized() */ + /* Matches smp_wmb() in fuse_chan_set_initialized() */ smp_rmb(); err = -ENOTCONN; @@ -339,6 +340,9 @@ void fuse_chan_release(struct fuse_chan *fch) if (fiq->ops->release) fiq->ops->release(fiq); + + if (fch->timeout.req_timeout) + cancel_delayed_work_sync(&fch->timeout.work); } void fuse_chan_free(struct fuse_chan *fch) @@ -382,6 +386,41 @@ struct fuse_chan *fuse_dev_chan_new(void) } EXPORT_SYMBOL_GPL(fuse_dev_chan_new); +unsigned int fuse_chan_num_background(struct fuse_chan *fch) +{ + return fch->num_background; +} + +unsigned int fuse_chan_max_background(struct fuse_chan *fch) +{ + return READ_ONCE(fch->max_background); +} + +void fuse_chan_max_background_set(struct fuse_chan *fch, unsigned int val) +{ + spin_lock(&fch->bg_lock); + fch->max_background = val; + fch->blocked = fch->num_background >= fch->max_background; + if (!fch->blocked) + wake_up(&fch->blocked_waitq); + spin_unlock(&fch->bg_lock); +} + +unsigned int fuse_chan_num_waiting(struct fuse_chan *fch) +{ + return atomic_read(&fch->num_waiting); +} + +void fuse_chan_set_fc(struct fuse_chan *fch, struct fuse_conn *fc) +{ + fch->conn = fc; +} + +void fuse_chan_io_uring_enable(struct fuse_chan *fch) +{ + fch->io_uring = 1; +} + void fuse_pqueue_init(struct fuse_pqueue *fpq) { unsigned int i; @@ -476,6 +515,34 @@ void fuse_dev_put(struct fuse_dev *fud) } EXPORT_SYMBOL_GPL(fuse_dev_put); +bool fuse_dev_is_installed(struct fuse_dev *fud) +{ + struct fuse_conn *fc = fuse_dev_fc_get(fud); + + return fc != NULL && fc != FUSE_DEV_FC_DISCONNECTED; +} + +/* + * Checks if @fc matches the one installed in @fud + */ +bool fuse_dev_verify(struct fuse_dev *fud, struct fuse_conn *fc) +{ + return fuse_dev_fc_get(fud) == fc; +} + +bool fuse_dev_is_sync_init(struct fuse_dev *fud) +{ + return fud->sync_init; +} + +struct fuse_dev *fuse_dev_grab(struct file *file) +{ + struct fuse_dev *fud = fuse_file_to_fud(file); + + refcount_inc(&fud->ref); + return fud; +} + static void fuse_send_one(struct fuse_iqueue *fiq, struct fuse_req *req) { req->in.h.len = sizeof(struct fuse_in_header) + @@ -2550,7 +2617,7 @@ void fuse_abort_conn(struct fuse_conn *fc) fc->chan->connected = 0; spin_unlock(&fc->chan->bg_lock); - fuse_set_initialized(fc); + fuse_chan_set_initialized(fc->chan); list_for_each_entry(fud, &fc->chan->devices, entry) { struct fuse_pqueue *fpq = &fud->pq; @@ -2609,7 +2676,7 @@ void fuse_wait_aborted(struct fuse_conn *fc) { /* matches implicit memory barrier in fuse_drop_waiting() */ smp_mb(); - wait_event(fc->chan->blocked_waitq, atomic_read(&fc->chan->num_waiting) == 0); + wait_event(fc->chan->blocked_waitq, fuse_chan_num_waiting(fc->chan) == 0); fuse_uring_wait_stopped_queues(fc); } diff --git a/fs/fuse/dev.h b/fs/fuse/dev.h index df8a199b42d28..7994f5290252b 100644 --- a/fs/fuse/dev.h +++ b/fs/fuse/dev.h @@ -11,16 +11,43 @@ struct fuse_conn; struct fuse_chan; struct fuse_dev; +struct file; 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); +unsigned int fuse_chan_num_background(struct fuse_chan *fch); +unsigned int fuse_chan_max_background(struct fuse_chan *fch); +void fuse_chan_max_background_set(struct fuse_chan *fch, unsigned int val); +unsigned int fuse_chan_num_waiting(struct fuse_chan *fch); +void fuse_chan_set_fc(struct fuse_chan *fch, struct fuse_conn *fc); +void fuse_chan_set_initialized(struct fuse_chan *fch); +void fuse_chan_io_uring_enable(struct fuse_chan *fch); + DEFINE_FREE(fuse_chan_free, struct fuse_chan *, if (_T) fuse_chan_free(_T)) void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc); +bool fuse_dev_verify(struct fuse_dev *fud, struct fuse_conn *fc); void fuse_dev_put(struct fuse_dev *fud); +bool fuse_dev_is_installed(struct fuse_dev *fud); +bool fuse_dev_is_sync_init(struct fuse_dev *fud); +struct fuse_dev *fuse_dev_grab(struct file *file); void fuse_init_server_timeout(struct fuse_chan *fch, unsigned int timeout); +#ifdef CONFIG_FUSE_IO_URING +bool fuse_uring_enabled(void); +void fuse_uring_destruct(struct fuse_chan *fch); +#else /* CONFIG_FUSE_IO_URING */ +static inline bool fuse_uring_enabled(void) +{ + return false; +} + +static inline void fuse_uring_destruct(struct fuse_chan *fch) +{ +} +#endif /* CONFIG_FUSE_IO_URING */ + #endif /* _FS_FUSE_DEV_H */ diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c index da63fc8d0c59d..296da4ff233c7 100644 --- a/fs/fuse/dev_uring.c +++ b/fs/fuse/dev_uring.c @@ -4,6 +4,7 @@ * Copyright (c) 2023-2024 DataDirect Networks. */ +#include "dev.h" #include "fuse_i.h" #include "dev_uring_i.h" #include "fuse_dev_i.h" @@ -185,9 +186,9 @@ bool fuse_uring_request_expired(struct fuse_chan *fch) return false; } -void fuse_uring_destruct(struct fuse_conn *fc) +void fuse_uring_destruct(struct fuse_chan *fch) { - struct fuse_ring *ring = fc->chan->ring; + struct fuse_ring *ring = fch->ring; int qid; if (!ring) @@ -218,7 +219,7 @@ void fuse_uring_destruct(struct fuse_conn *fc) kfree(ring->queues); kfree(ring); - fc->chan->ring = NULL; + fch->ring = NULL; } /* diff --git a/fs/fuse/dev_uring_i.h b/fs/fuse/dev_uring_i.h index c9fd92cb0f0da..8ba149e354235 100644 --- a/fs/fuse/dev_uring_i.h +++ b/fs/fuse/dev_uring_i.h @@ -136,8 +136,6 @@ struct fuse_ring { bool ready; }; -bool fuse_uring_enabled(void); -void fuse_uring_destruct(struct fuse_conn *fc); void fuse_uring_stop_queues(struct fuse_ring *ring); void fuse_uring_abort_end_requests(struct fuse_ring *ring); int fuse_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags); @@ -177,15 +175,6 @@ static inline bool fuse_uring_ready(struct fuse_conn *fc) #else /* CONFIG_FUSE_IO_URING */ -static inline void fuse_uring_destruct(struct fuse_conn *fc) -{ -} - -static inline bool fuse_uring_enabled(void) -{ - return false; -} - static inline void fuse_uring_abort(struct fuse_conn *fc) { } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 564bab1ea982a..c603cb0070f2d 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -7,7 +7,7 @@ */ #include "fuse_i.h" -#include "fuse_dev_i.h" +#include "dev.h" #include #include @@ -909,7 +909,7 @@ static int fuse_handle_readahead(struct folio *folio, ia = NULL; } if (!ia) { - if (fc->chan->num_background >= fc->congestion_threshold && + if (fuse_chan_num_background(fc->chan) >= fc->congestion_threshold && rac->ra->async_size >= readahead_count(rac)) /* * Congested and only async pages left, so skip the @@ -2301,7 +2301,7 @@ static int fuse_writepages(struct address_space *mapping, return -EIO; if (wbc->sync_mode == WB_SYNC_NONE && - fc->chan->num_background >= fc->congestion_threshold) + fuse_chan_num_background(fc->chan) >= fc->congestion_threshold) return 0; return iomap_writepages(&wpc); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index e6c1c161214c8..18fa729bfef2c 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1184,8 +1184,6 @@ int fuse_write_inode(struct inode *inode, struct writeback_control *wbc); int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *attr, struct file *file); -void fuse_set_initialized(struct fuse_conn *fc); - void fuse_unlock_inode(struct inode *inode, bool locked); bool fuse_lock_inode(struct inode *inode); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 772d9bec1362a..4de144cd4992c 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -8,8 +8,6 @@ #include "dev.h" #include "fuse_i.h" -#include "fuse_dev_i.h" -#include "dev_uring_i.h" #include #include @@ -812,8 +810,7 @@ static int fuse_opt_fd(struct fs_context *fsc, struct file *file) if (file->f_cred->user_ns != fsc->user_ns) return invalfc(fsc, "wrong user namespace for fuse device"); - ctx->fud = file->private_data; - refcount_inc(&ctx->fud->ref); + ctx->fud = fuse_dev_grab(file); return 0; } @@ -994,7 +991,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm, INIT_LIST_HEAD(&fc->mounts); list_add(&fm->fc_entry, &fc->mounts); fm->fc = fc; - fch->conn = fc; + fuse_chan_set_fc(fch, fc); fc->chan = fch; } EXPORT_SYMBOL_GPL(fuse_conn_init); @@ -1003,7 +1000,7 @@ static void delayed_release(struct rcu_head *p) { struct fuse_conn *fc = container_of(p, struct fuse_conn, rcu); - fuse_uring_destruct(fc); + fuse_uring_destruct(fc->chan); fuse_chan_free(fc->chan); put_user_ns(fc->user_ns); @@ -1019,8 +1016,6 @@ void fuse_conn_put(struct fuse_conn *fc) if (IS_ENABLED(CONFIG_FUSE_DAX)) fuse_dax_conn_free(fc); - if (fc->chan->timeout.req_timeout) - cancel_delayed_work_sync(&fc->chan->timeout.work); cancel_work_sync(&fc->epoch_work); fuse_chan_release(fc->chan); put_pid_ns(fc->pid_ns); @@ -1253,12 +1248,13 @@ static void process_init_limits(struct fuse_conn *fc, struct fuse_init_out *arg) sanitize_global_limit(&max_user_bgreq); sanitize_global_limit(&max_user_congthresh); - spin_lock(&fc->chan->bg_lock); if (arg->max_background) { - fc->chan->max_background = arg->max_background; + unsigned int max_background = arg->max_background; - if (!cap_sys_admin && fc->chan->max_background > max_user_bgreq) - fc->chan->max_background = max_user_bgreq; + if (!cap_sys_admin && max_background > max_user_bgreq) + max_background = max_user_bgreq; + + fuse_chan_max_background_set(fc->chan, max_background); } if (arg->congestion_threshold) { fc->congestion_threshold = arg->congestion_threshold; @@ -1267,7 +1263,6 @@ static void process_init_limits(struct fuse_conn *fc, struct fuse_init_out *arg) fc->congestion_threshold > max_user_congthresh) fc->congestion_threshold = max_user_congthresh; } - spin_unlock(&fc->chan->bg_lock); } struct fuse_init_args { @@ -1412,7 +1407,7 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args, ok = false; } if (flags & FUSE_OVER_IO_URING && fuse_uring_enabled()) - fc->chan->io_uring = 1; + fuse_chan_io_uring_enable(fc->chan); if (flags & FUSE_REQUEST_TIMEOUT) timeout = arg->request_timeout; @@ -1438,8 +1433,7 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args, fc->conn_error = 1; } - fuse_set_initialized(fc); - wake_up_all(&fc->chan->blocked_waitq); + fuse_chan_set_initialized(fc->chan); } static struct fuse_init_args *fuse_new_init(struct fuse_mount *fm) @@ -1788,9 +1782,9 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) mutex_lock(&fuse_mutex); err = -EINVAL; if (fud) { - if (fuse_dev_fc_get(fud)) + if (fuse_dev_is_installed(fud)) goto err_unlock; - if (fud->sync_init) + if (fuse_dev_is_sync_init(fud)) fc->sync_init = 1; } @@ -1848,9 +1842,7 @@ static int fuse_set_no_super(struct super_block *sb, struct fs_context *fsc) static int fuse_test_super(struct super_block *sb, struct fs_context *fsc) { - struct fuse_dev *fud = fsc->sget_key; - - return fuse_dev_fc_get(fud) == get_fuse_conn_super(sb); + return fuse_dev_verify(fsc->sget_key, get_fuse_conn_super(sb)); } static int fuse_get_tree(struct fs_context *fsc) @@ -1896,7 +1888,7 @@ static int fuse_get_tree(struct fs_context *fsc) * Allow creating a fuse mount with an already initialized fuse * connection */ - if (fuse_dev_fc_get(ctx->fud)) { + if (fuse_dev_is_installed(ctx->fud)) { fsc->sget_key = ctx->fud; sb = sget_fc(fsc, fuse_test_super, fuse_set_no_super); err = PTR_ERR_OR_ZERO(sb);