FILESYSTEM IN USERSPACE (FUSE) development
 help / color / mirror / Atom feed
* [PATCH v2 0/3] fuse: fix missing barriers in io-uring init
@ 2026-07-15 17:43 Joanne Koong
  2026-07-15 17:43 ` [PATCH v2 1/3] fuse: fix missing barrier when checking io-uring readiness Joanne Koong
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Joanne Koong @ 2026-07-15 17:43 UTC (permalink / raw)
  To: miklos, bernd; +Cc: fuse-devel

These are pre-existing issues Sashiko reported [1] on the fuse zerocopy
series.

[1] https://sashiko.dev/#/patchset/20260630211436.2062816-1-joannelkoong%40gmail.com

Changelog
---------
v1: https://lore.kernel.org/fuse-devel/20260713175345.2542331-1-joannelkoong@gmail.com/
* Fix some other pre-existing issues Sashiko found in response to v1
* Add patch for using releasing/acquire for fch->initialized to make things
  simpler

Joanne Koong (3):
  fuse: fix missing barrier when checking io-uring readiness
  fuse: use release/acquire for fch->initialized
  fuse: publish io-uring queues with release semantics

 fs/fuse/cuse.c      |  3 ++-
 fs/fuse/dev.c       | 17 +++++++++--------
 fs/fuse/dev_uring.c | 18 +++++++++++-------
 3 files changed, 22 insertions(+), 16 deletions(-)

-- 
2.52.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/3] fuse: fix missing barrier when checking io-uring readiness
  2026-07-15 17:43 [PATCH v2 0/3] fuse: fix missing barriers in io-uring init Joanne Koong
@ 2026-07-15 17:43 ` Joanne Koong
  2026-07-15 22:26   ` Bernd Schubert
  2026-07-15 17:43 ` [PATCH v2 2/3] fuse: use release/acquire for fch->initialized Joanne Koong
  2026-07-15 17:43 ` [PATCH v2 3/3] fuse: publish io-uring queues with release semantics Joanne Koong
  2 siblings, 1 reply; 8+ messages in thread
From: Joanne Koong @ 2026-07-15 17:43 UTC (permalink / raw)
  To: miklos, bernd; +Cc: fuse-devel, stable

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.

Fixes: 3393ff964e0f ("fuse: block request allocation until io-uring init is complete")
Cc: stable@vger.kernel.org
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/dev.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 5763a7cd3b37..b70c536d7e25 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -85,7 +85,13 @@ void fuse_chan_set_initialized(struct fuse_chan *fch, struct fuse_chan_param *pa
 
 static 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));
 }
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/3] fuse: use release/acquire for fch->initialized
  2026-07-15 17:43 [PATCH v2 0/3] fuse: fix missing barriers in io-uring init Joanne Koong
  2026-07-15 17:43 ` [PATCH v2 1/3] fuse: fix missing barrier when checking io-uring readiness Joanne Koong
@ 2026-07-15 17:43 ` Joanne Koong
  2026-07-15 17:43 ` [PATCH v2 3/3] fuse: publish io-uring queues with release semantics Joanne Koong
  2 siblings, 0 replies; 8+ messages in thread
From: Joanne Koong @ 2026-07-15 17:43 UTC (permalink / raw)
  To: miklos, bernd; +Cc: fuse-devel

fuse_chan_set_initialized() sets values for the connection state and
then sets fch->initialized to true, but lockless readers read
fch->initialized and if true, go to read the connection state values,
without using any barriers.

There are a few instances where this happens (fuse_uring_cmd() before
dispatching register / commit-and-fetch cmds, fuse_dev_do_wriite() for
handling notify retrieves, etc).

To make this as simple as possible, use release/acquire semantics for
writing/reading fch->initialized. Add the missing read barriers.
This is not marked for stable as these are not realistically reachable
on a well-behaved server, and buggy/malicious servers who trigger this
path fail benignly rather than crash or deadlock the kernel.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/cuse.c      |  3 ++-
 fs/fuse/dev.c       | 17 ++++++-----------
 fs/fuse/dev_uring.c |  4 +++-
 3 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index 3c15b5ba16d7..96d57735a79f 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -530,7 +530,8 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
 
 	INIT_LIST_HEAD(&cc->list);
 
