]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
fuse: don't access transport layer structs directly from the fs layer
authorMiklos Szeredi <mszeredi@redhat.com>
Thu, 19 Mar 2026 14:40:10 +0000 (15:40 +0100)
committerMiklos Szeredi <mszeredi@redhat.com>
Mon, 15 Jun 2026 12:06:16 +0000 (14:06 +0200)
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 <mszeredi@redhat.com>
fs/fuse/control.c
fs/fuse/dev.c
fs/fuse/dev.h
fs/fuse/dev_uring.c
fs/fuse/dev_uring_i.h
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c

index 228e1e7114b7ae4ecb564899ca7b6a53e1a7c10b..e6f513eb7d4a37f854ddb3ec5fd3e9e1b2ccc796 100644 (file)
@@ -7,7 +7,7 @@
 */
 
 #include "fuse_i.h"
-#include "fuse_dev_i.h"
+#include "dev.h"
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -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);
                }
        }
index 19b8cee3cff37c047350c2d0af7710b03c47f1e9..df851c2383e939bf487cd7c7f008461de34e3e4c 100644 (file)
@@ -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);
 }
index df8a199b42d28a450bbd6b265682bde34b244351..7994f5290252bb24c1a558fce95e11da70e4290c 100644 (file)
 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 */
index da63fc8d0c59df3340834194f954d635826d1e88..296da4ff233c77b5a3642bf67c03b397b93818a0 100644 (file)
@@ -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;
 }
 
 /*
index c9fd92cb0f0dace5da470fdfdba4a40d3dc23e46..8ba149e35423567d29a3d40f16972f5c5b042518 100644 (file)
@@ -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)
 {
 }
index 564bab1ea982a40cd0b6de6c1275458604d41bfd..c603cb0070f2daad9b0ad808d50586fce73172e0 100644 (file)
@@ -7,7 +7,7 @@
 */
 
 #include "fuse_i.h"
-#include "fuse_dev_i.h"
+#include "dev.h"
 
 #include <linux/pagemap.h>
 #include <linux/slab.h>
@@ -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);
index e6c1c161214c86db56de65dc77badf58eb0cc42a..18fa729bfef2c3d198655118620cc6aac3f36b5c 100644 (file)
@@ -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);
 
index 772d9bec1362a80ca9d3ca2421809dcea881bc0a..4de144cd4992c3e4220f8a85d87b9c0d943cda02 100644 (file)
@@ -8,8 +8,6 @@
 
 #include "dev.h"
 #include "fuse_i.h"
-#include "fuse_dev_i.h"
-#include "dev_uring_i.h"
 
 #include <linux/dax.h>
 #include <linux/pagemap.h>
@@ -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);