From 9ffcf1ac125bd0c272faec74f6b14472f5fab3fb Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 15 Aug 2018 17:42:34 +0200 Subject: [PATCH 1842/2944] fuse: delete dentry if timeout is zero task #28910367 commit 8fab010644363f8f80194322aa7a81e38c867af3 upstream Don't hold onto dentry in lru list if need to re-lookup it anyway at next access. Only do this if explicitly enabled, otherwise it could result in performance regression. More advanced version of this patch would periodically flush out dentries from the lru which have gone stale. Signed-off-by: Miklos Szeredi Signed-off-by: Liu Bo Reviewed-by: Joseph Qi --- fs/fuse/dir.c | 28 +++++++++++++++++++++++++--- fs/fuse/fuse_i.h | 3 +++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 6244345..899b7e5 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -44,12 +44,28 @@ static void fuse_advise_use_readdirplus(struct inode *dir) struct rcu_head rcu; }; -static inline void fuse_dentry_settime(struct dentry *entry, u64 time) +static void fuse_dentry_settime(struct dentry *dentry, u64 time) { - ((union fuse_dentry *) entry->d_fsdata)->time = time; + struct fuse_conn *fc = get_fuse_conn_super(dentry->d_sb); + bool delete = !time && fc->delete_stale; + /* + * Mess with DCACHE_OP_DELETE because dput() will be faster without it. + * Don't care about races, either way it's just an optimization + */ + if ((!delete && (dentry->d_flags & DCACHE_OP_DELETE)) || + (delete && !(dentry->d_flags & DCACHE_OP_DELETE))) { + spin_lock(&dentry->d_lock); + if (!delete) + dentry->d_flags &= ~DCACHE_OP_DELETE; + else + dentry->d_flags |= DCACHE_OP_DELETE; + spin_unlock(&dentry->d_lock); + } + + ((union fuse_dentry *) dentry->d_fsdata)->time = time; } -static inline u64 fuse_dentry_time(struct dentry *entry) +static inline u64 fuse_dentry_time(const struct dentry *entry) { return ((union fuse_dentry *) entry->d_fsdata)->time; } @@ -281,8 +297,14 @@ static void fuse_dentry_release(struct dentry *dentry) kfree_rcu(fd, rcu); } +static int fuse_dentry_delete(const struct dentry *dentry) +{ + return time_before64(fuse_dentry_time(dentry), get_jiffies_64()); +} + const struct dentry_operations fuse_dentry_operations = { .d_revalidate = fuse_dentry_revalidate, + .d_delete = fuse_dentry_delete, .d_init = fuse_dentry_init, .d_release = fuse_dentry_release, }; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 663eea4..019ce2b 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -695,6 +695,9 @@ struct fuse_conn { /** Allow other than the mounter user to access the filesystem ? */ unsigned allow_other:1; + /* Delete dentries that have gone stale */ + unsigned int delete_stale:1; + /** The number of requests waiting for completion */ atomic_t num_waiting; -- 1.8.3.1