-	cc->fc.chan->initialized = 1;
+	/* Pairs with smp_load_acquire() readers of fch->initialized */
+	smp_store_release(&cc->fc.chan->initialized, 1);
 	rc = cuse_send_init(cc);
 	if (rc) {
 		fuse_dev_put(fud);
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index b70c536d7e25..8b68b24af9d7 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -77,20 +77,17 @@ void fuse_chan_set_initialized(struct fuse_chan *fch, struct fuse_chan_param *pa
 		fch->max_pages = param->max_pages;
 	}
 
-	/* Make sure stores before this are seen on another CPU */
-	smp_wmb();
-	fch->initialized = 1;
+	/* Pairs with smp_load_acquire() readers of fch->initialized */
+	smp_store_release(&fch->initialized, 1);
 	wake_up_all(&fch->blocked_waitq);
 }
 
 static bool fuse_block_alloc(struct fuse_chan *fch, bool for_background)
 {
-	if (!fch->initialized)
+	/* Pairs with smp_store_release() in fuse_chan_set_initialized() */
+	if (!smp_load_acquire(&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));
 }
@@ -126,9 +123,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;
@@ -1894,7 +1888,8 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
 		 * initialized and connected state
 		 */
 		err = -EINVAL;
-		if (!fch->initialized || !fch->connected)
+		/* Pairs with smp_store_release() in fuse_chan_set_initialized() */
+		if (!smp_load_acquire(&fch->initialized) || !fch->connected)
 			goto copy_finish;
 
 		/* Don't try to move folios (yet) */
diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
index 77c8cec43d9c..51f985154aa1 100644
--- a/fs/fuse/dev_uring.c
+++ b/fs/fuse/dev_uring.c
@@ -1251,8 +1251,10 @@ int fuse_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
 	/*
 	 * fuse_uring_register() needs the ring to be initialized,
 	 * we need to know the max payload size
+	 *
+	 * Pairs with smp_store_release() in fuse_chan_set_initialized()
 	 */
-	if (!fch->initialized)
+	if (!smp_load_acquire(&fch->initialized))
 		return -EAGAIN;
 
 	switch (cmd_op) {
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/3] fuse: publish io-uring queues with release semantics
  2026-07-15 17:43 [PATCH v2 0/3] fuse: fix missing barriers in io-uring init Joanne Koong
  2026-07-15 17:43 ` [PATCH v2 1/3] fuse: fix missing barrier when checking io-uring readiness Joanne Koong
  2026-07-15 17:43 ` [PATCH v2 2/3] fuse: use release/acquire for fch->initialized Joanne Koong
@ 2026-07-15 17:43 ` Joanne Koong
  2026-07-15 22:54   ` Bernd Schubert
  2 siblings, 1 reply; 8+ messages in thread
From: Joanne Koong @ 2026-07-15 17:43 UTC (permalink / raw)
  To: miklos, bernd; +Cc: fuse-devel, stable

fuse_uring_create_queue() initializes a fuse_ring_queue and then
publishes the pointer into ring->queues[qid] with WRITE_ONCE() under the
fch->lock. There are several readers that may concurrently be fetching
that pointer locklessly and then deferencing it.

WRITE_ONCE() doesn't ensure ordering of the queue's field
initialization before the ring->queues[qid] pointer assignment. The
queue must be published with smp_store_release() so the field
initialization is guaranteed to happen before.

Readers in paths where the read may happen concurrently with the store
need to use READ_ONCE() because any race involving a plain access is
undefined.

Fixes: 24fe962c86f5 ("fuse: {io-uring} Handle SQEs - register commands")
Cc: stable@vger.kernel.org
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
 fs/fuse/dev_uring.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
index 51f985154aa1..bf9d51f2a508 100644
--- a/fs/fuse/dev_uring.c
+++ b/fs/fuse/dev_uring.c
@@ -321,9 +321,11 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
 	}
 
 	/*
-	 * write_once and lock as the caller mostly doesn't take the lock at all
+	 * fch->lock serializes concurrent creators for this qid.
+	 * smp_store_release() are for the lockless readers who must see a
+	 * fully initialized queue after &ring->queues[qid] is set
 	 */
-	WRITE_ONCE(ring->queues[qid], queue);
+	smp_store_release(&ring->queues[qid], queue);
 	spin_unlock(&fch->lock);
 
 	return queue;
