diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 6455617b74a0..85f738c53122 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -190,6 +190,11 @@ struct fuse_inode { */ struct timespec64 mtime; + /** + * @epoch: epoch of fc when cache was started + */ + int epoch; + /** * @iversion: iversion of directory when cache was * started diff --git a/fs/fuse/notify.c b/fs/fuse/notify.c index 7cd63502e124..f93d6fa05bf7 100644 --- a/fs/fuse/notify.c +++ b/fs/fuse/notify.c @@ -348,9 +348,9 @@ 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. Additionally, if inval_wq is set, a work - * queue is scheduled to trigger the invalidation. + * Increments the fuse connection epoch. This will cause dentries and + * readdir caches from 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) { diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index e993255584df..a94b00e13f6e 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -489,6 +489,7 @@ static void fuse_rdc_reset(struct inode *inode) fi->rdc.version++; fi->rdc.size = 0; fi->rdc.pos = 0; + fi->rdc.epoch = 0; } #define UNCACHED 1 @@ -530,6 +531,7 @@ static int fuse_readdir_cached(struct file *file, struct dir_context *ctx) if (!ctx->pos && !fi->rdc.size) { fi->rdc.mtime = inode_get_mtime(inode); fi->rdc.iversion = inode_query_iversion(inode); + fi->rdc.epoch = atomic_read(&fc->epoch); } spin_unlock(&fi->rdc.lock); return UNCACHED; @@ -543,7 +545,8 @@ static int fuse_readdir_cached(struct file *file, struct dir_context *ctx) struct timespec64 mtime = inode_get_mtime(inode); if (inode_peek_iversion(inode) != fi->rdc.iversion || - !timespec64_equal(&fi->rdc.mtime, &mtime)) { + !timespec64_equal(&fi->rdc.mtime, &mtime) || + fi->rdc.epoch != atomic_read(&fc->epoch)) { fuse_rdc_reset(inode); goto retry_locked; }