[PATCH v2] fuse: send forget req when lookup outarg is invalid

Zhang Tianci posted 1 patch 1 month ago
fs/fuse/dir.c | 36 ++++++++++++++++++++++++++----------
1 file changed, 26 insertions(+), 10 deletions(-)
[PATCH v2] fuse: send forget req when lookup outarg is invalid
Posted by Zhang Tianci 1 month ago
We shall send forget request if lookup/create/open success but returned
outarg.attr is invalid, because FUSEdaemon had increase the lookup count

Reported-by: Xie Yongji <xieyongji@bytedance.com>
Signed-off-by: Zhang Tianci <zhangtianci.1997@bytedance.com>
---

Changes in v2:
 - Fix wrong usage of goto label.               [Bernd]
 - Link to v1: https://lore.kernel.org/lkml/20260202120023.74357-1-zhangtianci.1997@bytedance.com/

 fs/fuse/dir.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 4b6b3d2758ff2..be25934b86105 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -578,8 +578,10 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
 		goto out_put_forget;
 
 	err = -EIO;
-	if (fuse_invalid_attr(&outarg->attr))
-		goto out_put_forget;
+	if (fuse_invalid_attr(&outarg->attr)) {
+		fuse_queue_forget(fm->fc, forget, outarg->nodeid, 1);
+		goto out;
+	}
 	if (outarg->nodeid == FUSE_ROOT_ID && outarg->generation != 0) {
 		pr_warn_once("root generation should be zero\n");
 		outarg->generation = 0;
@@ -878,14 +880,24 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
 	if (err)
 		goto out_free_ff;
 
-	err = -EIO;
-	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) ||
-	    fuse_invalid_attr(&outentry.attr))
-		goto out_free_ff;
-
 	ff->fh = outopenp->fh;
 	ff->nodeid = outentry.nodeid;
 	ff->open_flags = outopenp->open_flags;
+
+	err = -EIO;
+	if (invalid_nodeid(outentry.nodeid)) {
+		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
+		fuse_sync_release(NULL, ff, flags);
+		goto out_put_forget_req;
+	}
+
+	if (!S_ISREG(outentry.attr.mode) || fuse_invalid_attr(&outentry.attr)) {
+		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
+		fuse_sync_release(NULL, ff, flags);
+		fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1);
+		goto out_err;
+	}
+
 	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
 			  &outentry.attr, ATTR_TIMEOUT(&outentry), 0, 0);
 	if (!inode) {
@@ -1007,11 +1019,14 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun
 		goto out_put_forget_req;
 
 	err = -EIO;
-	if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr))
+	if (invalid_nodeid(outarg.nodeid))
 		goto out_put_forget_req;
 
-	if ((outarg.attr.mode ^ mode) & S_IFMT)
-		goto out_put_forget_req;
+	if (fuse_invalid_attr(&outarg.attr) ||
+	    ((outarg.attr.mode ^ mode) & S_IFMT)) {
+		fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1);
+		goto out_err;
+	}
 
 	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
 			  &outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0);
@@ -1040,6 +1055,7 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun
 	if (err == -EEXIST)
 		fuse_invalidate_entry(entry);
 	kfree(forget);
+out_err:
 	return ERR_PTR(err);
 }
 
-- 
2.39.5
Re: [PATCH v2] fuse: send forget req when lookup outarg is invalid
Posted by Miklos Szeredi 1 month ago
On Thu, 26 Feb 2026 at 13:50, Zhang Tianci
<zhangtianci.1997@bytedance.com> wrote:
>
> We shall send forget request if lookup/create/open success but returned
> outarg.attr is invalid, because FUSEdaemon had increase the lookup count

These are cases when the fuse daemon is broken anyway.  Keeping it
working does not make much sense, and adds complexity to the kernel.

So NAK unless there's a use case which explains why this would be a good thing.

Thanks,
Miklos