]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
fuse: new work queue to invalidate dentries from old epochs
authorLuis Henriques <luis@igalia.com>
Tue, 16 Sep 2025 13:53:09 +0000 (14:53 +0100)
committerMiklos Szeredi <mszeredi@redhat.com>
Wed, 12 Nov 2025 10:45:03 +0000 (11:45 +0100)
With the infrastructure introduced to periodically invalidate expired
dentries, it is now possible to add an extra work queue to invalidate
dentries when an epoch is incremented.  This work queue will only be
triggered when the 'inval_wq' parameter is set.

Signed-off-by: Luis Henriques <luis@igalia.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/fuse_i.h
fs/fuse/inode.c

index 49b18d7accb39927e49bc3814ad2c3e51db84bb4..6d59cbc877c6ad06deb6b02eba05a9015228cd05 100644 (file)
@@ -2041,13 +2041,14 @@ static int fuse_notify_resend(struct fuse_conn *fc)
 
 /*
  * Increments the fuse connection epoch.  This will result of dentries from
- * previous epochs to be invalidated.
- *
- * XXX optimization: add call to shrink_dcache_sb()?
+ * previous epochs to be invalidated.  Additionally, if inval_wq is set, a work
+ * queue is scheduled to trigger the invalidation.
  */
 static int fuse_notify_inc_epoch(struct fuse_conn *fc)
 {
        atomic_inc(&fc->epoch);
+       if (inval_wq)
+               schedule_work(&fc->epoch_work);
 
        return 0;
 }
index 77982fdbcf278ac416151a94b0090ba96fc527f8..8ef8134e1cd5dc13ba75f22abd5ae626d8dbcebb 100644 (file)
@@ -189,6 +189,27 @@ static void fuse_dentry_tree_work(struct work_struct *work)
                                      secs_to_jiffies(inval_wq));
 }
 
+void fuse_epoch_work(struct work_struct *work)
+{
+       struct fuse_conn *fc = container_of(work, struct fuse_conn,
+                                           epoch_work);
+       struct fuse_mount *fm;
+       struct inode *inode;
+
+       down_read(&fc->killsb);
+
+       inode = fuse_ilookup(fc, FUSE_ROOT_ID, &fm);
+       iput(inode);
+
+       if (fm) {
+               /* Remove all possible active references to cached inodes */
+               shrink_dcache_sb(fm->sb);
+       } else
+               pr_warn("Failed to get root inode");
+
+       up_read(&fc->killsb);
+}
+
 void fuse_dentry_tree_init(void)
 {
        int i;
index ac717b3b46a13f0f6263f4a2c09a46dbe20be86f..a80411028254e82ba353a5df03ee67f83ffadddb 100644 (file)
@@ -649,6 +649,8 @@ struct fuse_conn {
        /** Current epoch for up-to-date dentries */
        atomic_t epoch;
 
+       struct work_struct epoch_work;
+
        struct rcu_head rcu;
 
        /** The user id for this mount */
@@ -1287,6 +1289,8 @@ void fuse_check_timeout(struct work_struct *work);
 void fuse_dentry_tree_init(void);
 void fuse_dentry_tree_cleanup(void);
 
+void fuse_epoch_work(struct work_struct *work);
+
 /**
  * Invalidate inode attributes
  */
index 793f1766ae5afa5d287eca65b5dcb8ec752e5ecc..3087165a6004291c5487f9b1cbe987f73db4fb47 100644 (file)
@@ -977,6 +977,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
        refcount_set(&fc->count, 1);
        atomic_set(&fc->dev_count, 1);
        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);
@@ -1029,6 +1030,7 @@ void fuse_conn_put(struct fuse_conn *fc)
                        fuse_dax_conn_free(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);
                put_pid_ns(fc->pid_ns);