mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
fuse: invalidate readdir cache on epoch bump
FUSE_NOTIFY_INC_EPOCH invalidates dentries, but does not invalidate cached
readdir results. A process with cwd inside a FUSE mount can therefore
observe stale readdir(".") output after an epoch bump.
Fix this by recording epoch in the readdir cache and checking it on reuse.
Minimal reproducer:
- mount a tiny FUSE fs with an empty root directory
- on opendir, enable fi->cache_readdir and fi->keep_cache
- chdir into the mount and call readdir(".") to populate readdir cache
- make the FUSE server report one file in the root directory
- send only FUSE_NOTIFY_INC_EPOCH
- call readdir(".") again; before this change it stays stale, after this
change it sees the new file
Fixes: 2396356a94 ("fuse: add more control over cache invalidation behaviour")
Signed-off-by: Jun Wu <quark@meta.com>
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
Reviewed-by: Luis Henriques <luis@igalia.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
6af3330ec5
commit
0fa8346099
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user