FILESYSTEM IN USERSPACE (FUSE) development
 help / color / mirror / Atom feed
From: Joanne Koong <joannelkoong@gmail.com>
To: miklos@szeredi.hu, fuse-devel@lists.linux.dev
Subject: [PATCH v1 01/13] fuse: fix missing forget requests in error paths
Date: Thu, 23 Apr 2026 18:16:34 -0700	[thread overview]
Message-ID: <20260424011646.457682-2-joannelkoong@gmail.com> (raw)
In-Reply-To: <20260424011646.457682-1-joannelkoong@gmail.com>

If the server returned a valid nodeid but invalid attributes, the kernel
needs to send a forget request to tell the server to release its
reference, else this leads to server-side leaks. These paths only
trigger with a misbehaving server returning invalid attributes, so the
real-world impact is minimal, but forgets should be sent.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/dir.c | 52 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 31 insertions(+), 21 deletions(-)

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index be41c14ef329..6ab05d7d297d 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -583,7 +583,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
 
 	err = -EIO;
 	if (fuse_invalid_attr(&outarg->attr))
-		goto out_put_forget;
+		goto out_queue_forget;
 	if (outarg->nodeid == FUSE_ROOT_ID && outarg->generation != 0) {
 		pr_warn_once("root generation should be zero\n");
 		outarg->generation = 0;
@@ -593,16 +593,18 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
 			   &outarg->attr, ATTR_TIMEOUT(outarg),
 			   attr_version, evict_ctr);
 	err = -ENOMEM;
-	if (!*inode) {
-		fuse_chan_queue_forget(fm->fc->chan, forget, outarg->nodeid, 1);
-		goto out;
-	}
+	if (!*inode)
+		goto out_queue_forget;
 	err = 0;
 
  out_put_forget:
 	kfree(forget);
  out:
 	return err;
+
+out_queue_forget:
+	fuse_chan_queue_forget(fm->fc->chan, forget, outarg->nodeid, 1);
+	return err;
 }
 
 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
@@ -882,22 +884,21 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
 		goto out_free_ff;
 
 	err = -EIO;
-	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) ||
-	    fuse_invalid_attr(&outentry.attr))
+	if (invalid_nodeid(outentry.nodeid))
 		goto out_free_ff;
 
 	ff->fh = outopenp->fh;
 	ff->nodeid = outentry.nodeid;
 	ff->open_flags = outopenp->open_flags;
+
+	if (!S_ISREG(outentry.attr.mode) || fuse_invalid_attr(&outentry.attr))
+		goto out_forget;
+
 	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
 			  &outentry.attr, ATTR_TIMEOUT(&outentry), 0, 0);
-	if (!inode) {
-		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
-		fuse_sync_release(NULL, ff, flags);
-		fuse_chan_queue_forget(fm->fc->chan, forget, outentry.nodeid, 1);
-		err = -ENOMEM;
-		goto out_err;
-	}
+	err = -ENOMEM;
+	if (!inode)
+		goto out_forget;
 	kfree(forget);
 	d_instantiate(entry, inode);
 	entry->d_time = epoch;
@@ -925,6 +926,11 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
 	kfree(forget);
 out_err:
 	return err;
+out_forget:
+	flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
+	fuse_sync_release(NULL, ff, flags);
+	fuse_chan_queue_forget(fm->fc->chan, forget, outentry.nodeid, 1);
+	return err;
 }
 
 static int fuse_mknod(struct mnt_idmap *, struct inode *, struct dentry *,
@@ -1010,18 +1016,18 @@ 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)
+		goto out_forget;
 
 	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
 			  &outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0);
-	if (!inode) {
-		fuse_chan_queue_forget(fm->fc->chan, forget, outarg.nodeid, 1);
-		return ERR_PTR(-ENOMEM);
-	}
+	err = -ENOMEM;
+	if (!inode)
+		goto out_forget;
+
 	kfree(forget);
 
 	d_drop(entry);
@@ -1044,6 +1050,10 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun
 		fuse_invalidate_entry(entry);
 	kfree(forget);
 	return ERR_PTR(err);
+
+out_forget:
+	fuse_chan_queue_forget(fm->fc->chan, forget, outarg.nodeid, 1);
+	return ERR_PTR(err);
 }
 
 static int create_new_nondir(struct mnt_idmap *idmap, struct fuse_mount *fm,
-- 
2.52.0


  reply	other threads:[~2026-04-24  1:17 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-24  1:16 [PATCH v1 00/13] fuse: dir.c cleanups Joanne Koong
2026-04-24  1:16 ` Joanne Koong [this message]
2026-04-24  8:18   ` [PATCH v1 01/13] fuse: fix missing forget requests in error paths Amir Goldstein
2026-04-24 17:43     ` Joanne Koong
2026-04-24  1:16 ` [PATCH v1 02/13] fuse: clean up fuse_lookup_name() Joanne Koong
2026-04-24  1:16 ` [PATCH v1 03/13] fuse: clean up fuse_lookup() Joanne Koong
2026-04-24  1:16 ` [PATCH v1 04/13] fuse: clean up fuse_dentry_revalidate() Joanne Koong
2026-04-24  8:20   ` Amir Goldstein
2026-04-24  1:16 ` [PATCH v1 05/13] fuse: clean up fuse_create_open() Joanne Koong
2026-04-24  1:16 ` [PATCH v1 06/13] fuse: clean up fuse_rename2() Joanne Koong
2026-04-24  1:16 ` [PATCH v1 07/13] fuse: clean up fuse_time_to_jiffies() Joanne Koong
2026-04-24  1:16 ` [PATCH v1 08/13] fuse: clean up fuse_link() Joanne Koong
2026-04-24  1:16 ` [PATCH v1 09/13] fuse: clean up fuse_do_getattr() Joanne Koong
2026-04-24  1:16 ` [PATCH v1 10/13] fuse: clean up fuse_update_get_attr() Joanne Koong
2026-04-24  1:16 ` [PATCH v1 11/13] fuse: clean up fuse_get_link() Joanne Koong
2026-04-24  1:16 ` [PATCH v1 12/13] fuse: clean up fuse_dir_open() Joanne Koong
2026-04-24  1:16 ` [PATCH v1 13/13] fuse: clean up setattr() Joanne Koong
2026-04-24  7:51 ` [PATCH v1 00/13] fuse: dir.c cleanups Amir Goldstein
2026-04-24 17:27   ` Joanne Koong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260424011646.457682-2-joannelkoong@gmail.com \
    --to=joannelkoong@gmail.com \
    --cc=fuse-devel@lists.linux.dev \
    --cc=miklos@szeredi.hu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox