diff options
| author | Joanne Koong <joannelkoong@gmail.com> | 2026-08-14 11:59:42 -0700 |
|---|---|---|
| committer | Miklos Szeredi <mszeredi@redhat.com> | 2026-08-17 17:02:37 +0200 |
| commit | ebed9ea5b469588c6074f3ed5b8d8ec63c4ccf48 (patch) | |
| tree | a5a0c0692f1376556683eb97184012bca52be3d9 /fs/fuse | |
| parent | 6330b1f61ed1d17850fc61bdb8920ca1056e2cf9 (diff) | |
| download | linux-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.c | 45 |
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; } |
