summaryrefslogtreecommitdiff
path: root/fs/fuse
diff options
context:
space:
mode:
authorJoanne Koong <joannelkoong@gmail.com>2026-08-14 11:59:42 -0700
committerMiklos Szeredi <mszeredi@redhat.com>2026-08-17 17:02:37 +0200
commitebed9ea5b469588c6074f3ed5b8d8ec63c4ccf48 (patch)
treea5a0c0692f1376556683eb97184012bca52be3d9 /fs/fuse
parent6330b1f61ed1d17850fc61bdb8920ca1056e2cf9 (diff)
downloadlinux-ebed9ea5b469588c6074f3ed5b8d8ec63c4ccf48.tar.gz
linux-ebed9ea5b469588c6074f3ed5b8d8ec63c4ccf48.zip
fuse: add FUSE_IO_URING_CMD_ADD_QUEUE
fuse-over-io-uring queues are currently created lazily, as a side effect of the first FUSE_IO_URING_CMD_REGISTER command for a given qid. This ties queue creation to entry registration. Add a FUSE_IO_URING_CMD_ADD_QUEUE command so a server can create a queue explicitly, decoupling queue setup from entry registration. This is additionally a prerequisite for FUSE_IO_URING_CMD_ADD_BUFPOOL, which attaches a buffer pool to an existing queue and therefore needs the queue to have been created first. Reviewed-by: Bernd Schubert <bernd@bsbernd.com> Signed-off-by: Joanne Koong <joannelkoong@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/dev_uring.c45
1 files changed, 38 insertions, 7 deletions
diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
index 9616778505ba..3b9fd0daef66 100644
--- a/fs/fuse/dev_uring.c
+++ b/fs/fuse/dev_uring.c
@@ -281,7 +281,8 @@ void fuse_uring_conn_init(struct fuse_chan *fch)
}
static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
- int qid)
+ int qid,
+ bool fail_if_exists)
{
struct fuse_chan *fch = ring->chan;
struct fuse_ring_queue *queue;
@@ -289,11 +290,11 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
queue = kzalloc_obj(*queue, GFP_KERNEL_ACCOUNT);
if (!queue)
- return NULL;
+ return ERR_PTR(-ENOMEM);
pq = fuse_pqueue_alloc();
if (!pq) {
kfree(queue);
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
queue->qid = qid;
@@ -316,7 +317,7 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
spin_unlock(&fch->lock);
kfree(queue->fpq.processing);
kfree(queue);
- return ring->queues[qid];
+ return fail_if_exists ? ERR_PTR(-EEXIST) : ring->queues[qid];
}
/*
@@ -1189,9 +1190,9 @@ static int fuse_uring_register(struct io_uring_cmd *cmd,
queue = READ_ONCE(ring->queues[qid]);
if (!queue) {
- queue = fuse_uring_create_queue(ring, qid);
- if (!queue)
- return -ENOMEM;
+ queue = fuse_uring_create_queue(ring, qid, false);
+ if (IS_ERR(queue))
+ return PTR_ERR(queue);
}
/*
@@ -1206,6 +1207,30 @@ static int fuse_uring_register(struct io_uring_cmd *cmd,
return fuse_uring_do_register(ent, cmd, issue_flags);
}
+static int fuse_uring_add_queue(struct io_uring_cmd *cmd, struct fuse_chan *fch)
+{
+ const struct fuse_uring_cmd_req *cmd_req =
+ io_uring_sqe128_cmd(cmd->sqe, struct fuse_uring_cmd_req);
+ struct fuse_ring *ring = smp_load_acquire(&fch->ring);
+ unsigned int qid = READ_ONCE(cmd_req->qid);
+ uint64_t flags = READ_ONCE(cmd_req->flags);
+ struct fuse_ring_queue *queue;
+
+ if (!ring || flags)
+ return -EINVAL;
+
+ if (qid >= ring->nr_queues) {
+ pr_info_ratelimited("fuse: Invalid ring qid %u\n", qid);
+ return -EINVAL;
+ }
+
+ queue = fuse_uring_create_queue(ring, qid, true);
+ if (IS_ERR(queue))
+ return PTR_ERR(queue);
+
+ return 0;
+}
+
/*
* Entry function from io_uring to handle the given passthrough command
* (op code IORING_OP_URING_CMD)
@@ -1272,6 +1297,12 @@ int fuse_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
return err;
}
break;
+ case FUSE_IO_URING_CMD_ADD_QUEUE:
+ err = fuse_uring_add_queue(cmd, fch);
+ if (err)
+ pr_info_once("FUSE_IO_URING_CMD_ADD_QUEUE failed err=%d\n",
+ err);
+ return err;
default:
return -EINVAL;
}