From: Sasha Levin <sashal@kernel.org>
To: stable@vger.kernel.org
Cc: Miklos Szeredi <mszeredi@redhat.com>, Sasha Levin <sashal@kernel.org>
Subject: [PATCH 6.18.y 1/4] fuse: abort related layering cleanup
Date: Mon, 31 Aug 2026 12:42:53 -0400 [thread overview]
Message-ID: <20260831164256.270090-1-sashal@kernel.org> (raw)
In-Reply-To: <2026083101-rimless-sadness-3898@gregkh>
From: Miklos Szeredi <mszeredi@redhat.com>
[ Upstream commit 4eeb5e6cb0fd89b343fcf755ae3aad76fdb5b2c2 ]
- rename fuse_abort_conn() to fuse_chan_abort(), pass fuse_chan pointer
instead of fuse_conn
- pass an abort_with_err argument that tells fuse_dev_(read|write) to
return with ECONNABORTED instead of ENODEV
- move fc->aborted to fch->abort_with_err
- rename fuse_wait_aborted() to fuse_chan_wait_aborted()
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
[ 6.18 has no "struct fuse_chan" -- the connection object still plays
that role, and the surrounding series that splits it out is not in
stable. Adapted as follows:
- the renames (fuse_abort_conn() -> fuse_chan_abort(),
fuse_wait_aborted() -> fuse_chan_wait_aborted(), the "abort_conn"
label in fuse_check_timeout() -> "chan_abort") and the new
abort_with_err argument are taken as-is, but both helpers keep
taking "struct fuse_conn *".
- the "move fc->aborted to fch->abort_with_err" bullet is dropped:
there is no fuse_chan to move the flag into, so fc->aborted stays
in struct fuse_conn. fuse_chan_abort() only ever *sets* it, as
control.c did before, rather than assigning the new argument
unconditionally the way upstream does: on this tree the flag is
write-once and is what makes fuse_dev_do_read() and
fuse_uring_cmd() report ECONNABORTED instead of ENODEV, so letting
a later abort with abort_with_err=false clear it (umount -f,
fuse_conn_destroy(), fuse_dev_release(), the timeout worker) would
change what userspace sees after a sysfs abort on an abort_err
mount. Consequently the fuse_dev_i.h and dev_uring.c hunks, which
only rename the field access, are dropped as well.
- fs/fuse/dev.h and fs/fuse/req_timeout.c do not exist here: the
declarations stay in fuse_i.h and fuse_check_timeout() lives in
dev.c, so those two hunks were replayed there.
- in request_wait_answer() the connection pointer is named "fch",
matching the name upstream gives it in 28d733cc3ecad ("fuse: change
req->fm to req->chan"), so that the follow-up fix applies here
unchanged. ]
[ sashal: Reduced backport -- upstream 4eeb5e6cb0fd8 touches 9 file(s), this
backport carries 5. Not backported here:
fs/fuse/dev.h
fs/fuse/dev_uring.c
fs/fuse/fuse_dev_i.h
fs/fuse/req_timeout.c
This note is generated from the file lists only; see the resolution record
for the reasoning. ]
Stable-dep-of: 64b0b5cacbd2 ("fuse: wait for FR_FINISHED on abort_on_kill to prevent use-after-free")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/fuse/control.c | 4 +---
fs/fuse/cuse.c | 4 ++--
fs/fuse/dev.c | 35 +++++++++++++++++++----------------
fs/fuse/fuse_i.h | 4 ++--
fs/fuse/inode.c | 6 +++---
5 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index 2e300f6d646c3..5536d6ee65514 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -37,9 +37,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
{
struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
if (fc) {
- if (fc->abort_err)
- fc->aborted = true;
- fuse_abort_conn(fc);
+ fuse_chan_abort(fc, fc->abort_err);
fuse_conn_put(fc);
}
return count;
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index 2bb98bf81b079..d90f138321fe9 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -425,7 +425,7 @@ static void cuse_process_init_reply(struct fuse_mount *fm,
err_region:
unregister_chrdev_region(devt, 1);
err:
- fuse_abort_conn(fc);
+ fuse_chan_abort(fc, false);
goto out;
}
@@ -593,7 +593,7 @@ static ssize_t cuse_class_abort_store(struct device *dev,
{
struct cuse_conn *cc = dev_get_drvdata(dev);
- fuse_abort_conn(&cc->fc);
+ fuse_chan_abort(&cc->fc, false);
return count;
}
static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store);
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 77c3982bca3d7..934f9ac5056ed 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -87,13 +87,13 @@ void fuse_check_timeout(struct work_struct *work)
expired = fuse_request_expired(fc, &fiq->pending);
spin_unlock(&fiq->lock);
if (expired)
- goto abort_conn;
+ goto chan_abort;
spin_lock(&fc->bg_lock);
expired = fuse_request_expired(fc, &fc->bg_queue);
spin_unlock(&fc->bg_lock);
if (expired)
- goto abort_conn;
+ goto chan_abort;
spin_lock(&fc->lock);
if (!fc->connected) {
@@ -107,7 +107,7 @@ void fuse_check_timeout(struct work_struct *work)
fuse_fpq_processing_expired(fc, fpq->processing)) {
spin_unlock(&fpq->lock);
spin_unlock(&fc->lock);
- goto abort_conn;
+ goto chan_abort;
}
spin_unlock(&fpq->lock);
@@ -115,15 +115,15 @@ void fuse_check_timeout(struct work_struct *work)
spin_unlock(&fc->lock);
if (fuse_uring_request_expired(fc))
- goto abort_conn;
+ goto chan_abort;
out:
queue_delayed_work(system_percpu_wq, &fc->timeout.work,
fuse_timeout_timer_freq);
return;
-abort_conn:
- fuse_abort_conn(fc);
+chan_abort:
+ fuse_chan_abort(fc, false);
}
static void fuse_request_init(struct fuse_mount *fm, struct fuse_req *req)
@@ -180,7 +180,7 @@ static void fuse_drop_waiting(struct fuse_conn *fc)
{
/*
* lockess check of fc->connected is okay, because atomic_dec_and_test()
- * provides a memory barrier matched with the one in fuse_wait_aborted()
+ * provides a memory barrier matched with the one in fuse_chan_wait_aborted()
* to ensure no wake-up is missed.
*/
if (atomic_dec_and_test(&fc->num_waiting) &&
@@ -551,11 +551,11 @@ bool fuse_remove_pending_req(struct fuse_req *req, spinlock_t *lock)
static void request_wait_answer(struct fuse_req *req)
{
- struct fuse_conn *fc = req->fm->fc;
- struct fuse_iqueue *fiq = &fc->iq;
+ struct fuse_conn *fch = req->fm->fc;
+ struct fuse_iqueue *fiq = &fch->iq;
int err;
- if (!fc->no_interrupt) {
+ if (!fch->no_interrupt) {
/* Any signal may interrupt this */
err = wait_event_interruptible(req->waitq,
test_bit(FR_FINISHED, &req->flags));
@@ -579,7 +579,7 @@ static void request_wait_answer(struct fuse_req *req)
return;
if (req->args->abort_on_kill) {
- fuse_abort_conn(fc);
+ fuse_chan_abort(fch, false);
return;
}
@@ -1491,7 +1491,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
spin_lock(&fpq->lock);
/*
* Must not put request on fpq->io queue after having been shut down by
- * fuse_abort_conn()
+ * fuse_chan_abort()
*/
if (!fpq->connected) {
req->out.h.error = err = -ECONNABORTED;
@@ -2475,10 +2475,13 @@ static void end_polls(struct fuse_conn *fc)
* is OK, the request will in that case be removed from the list before we touch
* it.
*/
-void fuse_abort_conn(struct fuse_conn *fc)
+void fuse_chan_abort(struct fuse_conn *fc, bool abort_with_err)
{
struct fuse_iqueue *fiq = &fc->iq;
+ if (abort_with_err)
+ fc->aborted = true;
+
spin_lock(&fc->lock);
if (fc->connected) {
struct fuse_dev *fud;
@@ -2547,9 +2550,9 @@ void fuse_abort_conn(struct fuse_conn *fc)
spin_unlock(&fc->lock);
}
}
-EXPORT_SYMBOL_GPL(fuse_abort_conn);
+EXPORT_SYMBOL_GPL(fuse_chan_abort);
-void fuse_wait_aborted(struct fuse_conn *fc)
+void fuse_chan_wait_aborted(struct fuse_conn *fc)
{
/* matches implicit memory barrier in fuse_drop_waiting() */
smp_mb();
@@ -2579,7 +2582,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)
/* Are we the last open device? */
if (atomic_dec_and_test(&fc->dev_count)) {
WARN_ON(fc->iq.fasync != NULL);
- fuse_abort_conn(fc);
+ fuse_chan_abort(fc, false);
}
fuse_dev_free(fud);
}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index c288f28f6c6ea..8b745045f1ab3 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1272,8 +1272,8 @@ void fuse_request_assign_unique(struct fuse_iqueue *fiq, struct fuse_req *req);
void fuse_request_end(struct fuse_req *req);
/* Abort all requests */
-void fuse_abort_conn(struct fuse_conn *fc);
-void fuse_wait_aborted(struct fuse_conn *fc);
+void fuse_chan_abort(struct fuse_conn *fc, bool abort_with_err);
+void fuse_chan_wait_aborted(struct fuse_conn *fc);
/* Check if any requests timed out */
void fuse_check_timeout(struct work_struct *work);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index e9ed693fc7b37..399298816dea0 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -621,7 +621,7 @@ static void fuse_umount_begin(struct super_block *sb)
if (fc->no_force_umount)
return;
- fuse_abort_conn(fc);
+ fuse_chan_abort(fc, false);
// Only retire block-device-based superblocks.
if (sb->s_bdev != NULL)
@@ -2099,8 +2099,8 @@ void fuse_conn_destroy(struct fuse_mount *fm)
if (fc->destroy)
fuse_send_destroy(fm);
- fuse_abort_conn(fc);
- fuse_wait_aborted(fc);
+ fuse_chan_abort(fc, false);
+ fuse_chan_wait_aborted(fc);
if (!list_empty(&fc->entry)) {
mutex_lock(&fuse_mutex);
--
2.53.0
next prev parent reply other threads:[~2026-08-31 16:42 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-31 12:23 FAILED: patch "[PATCH] fuse: wait for FR_FINISHED on abort_on_kill to prevent" failed to apply to 6.18-stable tree gregkh
2026-08-31 16:42 ` Sasha Levin [this message]
2026-08-31 16:42 ` [PATCH 6.18.y 2/4] fuse: split off fuse_args and related definitions into a separate header Sasha Levin
2026-08-31 16:42 ` [PATCH 6.18.y 3/4] fuse: remove fm arg of args->end callback Sasha Levin
2026-08-31 16:42 ` [PATCH 6.18.y 4/4] fuse: wait for FR_FINISHED on abort_on_kill to prevent use-after-free Sasha Levin
2026-09-09 12:33 ` [PATCH 6.18.y 1/4] fuse: abort related layering cleanup Greg KH
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=20260831164256.270090-1-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=mszeredi@redhat.com \
--cc=stable@vger.kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.