since FUSE caches dentries and attributes with separate timeout, It may happen that checking the permission returns -ENOENT, but because the dentries cache has not timed out, creating the file returns -EEXIST. Fix this by when return -ENOENT, mark the entry as stale. Signed-off-by: Fengnan Chang <changfengnan@xxxxxxxx> --- fs/fuse/dir.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 06a18700a845..a22206290da9 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1065,6 +1065,24 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, fuse_fillattr(inode, &outarg.attr, stat); } } + if (err == -ENOENT && get_node_id(inode) != FUSE_ROOT_ID) { + if (S_ISDIR(inode->i_mode)) { + struct dentry *dir = d_find_any_alias(inode); + + if (dir) { + fuse_invalidate_entry_cache(dir); + dput(dir); + } + } else { + struct dentry *dentry; + + while ((dentry = d_find_alias(inode))) { + fuse_invalidate_entry_cache(dentry); + dput(dentry); + } + } + } + return err; } @@ -1226,6 +1244,24 @@ static int fuse_access(struct inode *inode, int mask) fm->fc->no_access = 1; err = 0; } + if (err == -ENOENT && get_node_id(inode) != FUSE_ROOT_ID) { + if (S_ISDIR(inode->i_mode)) { + struct dentry *dir = d_find_any_alias(inode); + + if (dir) { + fuse_invalidate_entry_cache(dir); + dput(dir); + } + } else { + struct dentry *dentry; + + while ((dentry = d_find_alias(inode))) { + fuse_invalidate_entry_cache(dentry); + dput(dentry); + } + } + } + return err; } -- 2.29.0