FILESYSTEM IN USERSPACE (FUSE) development
 help / color / mirror / Atom feed
* [PATCH v2] fuse: Fix the condition to enable over-io-uring
@ 2026-08-21 16:19 Bernd Schubert via B4 Relay
  2026-08-24  7:59 ` Baokun Li
  0 siblings, 1 reply; 2+ messages in thread
From: Bernd Schubert via B4 Relay @ 2026-08-21 16:19 UTC (permalink / raw)
  To: Miklos Szeredi, Bernd Schubert
  Cc: Joanne Koong, fuse-devel, Baokun Li, Thomas, zhu, Stefan Hajnoczi,
	stable

From: Bernd Schubert <bernd@bsbernd.com>

The existing condition in fuse_uring_cmd() is there only to avoid
disabling io-uring for connections that already run with it, missing
was a condition to refuse any IORING_OP_URING_CMD if the
connection/channel didn't get enabled because of missing FUSE_INIT
reply flag FUSE_OVER_IO_URING. Without the reply flag the barrier in
fuse_uring_ready() doesn't work and IO could already be going on and
cause deadlock states (at a minimum one between fch->bg_lock and
queue->lock).

The change itself is trivial, but brings behavior change,
FUSE_OVER_IO_URING has to be set in the FUSE_INIT_REPLY by fuse servers
to accept any IORING_OP_URING_CMD. Libfuse does that and the only
non-libfuse implementation I found (fractal-fuse) also does it.
Qemu patches for fuse-io-uring are not merged yet, as far as I know.

Moved up is the smp_load_acquire(&fch->initialized) check, as a
fuse-server implementation might try to setup io-uring before FUSE_INIT
is processed and might have gotten -EOPNOTSUPP instead of -EAGAIN.

Also fixed is a stale comment that explains the handling of the
FUSE_OVER_IO_URING flag in early RFC versions.

If there should be a report from any library or application we
probably need to revert this commit.

Fixes: 3393ff964e0f ("fuse: block request allocation until io-uring init is complete")
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
---
Changes in v2:
- Seperate condition for fch->io_uring, switching from "&&" to "||" would have
  brought up another regression.
- Commit message update, fortunately bypassing the module option
  wasn't possible because of another check in process_init_reply()
- Link to v1: https://patch.msgid.link/20260821-fuse-fix-enable-condition-v1-1-488f77b27e96@bsbernd.com
---
 fs/fuse/dev_uring.c | 31 ++++++++++++++++++-------------
 fs/fuse/inode.c     |  4 ----
 2 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
index e22a48c9a678..c6dd420c4034 100644
--- a/fs/fuse/dev_uring.c
+++ b/fs/fuse/dev_uring.c
@@ -1665,25 +1665,30 @@ int fuse_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
 	}
 	fch = fud->chan;
 
-	/* Once a connection has io-uring enabled on it, it can't be disabled */
-	if (!enable_uring && !fch->io_uring) {
-		pr_info_ratelimited("fuse-io-uring is disabled\n");
-		return -EOPNOTSUPP;
-	}
+	/*
+	 * The ring is sized from values negotiated by FUSE_INIT
+	 *
+	 * Pairs with smp_store_release() in fuse_chan_set_initialized()
+	 */
+	if (!smp_load_acquire(&fch->initialized))
+		return -EAGAIN;
 
 	if (fch->abort_with_err)
 		return -ECONNABORTED;
 	if (!fch->connected)
 		return -ENOTCONN;
 
-	/*
-	 * 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 (!smp_load_acquire(&fch->initialized))
-		return -EAGAIN;
+	/* Once a connection has io-uring enabled on it, it can't be disabled */
+	if (!enable_uring && !fch->io_uring) {
+		pr_info_ratelimited("fuse-io-uring is disabled by module parameter\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (!fch->io_uring) {
+		pr_info_ratelimited(
+			"fuse-io-uring not enabled on this connection\n");
+		return -EOPNOTSUPP;
+	}
 
 	switch (cmd_op) {
 	case FUSE_IO_URING_CMD_REGISTER:
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 1c6ee01c6796..e9552be3637b 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1480,10 +1480,6 @@ static struct fuse_init_args *fuse_new_init(struct fuse_mount *fm)
 	if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
 		flags |= FUSE_PASSTHROUGH;
 
-	/*
-	 * This is just an information flag for fuse server. No need to check
-	 * the reply - server is either sending IORING_OP_URING_CMD or not.
-	 */
 	if (fuse_uring_enabled())
 		flags |= FUSE_OVER_IO_URING | FUSE_HAS_IO_URING_BUFPOOL;
 

---
base-commit: d1dbc59200b54944f00251ca4dfbb2b318beca13
change-id: 20260821-fuse-fix-enable-condition-df87aa4c25c8

Best regards,
--  
Bernd Schubert <bernd@bsbernd.com>



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

* Re: [PATCH v2] fuse: Fix the condition to enable over-io-uring
  2026-08-21 16:19 [PATCH v2] fuse: Fix the condition to enable over-io-uring Bernd Schubert via B4 Relay
@ 2026-08-24  7:59 ` Baokun Li
  0 siblings, 0 replies; 2+ messages in thread
From: Baokun Li @ 2026-08-24  7:59 UTC (permalink / raw)
  To: bernd
  Cc: Miklos Szeredi, Joanne Koong, fuse-devel, Thomas, zhu,
	Stefan Hajnoczi, stable

Hi Bernd,

On 2026/8/22 00:19, Bernd Schubert via B4 Relay wrote:
> + /* Once a connection has io-uring enabled on it, it can't be disabled */
> + if (!enable_uring && !fch->io_uring) {
> + pr_info_ratelimited("fuse-io-uring is disabled by module parameter\n");
> + return -EOPNOTSUPP;
> + }
> +
> + if (!fch->io_uring) {
> + pr_info_ratelimited(
> + "fuse-io-uring not enabled on this connection\n");
> + return -EOPNOTSUPP;
> + }

This combined with the REGISTER error path can hang IO when the ring is
already operational.  E.g. 100 entries, the 100th REGISTER fails after
ring->ready is set:

  new request:                        server fetch:
  fuse_send_one()                     IORING_OP_URING_CMD
    fiq->ops->send_req()                fuse_uring_cmd()
      fuse_uring_queue_fuse_req()         if (!fch->io_uring)  // == 0
        -> queued, no consumer              return -EOPNOTSUPP

The error path clears fch->io_uring but never reverts fiq->ops, so
requests keep flowing into io_uring queues while COMMIT_AND_FETCH is
rejected for all 99 active entries.

Maybe only tear down if the ring never became ready:

      if (err) {
          if (!fuse_uring_ready(fch)) {
              fch->io_uring = 0;
              wake_up_all(&fch->blocked_waitq);
              pr_info("[%u] fuse-io-uring disabled on connection err=%d\n",
                      fch->conn->dev, err);
          }
          return err;
      }


Regards,
Baokun



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

end of thread, other threads:[~2026-08-24  7:59 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21 16:19 [PATCH v2] fuse: Fix the condition to enable over-io-uring Bernd Schubert via B4 Relay
2026-08-24  7:59 ` Baokun Li

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