[PATCH 2/3] fuse: Add negative_dentry_timeout option
From: Keiichi Watanabe
Date: Tue Jun 20 2023 - 11:15:25 EST
Add `negative_dentry_timeout` mount option for FUSE to cache negative
dentries for the specified duration.
With this option enabled, second and subsequent lookups to non-existent
files can be omitted.
A user needs to specify how often each negative_dentry cache should be
refreshed. This is because the kernel has no idea when a FUSE server
creates or deletes files, unlike normal filesystems such as ext4 where
all of file operations are managed by the kernel.
The appropriate timeout duration should be determined by considering how
often a FUSE server update file paths and the amount of memory the
kernel can use the cache.
Signed-off-by: Keiichi Watanabe <keiichiw@xxxxxxxxxxxx>
---
Documentation/filesystems/fuse.rst | 6 ++++++
fs/fuse/dir.c | 3 ++-
fs/fuse/fuse_i.h | 4 ++++
fs/fuse/inode.c | 12 +++++++++++-
4 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/Documentation/filesystems/fuse.rst b/Documentation/filesystems/fuse.rst
index 1e31e87aee68..6d3b55476504 100644
--- a/Documentation/filesystems/fuse.rst
+++ b/Documentation/filesystems/fuse.rst
@@ -103,6 +103,12 @@ blksize=N
Set the block size for the filesystem. The default is 512. This
option is only valid for 'fuseblk' type mounts.
+negative_dentry_timeout=N
+ Set the time in seconds to keep negative dentry cache. If a lookup for
+ a path fails, the kernel won't do another lookup for this period of
+ time. The default value is 0, which means that negative dentries are not
+ cached.
+
Control filesystem
==================
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 35bc174f9ba2..21ff395467ab 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -453,7 +453,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
if (outarg_valid)
fuse_change_entry_timeout(entry, &outarg);
else
- fuse_invalidate_entry_cache(entry);
+ fuse_dentry_settime(entry,
+ time_to_jiffies(get_fuse_mount(dir)->negative_dentry_timeout, 0));
if (inode)
fuse_advise_use_readdirplus(dir);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 9b7fc7d3c7f1..bbfe53635329 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -516,6 +516,7 @@ struct fuse_fs_context {
unsigned int max_read;
unsigned int blksize;
const char *subtype;
+ unsigned int negative_dentry_timeout;
/* DAX device, may be NULL */
struct dax_device *dax_dev;
@@ -860,6 +861,9 @@ struct fuse_mount {
*/
struct super_block *sb;
+ /* Timeout on negative denty caches in seconds */
+ u32 negative_dentry_timeout;
+
/* Entry on fc->mounts */
struct list_head fc_entry;
};
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index d66070af145d..45ed0c52f8a6 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -654,7 +654,8 @@ enum {
OPT_ALLOW_OTHER,
OPT_MAX_READ,
OPT_BLKSIZE,
- OPT_ERR
+ OPT_ERR,
+ OPT_NEGATIVE_DENTRY_TIMEOUT
};
static const struct fs_parameter_spec fuse_fs_parameters[] = {
@@ -668,6 +669,7 @@ static const struct fs_parameter_spec fuse_fs_parameters[] = {
fsparam_u32 ("max_read", OPT_MAX_READ),
fsparam_u32 ("blksize", OPT_BLKSIZE),
fsparam_string ("subtype", OPT_SUBTYPE),
+ fsparam_u32 ("negative_dentry_timeout", OPT_NEGATIVE_DENTRY_TIMEOUT),
{}
};
@@ -751,6 +753,10 @@ static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param)
ctx->blksize = result.uint_32;
break;
+ case OPT_NEGATIVE_DENTRY_TIMEOUT:
+ ctx->negative_dentry_timeout = result.uint_32;
+ break;
+
default:
return -EINVAL;
}
@@ -1482,6 +1488,10 @@ static int fuse_get_tree_submount(struct fs_context *fsc)
return -ENOMEM;
fm->fc = fuse_conn_get(fc);
+ fm->negative_dentry_timeout =
+ ((struct fuse_fs_context *)fsc->fs_private)
+ ->negative_dentry_timeout;
+
fsc->s_fs_info = fm;
sb = sget_fc(fsc, NULL, set_anon_super_fc);
if (fsc->s_fs_info)
--
2.41.0.185.g7c58973941-goog