mirror of
https://github.com/torvalds/linux.git
synced 2025-11-01 00:58:39 +02:00
io_uring: uring_cmd: add multishot support
Add UAPI flag IORING_URING_CMD_MULTISHOT for supporting multishot uring_cmd operations with provided buffer. This enables drivers to post multiple completion events from a single uring_cmd submission, which is useful for: - Notifying userspace of device events (e.g., interrupt handling) - Supporting devices with multiple event sources (e.g., multi-queue devices) - Avoiding the need for device poll() support when events originate from multiple sources device-wide The implementation adds two new APIs: - io_uring_cmd_select_buffer(): selects a buffer from the provided buffer group for multishot uring_cmd - io_uring_mshot_cmd_post_cqe(): posts a CQE after event data is pushed to the provided buffer Multishot uring_cmd must be used with buffer select (IOSQE_BUFFER_SELECT) and is mutually exclusive with IORING_URING_CMD_FIXED for now. The ublk driver will be the first user of this functionality: https://github.com/ming1/linux/commits/ublk-devel/ Signed-off-by: Ming Lei <ming.lei@redhat.com> Link: https://lore.kernel.org/r/20250821040210.1152145-3-ming.lei@redhat.com [axboe: fold in fix for !CONFIG_IO_URING] Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
d589bcddaa
commit
620a50c927
4 changed files with 102 additions and 2 deletions
|
|
@ -70,6 +70,21 @@ void io_uring_cmd_mark_cancelable(struct io_uring_cmd *cmd,
|
|||
/* Execute the request from a blocking context */
|
||||
void io_uring_cmd_issue_blocking(struct io_uring_cmd *ioucmd);
|
||||
|
||||
/*
|
||||
* Select a buffer from the provided buffer group for multishot uring_cmd.
|
||||
* Returns the selected buffer address and size.
|
||||
*/
|
||||
struct io_br_sel io_uring_cmd_buffer_select(struct io_uring_cmd *ioucmd,
|
||||
unsigned buf_group, size_t *len,
|
||||
unsigned int issue_flags);
|
||||
|
||||
/*
|
||||
* Complete a multishot uring_cmd event. This will post a CQE to the completion
|
||||
* queue and update the provided buffer.
|
||||
*/
|
||||
bool io_uring_mshot_cmd_post_cqe(struct io_uring_cmd *ioucmd,
|
||||
struct io_br_sel *sel, unsigned int issue_flags);
|
||||
|
||||
#else
|
||||
static inline int
|
||||
io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
|
||||
|
|
@ -102,6 +117,17 @@ static inline void io_uring_cmd_mark_cancelable(struct io_uring_cmd *cmd,
|
|||
static inline void io_uring_cmd_issue_blocking(struct io_uring_cmd *ioucmd)
|
||||
{
|
||||
}
|
||||
static inline struct io_br_sel
|
||||
io_uring_cmd_buffer_select(struct io_uring_cmd *ioucmd, unsigned buf_group,
|
||||
size_t *len, unsigned int issue_flags)
|
||||
{
|
||||
return (struct io_br_sel) { .val = -EOPNOTSUPP };
|
||||
}
|
||||
static inline bool io_uring_mshot_cmd_post_cqe(struct io_uring_cmd *ioucmd,
|
||||
ssize_t ret, unsigned int issue_flags)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -298,9 +298,13 @@ enum io_uring_op {
|
|||
* sqe->uring_cmd_flags top 8bits aren't available for userspace
|
||||
* IORING_URING_CMD_FIXED use registered buffer; pass this flag
|
||||
* along with setting sqe->buf_index.
|
||||
* IORING_URING_CMD_MULTISHOT must be used with buffer select, like other
|
||||
* multishot commands. Not compatible with
|
||||
* IORING_URING_CMD_FIXED, for now.
|
||||
*/
|
||||
#define IORING_URING_CMD_FIXED (1U << 0)
|
||||
#define IORING_URING_CMD_MASK IORING_URING_CMD_FIXED
|
||||
#define IORING_URING_CMD_MULTISHOT (1U << 1)
|
||||
#define IORING_URING_CMD_MASK (IORING_URING_CMD_FIXED | IORING_URING_CMD_MULTISHOT)
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -413,6 +413,7 @@ const struct io_issue_def io_issue_defs[] = {
|
|||
#endif
|
||||
},
|
||||
[IORING_OP_URING_CMD] = {
|
||||
.buffer_select = 1,
|
||||
.needs_file = 1,
|
||||
.plug = 1,
|
||||
.iopoll = 1,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "io_uring.h"
|
||||
#include "alloc_cache.h"
|
||||
#include "rsrc.h"
|
||||
#include "kbuf.h"
|
||||
#include "uring_cmd.h"
|
||||
#include "poll.h"
|
||||
|
||||
|
|
@ -194,8 +195,21 @@ int io_uring_cmd_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
if (ioucmd->flags & ~IORING_URING_CMD_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
if (ioucmd->flags & IORING_URING_CMD_FIXED)
|
||||
if (ioucmd->flags & IORING_URING_CMD_FIXED) {
|
||||
if (ioucmd->flags & IORING_URING_CMD_MULTISHOT)
|
||||
return -EINVAL;
|
||||
req->buf_index = READ_ONCE(sqe->buf_index);
|
||||
}
|
||||
|
||||
if (ioucmd->flags & IORING_URING_CMD_MULTISHOT) {
|
||||
if (ioucmd->flags & IORING_URING_CMD_FIXED)
|
||||
return -EINVAL;
|
||||
if (!(req->flags & REQ_F_BUFFER_SELECT))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (req->flags & REQ_F_BUFFER_SELECT)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ioucmd->cmd_op = READ_ONCE(sqe->cmd_op);
|
||||
|
||||
|
|
@ -251,6 +265,10 @@ int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
|
|||
}
|
||||
|
||||
ret = file->f_op->uring_cmd(ioucmd, issue_flags);
|
||||
if (ioucmd->flags & IORING_URING_CMD_MULTISHOT) {
|
||||
if (ret >= 0)
|
||||
return IOU_ISSUE_SKIP_COMPLETE;
|
||||
}
|
||||
if (ret == -EAGAIN) {
|
||||
ioucmd->flags |= IORING_URING_CMD_REISSUE;
|
||||
return ret;
|
||||
|
|
@ -333,3 +351,54 @@ bool io_uring_cmd_post_mshot_cqe32(struct io_uring_cmd *cmd,
|
|||
return false;
|
||||
return io_req_post_cqe32(req, cqe);
|
||||
}
|
||||
|
||||
/*
|
||||
* Work with io_uring_mshot_cmd_post_cqe() together for committing the
|
||||
* provided buffer upfront
|
||||
*/
|
||||
struct io_br_sel io_uring_cmd_buffer_select(struct io_uring_cmd *ioucmd,
|
||||
unsigned buf_group, size_t *len,
|
||||
unsigned int issue_flags)
|
||||
{
|
||||
struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
|
||||
|
||||
if (!(ioucmd->flags & IORING_URING_CMD_MULTISHOT))
|
||||
return (struct io_br_sel) { .val = -EINVAL };
|
||||
|
||||
if (WARN_ON_ONCE(!io_do_buffer_select(req)))
|
||||
return (struct io_br_sel) { .val = -EINVAL };
|
||||
|
||||
return io_buffer_select(req, len, buf_group, issue_flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(io_uring_cmd_buffer_select);
|
||||
|
||||
/*
|
||||
* Return true if this multishot uring_cmd needs to be completed, otherwise
|
||||
* the event CQE is posted successfully.
|
||||
*
|
||||
* This function must use `struct io_br_sel` returned from
|
||||
* io_uring_cmd_buffer_select() for committing the buffer in the same
|
||||
* uring_cmd submission context.
|
||||
*/
|
||||
bool io_uring_mshot_cmd_post_cqe(struct io_uring_cmd *ioucmd,
|
||||
struct io_br_sel *sel, unsigned int issue_flags)
|
||||
{
|
||||
struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
|
||||
unsigned int cflags = 0;
|
||||
|
||||
if (!(ioucmd->flags & IORING_URING_CMD_MULTISHOT))
|
||||
return true;
|
||||
|
||||
if (sel->val > 0) {
|
||||
cflags = io_put_kbuf(req, sel->val, sel->buf_list);
|
||||
if (io_req_post_cqe(req, sel->val, cflags | IORING_CQE_F_MORE))
|
||||
return false;
|
||||
}
|
||||
|
||||
io_kbuf_recycle(req, sel->buf_list, issue_flags);
|
||||
if (sel->val < 0)
|
||||
req_set_fail(req);
|
||||
io_req_set_res(req, sel->val, cflags);
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(io_uring_mshot_cmd_post_cqe);
|
||||
|
|
|
|||
Loading…
Reference in a new issue