@@ -434,7 +436,7 @@ static void fuse_uring_log_ent_state(struct fuse_ring *ring)
 	struct fuse_ring_ent *ent;
 
 	for (qid = 0; qid < ring->nr_queues; qid++) {
-		struct fuse_ring_queue *queue = ring->queues[qid];
+		struct fuse_ring_queue *queue = READ_ONCE(ring->queues[qid]);
 
 		if (!queue)
 			continue;
@@ -967,7 +969,7 @@ static int fuse_uring_commit_fetch(struct io_uring_cmd *cmd, int issue_flags,
 	if (qid >= ring->nr_queues)
 		return -EINVAL;
 
-	queue = ring->queues[qid];
+	queue = READ_ONCE(ring->queues[qid]);
 	if (!queue)
 		return err;
 	fpq = &queue->fpq;
@@ -1035,7 +1037,7 @@ static bool is_ring_ready(struct fuse_ring *ring, int current_qid)
 		if (current_qid == qid)
 			continue;
 
-		queue = ring->queues[qid];
+		queue = READ_ONCE(ring->queues[qid]);
 		if (!queue) {
 			ready = false;
 			break;
@@ -1191,7 +1193,7 @@ static int fuse_uring_register(struct io_uring_cmd *cmd,
 		return -EINVAL;
 	}
 
-	queue = ring->queues[qid];
+	queue = READ_ONCE(ring->queues[qid]);
 	if (!queue) {
 		queue = fuse_uring_create_queue(ring, qid);
 		if (!queue)
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/3] fuse: fix missing barrier when checking io-uring readiness
  2026-07-15 17:43 ` [PATCH v2 1/3] fuse: fix missing barrier when checking io-uring readiness Joanne Koong
@ 2026-07-15 22:26   ` Bernd Schubert
  2026-07-16 18:17     ` Joanne Koong
  0 siblings, 1 reply; 8+ messages in thread
From: Bernd Schubert @ 2026-07-15 22:26 UTC (permalink / raw)
  To: Joanne Koong, miklos; +Cc: fuse-devel, stable



On 7/15/26 19:43, Joanne Koong wrote:
> 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.
> 
> Fixes: 3393ff964e0f ("fuse: block request allocation until io-uring init is complete")
> Cc: stable@vger.kernel.org
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  fs/fuse/dev.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 5763a7cd3b37..b70c536d7e25 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -85,7 +85,13 @@ void fuse_chan_set_initialized(struct fuse_chan *fch, struct fuse_chan_param *pa
>  
>  static 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));
>  }
>  

I wonder if we could remove smp_rmb() in fuse_get_req(), it follows
fuse_block_alloc().

Otherwise,

Reviewed-by: Bernd Schubert <bernd@bsbernd.com>



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 3/3] fuse: publish io-uring queues with release semantics
  2026-07-15 17:43 ` [PATCH v2 3/3] fuse: publish io-uring queues with release semantics Joanne Koong
@ 2026-07-15 22:54   ` Bernd Schubert
  2026-07-16 18:21     ` Joanne Koong
  0 siblings, 1 reply; 8+ messages in thread
From: Bernd Schubert @ 2026-07-15 22:54 UTC (permalink / raw)
  To: Joanne Koong, miklos; +Cc: fuse-devel, stable



On 7/15/26 19:43, Joanne Koong wrote:
> fuse_uring_create_queue() initializes a fuse_ring_queue and then
> publishes the pointer into ring->queues[qid] with WRITE_ONCE() under the
> fch->lock. There are several readers that may concurrently be fetching
> that pointer locklessly and then deferencing it.
> 
> WRITE_ONCE() doesn't ensure ordering of the queue's field
> initialization before the ring->queues[qid] pointer assignment. The
> queue must be published with smp_store_release() so the field
> initialization is guaranteed to happen before.
> 
> Readers in paths where the read may happen concurrently with the store
> need to use READ_ONCE() because any race involving a plain access is
> undefined.
> 
> Fixes: 24fe962c86f5 ("fuse: {io-uring} Handle SQEs - register commands")
> Cc: stable@vger.kernel.org
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
>  fs/fuse/dev_uring.c | 14 ++++++++------
>  1 file changed, 8 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
> index 51f985154aa1..bf9d51f2a508 100644
> --- a/fs/fuse/dev_uring.c
> +++ b/fs/fuse/dev_uring.c
> @@ -321,9 +321,11 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
>  	}
>  
>  	/*
> -	 * write_once and lock as the caller mostly doesn't take the lock at all
> +	 * fch->lock serializes concurrent creators for this qid.
> +	 * smp_store_release() are for the lockless readers who must see a
> +	 * fully initialized queue after &ring->queues[qid] is set
>  	 */
> -	WRITE_ONCE(ring->queues[qid], queue);
> +	smp_store_release(&ring->queues[qid], queue);
>  	spin_unlock(&fch->lock);
>  
>  	return queue;
> @@ -434,7 +436,7 @@ static void fuse_uring_log_ent_state(struct fuse_ring *ring)
>  	struct fuse_ring_ent *ent;
>  
>  	for (qid = 0; qid < ring->nr_queues; qid++) {
> -		struct fuse_ring_queue *queue = ring->queues[qid];
> +		struct fuse_ring_queue *queue = READ_ONCE(ring->queues[qid]);
>  
>  		if (!queue)
>  			continue;
> @@ -967,7 +969,7 @@ static int fuse_uring_commit_fetch(struct io_uring_cmd *cmd, int issue_flags,
>  	if (qid >= ring->nr_queues)
>  		return -EINVAL;
>  
> -	queue = ring->queues[qid];
> +	queue = READ_ONCE(ring->queues[qid]);
>  	if (!queue)
>  		return err;
>  	fpq = &queue->fpq;
> @@ -1035,7 +1037,7 @@ static bool is_ring_ready(struct fuse_ring *ring, int current_qid)
>  		if (current_qid == qid)
>  			continue;
>  
> -		queue = ring->queues[qid];
> +		queue = READ_ONCE(ring->queues[qid]);
>  		if (!queue) {
>  			ready = false;
>  			break;
> @@ -1191,7 +1193,7 @@ static int fuse_uring_register(struct io_uring_cmd *cmd,
>  		return -EINVAL;
>  	}
>  
> -	queue = ring->queues[qid];
> +	queue = READ_ONCE(ring->queues[qid]);
>  	if (!queue) {
>  		queue = fuse_uring_create_queue(ring, qid);
>  		if (!queue)


For consistency, maybe READ_ONCE/WRITE_ONCE in fuse_uring_destruct?
Otherwise,

Reviewed-by: Bernd Schubert <bernd@bsbernd.com>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/3] fuse: fix missing barrier when checking io-uring readiness
  2026-07-15 22:26   ` Bernd Schubert
@ 2026-07-16 18:17     ` Joanne Koong
  0 siblings, 0 replies; 8+ messages in thread
From: Joanne Koong @ 2026-07-16 18:17 UTC (permalink / raw)
  To: Bernd Schubert; +Cc: miklos, fuse-devel, stable

On Wed, Jul 15, 2026 at 3:26 PM Bernd Schubert <bernd@bsbernd.com> wrote:
>
> On 7/15/26 19:43, Joanne Koong wrote:
> > 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.
> >
> > Fixes: 3393ff964e0f ("fuse: block request allocation until io-uring init is complete")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
> >  fs/fuse/dev.c | 8 +++++++-
> >  1 file changed, 7 insertions(+), 1 deletion(-)
> >
> > diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> > index 5763a7cd3b37..b70c536d7e25 100644
> > --- a/fs/fuse/dev.c
> > +++ b/fs/fuse/dev.c
> > @@ -85,7 +85,13 @@ void fuse_chan_set_initialized(struct fuse_chan *fch, struct fuse_chan_param *pa
> >
> >  static 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));
> >  }
> >
>
> I wonder if we could remove smp_rmb() in fuse_get_req(), it follows
> fuse_block_alloc().

Nicely spotted. This is removed in the 2nd patch ("fuse: use
release/acquire for fch->initialized") but I can move deleting that
line into this patch.

Thanks,
Joanne

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 3/3] fuse: publish io-uring queues with release semantics
  2026-07-15 22:54   ` Bernd Schubert
@ 2026-07-16 18:21     ` Joanne Koong
  0 siblings, 0 replies; 8+ messages in thread
From: Joanne Koong @ 2026-07-16 18:21 UTC (permalink / raw)
  To: Bernd Schubert; +Cc: miklos, fuse-devel, stable

On Wed, Jul 15, 2026 at 3:54 PM Bernd Schubert <bernd@bsbernd.com> wrote:
>
>
>
> On 7/15/26 19:43, Joanne Koong wrote:
> > fuse_uring_create_queue() initializes a fuse_ring_queue and then
> > publishes the pointer into ring->queues[qid] with WRITE_ONCE() under the
> > fch->lock. There are several readers that may concurrently be fetching
> > that pointer locklessly and then deferencing it.
> >
> > WRITE_ONCE() doesn't ensure ordering of the queue's field
> > initialization before the ring->queues[qid] pointer assignment. The
> > queue must be published with smp_store_release() so the field
> > initialization is guaranteed to happen before.
> >
> > Readers in paths where the read may happen concurrently with the store
> > need to use READ_ONCE() because any race involving a plain access is
> > undefined.
> >
> > Fixes: 24fe962c86f5 ("fuse: {io-uring} Handle SQEs - register commands")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
> >  fs/fuse/dev_uring.c | 14 ++++++++------
> >  1 file changed, 8 insertions(+), 6 deletions(-)
> >
> > diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
> > index 51f985154aa1..bf9d51f2a508 100644
> > --- a/fs/fuse/dev_uring.c
> > +++ b/fs/fuse/dev_uring.c
> > @@ -321,9 +321,11 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
> >       }
> >
> >       /*
> > -      * write_once and lock as the caller mostly doesn't take the lock at all
> > +      * fch->lock serializes concurrent creators for this qid.
> > +      * smp_store_release() are for the lockless readers who must see a
> > +      * fully initialized queue after &ring->queues[qid] is set
> >        */
> > -     WRITE_ONCE(ring->queues[qid], queue);
> > +     smp_store_release(&ring->queues[qid], queue);
> >       spin_unlock(&fch->lock);
> >
> >       return queue;
> > @@ -434,7 +436,7 @@ static void fuse_uring_log_ent_state(struct fuse_ring *ring)
> >       struct fuse_ring_ent *ent;
> >
> >       for (qid = 0; qid < ring->nr_queues; qid++) {
> > -             struct fuse_ring_queue *queue = ring->queues[qid];
> > +             struct fuse_ring_queue *queue = READ_ONCE(ring->queues[qid]);
> >
> >               if (!queue)
> >                       continue;
> > @@ -967,7 +969,7 @@ static int fuse_uring_commit_fetch(struct io_uring_cmd *cmd, int issue_flags,
> >       if (qid >= ring->nr_queues)
> >               return -EINVAL;
> >
> > -     queue = ring->queues[qid];
> > +     queue = READ_ONCE(ring->queues[qid]);
> >       if (!queue)
> >               return err;
> >       fpq = &queue->fpq;
> > @@ -1035,7 +1037,7 @@ static bool is_ring_ready(struct fuse_ring *ring, int current_qid)
> >               if (current_qid == qid)
> >                       continue;
> >
> > -             queue = ring->queues[qid];
> > +             queue = READ_ONCE(ring->queues[qid]);
> >               if (!queue) {
> >                       ready = false;
> >                       break;
> > @@ -1191,7 +1193,7 @@ static int fuse_uring_register(struct io_uring_cmd *cmd,
> >               return -EINVAL;
> >       }
> >
> > -     queue = ring->queues[qid];
> > +     queue = READ_ONCE(ring->queues[qid]);
> >       if (!queue) {
> >               queue = fuse_uring_create_queue(ring, qid);
> >               if (!queue)
>
>
> For consistency, maybe READ_ONCE/WRITE_ONCE in fuse_uring_destruct?

I didn't add it because I don't think it's necessary (because
fuse_uring_destruct can only run after the queue has been created),
but I can add it to make things more uniform, if you have a preference
for one way or the other. I'll send out v3 with this change.

Thanks,
Joanne

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-07-16 18:21 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-15 17:43 [PATCH v2 0/3] fuse: fix missing barriers in io-uring init Joanne Koong
2026-07-15 17:43 ` [PATCH v2 1/3] fuse: fix missing barrier when checking io-uring readiness Joanne Koong
2026-07-15 22:26   ` Bernd Schubert
2026-07-16 18:17     ` Joanne Koong
2026-07-15 17:43 ` [PATCH v2 2/3] fuse: use release/acquire for fch->initialized Joanne Koong
2026-07-15 17:43 ` [PATCH v2 3/3] fuse: publish io-uring queues with release semantics Joanne Koong
2026-07-15 22:54   ` Bernd Schubert
2026-07-16 18:21     ` Joanne Koong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox