FAILED: patch "[PATCH] fuse: fix missing barrier when checking io-uring readiness" failed to apply to 6.18-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x edb310bc27f0ad83e7fd558a3caf1a94ca511654
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026083142-tingly-scarecrow-e145@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From edb310bc27f0ad83e7fd558a3caf1a94ca511654 Mon Sep 17 00:00:00 2001
From: Joanne Koong <[email protected]>
Date: Thu, 16 Jul 2026 11:31:42 -0700
Subject: [PATCH] fuse: fix missing barrier when checking io-uring readiness
fuse_block_alloc() reads fch->initialized and then fch->io_uring. fch->io_uring is set before fch->initialized, ordered by the smp_wmb() in fuse_chan_set_intialized(), but fuse_block_alloc() has no matching read barrier between the two loads.
This may lead a CPU to observe fch->initialized=1 but fch->io_uring=0, and skip the check that blocks request allocation until the io-uring queues are ready. This can reintroduce the lock-order inversion deadlock that commit 3393ff964e0f prevents.
Add an smp_rmb() barrier to pair with the smp_wmb() in fuse_chan_set_initialized() to prevent this.
fs/fuse/dev.c +7 -4
@@ -85,7 +85,13 @@ void fuse_chan_set_initialized(struct fuse_chan *fch, struct fuse_chan_param *pastatic bool fuse_block_alloc (struct fuse_chan *fch,bool for_background) { -return !fch->initialized || (for_background && fch->blocked) || +if (!fch->initialized) +return true; + +/* Pairs with smp_wmb() in fuse_chan_set_initialized() */ +smp_rmb (); + +return (for_background && fch->blocked) || (fch->io_uring && fch->connected && !fuse_uring_ready (fch)); }
@@ -120,9 +126,6 @@ static struct fuse_req *fuse_get_req(struct fuse_chan *fch, bool for_background) goto out; } -/* Matches smp_wmb() in fuse_chan_set_initialized() */ -smp_rmb (); - err = -ENOTCONN ;if (!fch->connected) goto out;
Sasha Levin
maintainerPATCH 1/3 fuse: split off fuse_args and related definitions into a separate header
From: Miklos Szeredi <[email protected]>
[ Upstream commit 229f9b9b66ab5be9e015422cf30b97740cfbdc8d ]
This is going to be used by both layers (transport and filesystem)
Stable-dep-of: edb310bc27f0 ("fuse: fix missing barrier when checking io-uring readiness")
--- fs/fuse/args.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 53 +-------------------------------------- 2 files changed, 66 insertions(+), 52 deletions(-) create mode 100644 fs/fuse/args.h
fs/fuse/args.h new file +65 -0
@@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _FS_FUSE_ARGS_H +#define _FS_FUSE_ARGS_H + +#include <linux/types.h> + +struct fuse_mount ; + +/** One input argument of a request */ +struct fuse_in_arg { +unsigned size; +const void *value; +}; + +/** One output argument of a request */ +struct fuse_arg { +unsigned size; +void *value; +}; + +struct fuse_args { +u64 nodeid; +u32 opcode; +u32 uid; +u32 gid; +u32 pid; +u8 in_numargs; +u8 out_numargs; +u8 ext_idx; +bool force:1 ; +bool noreply:1 ; +bool nocreds:1 ; +bool in_pages:1 ; +bool out_pages:1 ; +bool user_pages:1 ; +bool out_argvar:1 ; +bool page_zeroing:1 ; +bool page_replace:1 ; +bool may_block:1 ; +bool is_ext:1 ; +bool is_pinned:1 ; +bool invalidate_vmap:1 ; +bool abort_on_kill:1 ; +struct fuse_in_arg in_args[4 ]; +struct fuse_arg out_args[2 ]; +void (*end)(struct fuse_mount *fm,struct fuse_args *args,int error); +/* Used for kvec iter backed by vmalloc address */ +void *vmap_base; +}; + +/** FUSE folio descriptor */ +struct fuse_folio_desc { +unsigned int length; +unsigned int offset; +}; + +struct fuse_args_pages { +struct fuse_args args; +struct folio **folios; +struct fuse_folio_desc *descs; +unsigned int num_folios; +}; + +#endif /* _FS_FUSE_ARGS_H */
fs/fuse/fuse_i.h +1 -52
65 lines not on this page · raw message
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 fuse: remove fm arg of args->end callback
From: Miklos Szeredi <[email protected]>
[ Upstream commit a697d95fcdbb3bbe25cdc29db5542ddcebb831c1 ]
Only used by FUSE_INIT and CUSE_INIT, these can store the relevant pointer in their structs derived from fuse_args.
Stable-dep-of: edb310bc27f0 ("fuse: fix missing barrier when checking io-uring readiness")
--- fs/fuse/args.h | 2 +- fs/fuse/cuse.c | 7 ++++--- fs/fuse/dev.c | 7 +++---- fs/fuse/file.c | 22 +++++++++------------- fs/fuse/inode.c | 10 ++++++---- 5 files changed, 23 insertions(+), 25 deletions(-)
fs/fuse/args.h +1 -1
@@ -44,7 +44,7 @@ struct fuse_args { bool abort_on_kill:1;struct fuse_in_arg in_args[4 ];struct fuse_arg out_args[2 ]; -void (*end)(struct fuse_mount *fm,struct fuse_args *args,int error); +void (*end)(struct fuse_args *args,int error);/* Used for kvec iter backed by vmalloc address */ void *vmap_base; };
fs/fuse/cuse.c +4 -3
@@ -306,6 +306,7 @@ struct cuse_init_args {struct cuse_init_out out;struct folio *folio;struct fuse_folio_desc desc; +struct fuse_conn *fc; };/**
@@ -319,11 +320,10 @@ struct cuse_init_args {* required data structures for it. Please read the comment at the * top of this file for high level overview. */ -static void cuse_process_init_reply (struct fuse_mount *fm, -struct fuse_args *args,int error) +static void cuse_process_init_reply (struct fuse_args *args,int error) { -struct fuse_conn *fc = fm->fc;struct cuse_init_args *ia =container_of (args,typeof (*ia), ap.args); +struct fuse_conn *fc = ia->fc;struct fuse_args_pages *ap = &ia->ap;struct cuse_conn *cc =fc_to_cc (fc), *pos;struct cuse_init_out *arg = &ia->out;
@@ -468,6 +468,7 @@ static int cuse_send_init(struct cuse_conn *cc) ap->descs = &ia->desc; ia->folio = folio; ia->desc.length = ap->args.out_args[1 ].size; + ia->fc = &cc->fc; ap->args.end = cuse_process_init_reply; rc =fuse_simple_background (fm, &ap->args,GFP_KERNEL );
fs/fuse/dev.c +3 -4
@@ -512,7 +512,7 @@ void fuse_request_end(struct fuse_req *req) }if (test_bit (FR_ASYNC , &req->flags)) - req->args->end (fm, req->args, req->out.h.error); + req->args->end (req->args, req->out.h.error); put_request:fuse_put_request (req); }
@@ -1859,8 +1859,7 @@ struct fuse_retrieve_args {struct fuse_notify_retrieve_in inarg; }; -static void fuse_retrieve_end (struct fuse_mount *fm,struct fuse_args *args, -int error) +static void fuse_retrieve_end (struct fuse_args *args,int error) {struct fuse_retrieve_args *ra =container_of (args,typeof (*ra), ap.args);
@@ -1955,7 +1954,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode, err =fuse_simple_notify_reply (fm, args, outarg->notify_unique);if (err) -fuse_retrieve_end (fm, args, err); +fuse_retrieve_end (args, err);return err; }
fs/fuse/file.c +9 -13
@@ -91,8 +91,7 @@ static struct fuse_file *fuse_file_get(struct fuse_file *ff)return ff; } -static void fuse_release_end (struct fuse_mount *fm,struct fuse_args *args, -int error) +static void fuse_release_end (struct fuse_args *args,int error) {struct fuse_release_args *ra =container_of (args,typeof (*ra), args);
@@ -112,15 +111,15 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)if (!args) {/* Do nothing when server does not implement 'opendir' */ }else if (args->opcode ==FUSE_RELEASE && ff->fm->fc->no_open) { -fuse_release_end (ff->fm, args,0 ); +fuse_release_end (args,0 ); }else if (sync) {fuse_simple_request (ff->fm, args); -fuse_release_end (ff->fm, args,0 ); +fuse_release_end (args,0 ); }else { args->end = fuse_release_end;if (fuse_simple_background (ff->fm, args,GFP_KERNEL | __GFP_NOFAIL)) -fuse_release_end (ff->fm, args, -ENOTCONN ); +fuse_release_end (args, -ENOTCONN ); }kfree (ff); }
@@ -709,8 +708,7 @@ static void fuse_io_free(struct fuse_io_args *ia)kfree (ia); } -static void fuse_aio_complete_req (struct fuse_mount *fm,struct fuse_args *args, -int err) +static void fuse_aio_complete_req (struct fuse_args *args,int err) {struct fuse_io_args *ia =container_of (args,typeof (*ia), ap.args);struct fuse_io_priv *io = ia->io;
@@ -758,7 +756,7 @@ static ssize_t fuse_async_req_send(struct fuse_mount *fm, ia->ap.args.may_block = io->should_dirty; err =fuse_simple_background (fm, &ia->ap.args,GFP_KERNEL );if (err) -fuse_aio_complete_req (fm, &ia->ap.args, err); +fuse_aio_complete_req (&ia->ap.args, err);return num_bytes; }
@@ -881,8 +879,7 @@ static int fuse_iomap_read_folio_range(const struct iomap_iter *iter,return fuse_do_readfolio (file, folio, off, len); } -static void fuse_readpages_end (struct fuse_mount *fm,struct fuse_args *args, -int err) +static void fuse_readpages_end (struct fuse_args *args,int err) {int i;struct fuse_io_args *ia =container_of (args,typeof (*ia), ap.args);
@@ -947,7 +944,7 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file, res =fuse_simple_request (fm, &ap->args); err = res <0 ? res :0 ; } -fuse_readpages_end (fm, &ap->args, err); +fuse_readpages_end (&ap->args, err); }static void fuse_readahead (struct readahead_control *rac)
@@ -1950,8 +1947,7 @@ __acquires(fi->lock) } } -static void fuse_writepage_end (struct fuse_mount *fm,struct fuse_args *args, -int error) +static void fuse_writepage_end (struct fuse_args *args,int error) {struct fuse_writepage_args *wpa =container_of (args,typeof (*wpa), ia.ap.args);
fs/fuse/inode.c +6 -4
@@ -1311,13 +1311,14 @@ struct fuse_init_args {struct fuse_args args;struct fuse_init_in in;struct fuse_init_out out; +struct fuse_mount *fm; }; -static void process_init_reply (struct fuse_mount *fm,struct fuse_args *args, -int error) +static void process_init_reply (struct fuse_args *args,int error) { -struct fuse_conn *fc = fm->fc;struct fuse_init_args *ia =container_of (args,typeof (*ia), args); +struct fuse_mount *fm = ia->fm; +struct fuse_conn *fc = fm->fc;struct fuse_init_out *arg = &ia->out;bool ok = true;
@@ -1486,6 +1487,7 @@ static struct fuse_init_args *fuse_new_init(struct fuse_mount *fm) ia =kzalloc (sizeof (*ia),GFP_KERNEL | __GFP_NOFAIL); + ia->fm = fm; ia->in.major =FUSE_KERNEL_VERSION ; ia->in.minor =FUSE_KERNEL_MINOR_VERSION ; ia->in.max_readahead = fm->sb->s_bdi->ra_pages *PAGE_SIZE ;
@@ -1559,7 +1561,7 @@ int fuse_send_init(struct fuse_mount *fm)if (!err)return 0 ; } -process_init_reply (fm, &ia->args, err); +process_init_reply (&ia->args, err);if (fm->fc->conn_error)return -ENOTCONN ;return 0 ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 fuse: fix missing barrier when checking io-uring readiness
In reply to Sasha LevinFrom: Joanne Koong <[email protected]>
[ Upstream commit edb310bc27f0ad83e7fd558a3caf1a94ca511654 ]
fuse_block_alloc() reads fch->initialized and then fch->io_uring. fch->io_uring is set before fch->initialized, ordered by the smp_wmb() in fuse_chan_set_intialized(), but fuse_block_alloc() has no matching read barrier between the two loads.
This may lead a CPU to observe fch->initialized=1 but fch->io_uring=0, and skip the check that blocks request allocation until the io-uring queues are ready. This can reintroduce the lock-order inversion deadlock that commit 3393ff964e0f prevents.
Add an smp_rmb() barrier to pair with the smp_wmb() in fuse_chan_set_initialized() to prevent this.
--- fs/fuse/dev.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
fs/fuse/dev.c +7 -3
@@ -172,7 +172,13 @@ void fuse_set_initialized(struct fuse_conn *fc)static bool fuse_block_alloc (struct fuse_conn *fc,bool for_background) { -return !fc->initialized || (for_background && fc->blocked) || +if (!fc->initialized) +return true; + +/* Pairs with smp_wmb() in fuse_set_initialized() */ +smp_rmb (); + +return (for_background && fc->blocked) || (fc->io_uring && fc->connected && !fuse_uring_ready (fc)); }
@@ -212,8 +218,6 @@ static struct fuse_req *fuse_get_req(struct mnt_idmap *idmap, (TASK_KILLABLE | TASK_FREEZABLE))) goto out; } -/* Matches smp_wmb() in fuse_set_initialized() */ -smp_rmb (); err = -ENOTCONN ;if (!fc->connected)
Signature · 1 line
2.53.0