[PATCH v1 2/2] fuse: publish io-uring queues with release semantics

Joanne Koong <[email protected]> Mon, 13 Jul 2026 10:53:45 -0700
Newsgroups dev.linux.lists.fuse-devel,org.kernel.vger.stable
Message-ID <[email protected]>
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. On the reader side, fuse_uring_register() reads that pointer
on a fast path locklessly with

	queue = ring->queues[qid];

There's no barrier that orders the initialization/setup of the queue's
fields and the WRITE_ONCE() that publishes the queue. As a result, the
lockless concurrent reader can see a non-null queue but uninitialized
queue fields (eg spinlock and list heads) and then operate on
uninitialized memory.

Publish the queue with smp_store_release() and read it on the lockless
fast path with smp_load_acquire().

Fixes: 24fe962c86f5 ("fuse: {io-uring} Handle SQEs - register commands")
Cc: [email protected]
Signed-off-by: Joanne Koong <[email protected]>
---
 fs/fuse/dev_uring.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
index 77c8cec43d9c..0ea142d6670b 100644
--- a/fs/fuse/dev_uring.c
+++ b/fs/fuse/dev_uring.c
@@ -321,9 +321,12 @@ 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() is for the lockless reader in
+	 * fuse_uring_register(), which pairs it with smp_load_acquire() and
+	 * must see the fully initialized queue if it sees a non-null queue
 	 */
-	WRITE_ONCE(ring->queues[qid], queue);
+	smp_store_release(&ring->queues[qid], queue);
 	spin_unlock(&fch->lock);
 
 	return queue;
@@ -1191,7 +1194,8 @@ static int fuse_uring_register(struct io_uring_cmd *cmd,
 		return -EINVAL;
 	}
 
-	queue = ring->queues[qid];
+	/* Pairs with smp_store_release() in fuse_uring_create_queue() */
+	queue = smp_load_acquire(&ring->queues[qid]);
 	if (!queue) {
 		queue = fuse_uring_create_queue(ring, qid);
 		if (!queue)
-- 
2.52.0