diff mbox series

fuse: fix inconsistent status between faccess and mkdir

Message ID 20210514015517.258-1-changfengnan@vivo.com (mailing list archive)
State New
Headers show
Series fuse: fix inconsistent status between faccess and mkdir | expand

Commit Message

Fengnan Chang May 14, 2021, 1:55 a.m. UTC
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@vivo.com>
---
 fs/fuse/dir.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

Comments

Matthew Wilcox May 14, 2021, 2:26 a.m. UTC | #1
On Fri, May 14, 2021 at 09:55:17AM +0800, Fengnan Chang wrote:
> +++ b/fs/fuse/dir.c
> @@ -1065,6 +1065,14 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
>  				fuse_fillattr(inode, &outarg.attr, stat);
>  		}
>  	}
> +	if (err == -ENOENT) {
> +		struct dentry *entry;
> +
> +		entry = d_obtain_alias(inode);

Why d_obtain_alias() instead of d_find_any_alias()?

And what if you find the wrong alias?  ie an inode with two links?
Or does fuse not support hardlinks?
Fengnan Chang May 14, 2021, 3:27 a.m. UTC | #2
we should us d_find_any_alias() rather than d_obtain_alias(), it's my
mistake.

Fuse is support hardlinks, if an inode with two links, we may found wrong
alias, we may need invalidate all dentry, because of the file is not exist
anymore.
But in other kernel code, I didn't see any handling for this situation. I
can't figure out why.

Thanks.

-----邮件原件-----
发件人: Matthew Wilcox <willy@infradead.org> 
发送时间: 2021年5月14日 10:27
收件人: Fengnan Chang <changfengnan@vivo.com>
抄送: miklos@szeredi.hu; linux-fsdevel@vger.kernel.org
主题: Re: [PATCH] fuse: fix inconsistent status between faccess and mkdir

On Fri, May 14, 2021 at 09:55:17AM +0800, Fengnan Chang wrote:
> +++ b/fs/fuse/dir.c
> @@ -1065,6 +1065,14 @@ static int fuse_do_getattr(struct inode *inode,
struct kstat *stat,
>  				fuse_fillattr(inode, &outarg.attr, stat);
>  		}
>  	}
> +	if (err == -ENOENT) {
> +		struct dentry *entry;
> +
> +		entry = d_obtain_alias(inode);

Why d_obtain_alias() instead of d_find_any_alias()?

And what if you find the wrong alias?  ie an inode with two links?
Or does fuse not support hardlinks?
diff mbox series

Patch

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 06a18700a845..154dd4578762 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1065,6 +1065,14 @@  static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
 				fuse_fillattr(inode, &outarg.attr, stat);
 		}
 	}
+	if (err == -ENOENT) {
+		struct dentry *entry;
+
+		entry = d_obtain_alias(inode);
+		if (!IS_ERR(entry) && get_node_id(inode) != FUSE_ROOT_ID)
+			fuse_invalidate_entry_cache(entry);
+	}
+
 	return err;
 }

@@ -1226,6 +1234,14 @@  static int fuse_access(struct inode *inode, int mask)
 		fm->fc->no_access = 1;
 		err = 0;
 	}
+	if (err == -ENOENT) {
+		struct dentry *entry;
+
+		entry = d_obtain_alias(inode);
+		if (!IS_ERR(entry) && get_node_id(inode) != FUSE_ROOT_ID)
+			fuse_invalidate_entry_cache(entry);
+	}
+
 	return err;
 }