* [PATCH V5 0/2] io_uring: uring_cmd: add multishot support with provided buffer
@ 2025-08-21 4:02 Ming Lei
2025-08-21 4:02 ` [PATCH V5 1/2] io-uring: move `struct io_br_sel` into io_uring_types.h Ming Lei
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Ming Lei @ 2025-08-21 4:02 UTC (permalink / raw)
To: Jens Axboe, io-uring, Pavel Begunkov; +Cc: Caleb Sander Mateos, Ming Lei
Hi Jens,
This patchset adds multishot support with provided buffer, see details in
commit log of patch 2.
Thanks,
Ming
V5:
- rebase on block/io_uring-buf-list and use 'struct io_br_sel' to build the two APIs
- add patch 1 for moving `struct io_br_sel` to `linux/io_uring_types.h`
V4:
- add io_do_buffer_select() check in io_uring_cmd_select_buffer(()
- comments that the two APIs should work together for committing buffer
upfront(Jens)
V3:
- enhance buffer select check(Jens)
V2:
- Fixed static inline return type
- Updated UAPI comments: Clarified that IORING_URING_CMD_MULTISHOT must be used with buffer select
- Refactored validation checks: Moved the mutual exclusion checks into the individual flag validation
sections for better code organization
- Added missing req_set_fail(): Added the missing failure handling in io_uring_mshot_cmd_post_cqe
- Improved commit message: Rewrote the commit message to be clearer, more technical, and better explain
the use cases and API changes
Ming Lei (2):
io-uring: move `struct io_br_sel` into io_uring_types.h
io_uring: uring_cmd: add multishot support
include/linux/io_uring/cmd.h | 27 +++++++++++++
include/linux/io_uring_types.h | 19 +++++++++
include/uapi/linux/io_uring.h | 6 ++-
io_uring/kbuf.h | 18 ---------
io_uring/opdef.c | 1 +
io_uring/uring_cmd.c | 71 +++++++++++++++++++++++++++++++++-
6 files changed, 122 insertions(+), 20 deletions(-)
--
2.47.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V5 1/2] io-uring: move `struct io_br_sel` into io_uring_types.h
2025-08-21 4:02 [PATCH V5 0/2] io_uring: uring_cmd: add multishot support with provided buffer Ming Lei
@ 2025-08-21 4:02 ` Ming Lei
2025-08-21 4:02 ` [PATCH V5 2/2] io_uring: uring_cmd: add multishot support Ming Lei
2025-08-21 11:41 ` [PATCH V5 0/2] io_uring: uring_cmd: add multishot support with provided buffer Jens Axboe
2 siblings, 0 replies; 11+ messages in thread
From: Ming Lei @ 2025-08-21 4:02 UTC (permalink / raw)
To: Jens Axboe, io-uring, Pavel Begunkov; +Cc: Caleb Sander Mateos, Ming Lei
Move `struct io_br_sel` into io_uring_types.h and prepare for supporting
provided buffer on uring_cmd.
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
include/linux/io_uring_types.h | 19 +++++++++++++++++++
io_uring/kbuf.h | 18 ------------------
2 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/include/linux/io_uring_types.h b/include/linux/io_uring_types.h
index 1d33984611bc..9c6c548f43f5 100644
--- a/include/linux/io_uring_types.h
+++ b/include/linux/io_uring_types.h
@@ -85,6 +85,25 @@ struct io_mapped_region {
unsigned flags;
};
+/*
+ * Return value from io_buffer_list selection, to avoid stashing it in
+ * struct io_kiocb. For legacy/classic provided buffers, keeping a reference
+ * across execution contexts are fine. But for ring provided buffers, the
+ * list may go away as soon as ->uring_lock is dropped. As the io_kiocb
+ * persists, it's better to just keep the buffer local for those cases.
+ */
+struct io_br_sel {
+ struct io_buffer_list *buf_list;
+ /*
+ * Some selection parts return the user address, others return an error.
+ */
+ union {
+ void __user *addr;
+ ssize_t val;
+ };
+};
+
+
/*
* Arbitrary limit, can be raised if need be
*/
diff --git a/io_uring/kbuf.h b/io_uring/kbuf.h
index 32f73adbe1e9..ada382ff38d7 100644
--- a/io_uring/kbuf.h
+++ b/io_uring/kbuf.h
@@ -62,24 +62,6 @@ struct buf_sel_arg {
unsigned short partial_map;
};
-/*
- * Return value from io_buffer_list selection, to avoid stashing it in
- * struct io_kiocb. For legacy/classic provided buffers, keeping a reference
- * across execution contexts are fine. But for ring provided buffers, the
- * list may go away as soon as ->uring_lock is dropped. As the io_kiocb
- * persists, it's better to just keep the buffer local for those cases.
- */
-struct io_br_sel {
- struct io_buffer_list *buf_list;
- /*
- * Some selection parts return the user address, others return an error.
- */
- union {
- void __user *addr;
- ssize_t val;
- };
-};
-
struct io_br_sel io_buffer_select(struct io_kiocb *req, size_t *len,
unsigned buf_group, unsigned int issue_flags);
int io_buffers_select(struct io_kiocb *req, struct buf_sel_arg *arg,
--
2.47.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH V5 2/2] io_uring: uring_cmd: add multishot support
2025-08-21 4:02 [PATCH V5 0/2] io_uring: uring_cmd: add multishot support with provided buffer Ming Lei
2025-08-21 4:02 ` [PATCH V5 1/2] io-uring: move `struct io_br_sel` into io_uring_types.h Ming Lei
@ 2025-08-21 4:02 ` Ming Lei
2025-08-21 16:23 ` Caleb Sander Mateos
2025-08-21 16:29 ` Caleb Sander Mateos
2025-08-21 11:41 ` [PATCH V5 0/2] io_uring: uring_cmd: add multishot support with provided buffer Jens Axboe
2 siblings, 2 replies; 11+ messages in thread
From: Ming Lei @ 2025-08-21 4:02 UTC (permalink / raw)
To: Jens Axboe, io-uring, Pavel Begunkov; +Cc: Caleb Sander Mateos, Ming Lei
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>
---
include/linux/io_uring/cmd.h | 27 +++++++++++++
include/uapi/linux/io_uring.h | 6 ++-
io_uring/opdef.c | 1 +
io_uring/uring_cmd.c | 71 ++++++++++++++++++++++++++++++++++-
4 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/include/linux/io_uring/cmd.h b/include/linux/io_uring/cmd.h
index cfa6d0c0c322..856d343b8e2a 100644
--- a/include/linux/io_uring/cmd.h
+++ b/include/linux/io_uring/cmd.h
@@ -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,18 @@ 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 int io_uring_cmd_select_buffer(struct io_uring_cmd *ioucmd,
+ unsigned buf_group,
+ void **buf, size_t *len,
+ unsigned int issue_flags)
+{
+ return -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
/*
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 6957dc539d83..1e935f8901c5 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -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)
/*
diff --git a/io_uring/opdef.c b/io_uring/opdef.c
index 9568785810d9..932319633eac 100644
--- a/io_uring/opdef.c
+++ b/io_uring/opdef.c
@@ -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,
diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
index 053bac89b6c0..3cfb5d51b88a 100644
--- a/io_uring/uring_cmd.c
+++ b/io_uring/uring_cmd.c
@@ -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);
--
2.47.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH V5 0/2] io_uring: uring_cmd: add multishot support with provided buffer
2025-08-21 4:02 [PATCH V5 0/2] io_uring: uring_cmd: add multishot support with provided buffer Ming Lei
2025-08-21 4:02 ` [PATCH V5 1/2] io-uring: move `struct io_br_sel` into io_uring_types.h Ming Lei
2025-08-21 4:02 ` [PATCH V5 2/2] io_uring: uring_cmd: add multishot support Ming Lei
@ 2025-08-21 11:41 ` Jens Axboe
2025-08-21 11:44 ` Jens Axboe
2 siblings, 1 reply; 11+ messages in thread
From: Jens Axboe @ 2025-08-21 11:41 UTC (permalink / raw)
To: io-uring, Pavel Begunkov, Ming Lei; +Cc: Caleb Sander Mateos
On Thu, 21 Aug 2025 12:02:05 +0800, Ming Lei wrote:
> This patchset adds multishot support with provided buffer, see details in
> commit log of patch 2.
>
> Thanks,
> Ming
>
>
> [...]
Applied, thanks!
[1/2] io-uring: move `struct io_br_sel` into io_uring_types.h
commit: 1a8ceff033519eac7bb5ab1d910e9b0340835c0d
[2/2] io_uring: uring_cmd: add multishot support
commit: 55dc643dd2ad15e755a706980692a374de1bb7a8
Best regards,
--
Jens Axboe
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V5 0/2] io_uring: uring_cmd: add multishot support with provided buffer
2025-08-21 11:41 ` [PATCH V5 0/2] io_uring: uring_cmd: add multishot support with provided buffer Jens Axboe
@ 2025-08-21 11:44 ` Jens Axboe
0 siblings, 0 replies; 11+ messages in thread
From: Jens Axboe @ 2025-08-21 11:44 UTC (permalink / raw)
To: io-uring, Pavel Begunkov, Ming Lei; +Cc: Caleb Sander Mateos
On 8/21/25 5:41 AM, Jens Axboe wrote:
>
> On Thu, 21 Aug 2025 12:02:05 +0800, Ming Lei wrote:
>> This patchset adds multishot support with provided buffer, see details in
>> commit log of patch 2.
>>
>> Thanks,
>> Ming
>>
>>
>> [...]
>
> Applied, thanks!
>
> [1/2] io-uring: move `struct io_br_sel` into io_uring_types.h
> commit: 1a8ceff033519eac7bb5ab1d910e9b0340835c0d
> [2/2] io_uring: uring_cmd: add multishot support
> commit: 55dc643dd2ad15e755a706980692a374de1bb7a8
I did notice an issue with !CONFIG_IO_URING, but figured I could just
fix it up as it should not need a respin for that. Below is the
incremental I applied while committing this.
diff --git a/include/linux/io_uring/cmd.h b/include/linux/io_uring/cmd.h
index 856d343b8e2a..be0e29b72669 100644
--- a/include/linux/io_uring/cmd.h
+++ b/include/linux/io_uring/cmd.h
@@ -117,12 +117,11 @@ 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 int io_uring_cmd_select_buffer(struct io_uring_cmd *ioucmd,
- unsigned buf_group,
- void **buf, size_t *len,
- unsigned int issue_flags)
+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 -EOPNOTSUPP;
+ 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)
--
Jens Axboe
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH V5 2/2] io_uring: uring_cmd: add multishot support
2025-08-21 4:02 ` [PATCH V5 2/2] io_uring: uring_cmd: add multishot support Ming Lei
@ 2025-08-21 16:23 ` Caleb Sander Mateos
2025-08-21 16:37 ` Jens Axboe
2025-08-21 16:29 ` Caleb Sander Mateos
1 sibling, 1 reply; 11+ messages in thread
From: Caleb Sander Mateos @ 2025-08-21 16:23 UTC (permalink / raw)
To: Ming Lei; +Cc: Jens Axboe, io-uring, Pavel Begunkov
On Wed, Aug 20, 2025 at 9:02 PM Ming Lei <ming.lei@redhat.com> wrote:
>
> 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>
Sorry I was out for a while and didn't get a chance to look at this
earlier. It generally looks reasonable. I noticed a couple of small
things which I'll send out patches for.
> ---
> include/linux/io_uring/cmd.h | 27 +++++++++++++
> include/uapi/linux/io_uring.h | 6 ++-
> io_uring/opdef.c | 1 +
> io_uring/uring_cmd.c | 71 ++++++++++++++++++++++++++++++++++-
> 4 files changed, 103 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/io_uring/cmd.h b/include/linux/io_uring/cmd.h
> index cfa6d0c0c322..856d343b8e2a 100644
> --- a/include/linux/io_uring/cmd.h
> +++ b/include/linux/io_uring/cmd.h
> @@ -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,18 @@ 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 int io_uring_cmd_select_buffer(struct io_uring_cmd *ioucmd,
> + unsigned buf_group,
> + void **buf, size_t *len,
> + unsigned int issue_flags)
> +{
> + return -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
>
> /*
> diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
> index 6957dc539d83..1e935f8901c5 100644
> --- a/include/uapi/linux/io_uring.h
> +++ b/include/uapi/linux/io_uring.h
> @@ -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)
>
>
> /*
> diff --git a/io_uring/opdef.c b/io_uring/opdef.c
> index 9568785810d9..932319633eac 100644
> --- a/io_uring/opdef.c
> +++ b/io_uring/opdef.c
> @@ -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,
> diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
> index 053bac89b6c0..3cfb5d51b88a 100644
> --- a/io_uring/uring_cmd.c
> +++ b/io_uring/uring_cmd.c
> @@ -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 };
Would this condition make more sense as a WARN_ON()? When would this
be called for a non-IORING_URING_CMD_MULTISHOT io_uring_cmd?
> +
> + 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;
Same here, a WARN_ON() seems like it would make more sense.
Best,
Caleb
> +
> + 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);
> --
> 2.47.0
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V5 2/2] io_uring: uring_cmd: add multishot support
2025-08-21 4:02 ` [PATCH V5 2/2] io_uring: uring_cmd: add multishot support Ming Lei
2025-08-21 16:23 ` Caleb Sander Mateos
@ 2025-08-21 16:29 ` Caleb Sander Mateos
2025-08-21 16:38 ` Jens Axboe
1 sibling, 1 reply; 11+ messages in thread
From: Caleb Sander Mateos @ 2025-08-21 16:29 UTC (permalink / raw)
To: Ming Lei; +Cc: Jens Axboe, io-uring, Pavel Begunkov
On Wed, Aug 20, 2025 at 9:02 PM Ming Lei <ming.lei@redhat.com> wrote:
>
> 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>
> ---
> include/linux/io_uring/cmd.h | 27 +++++++++++++
> include/uapi/linux/io_uring.h | 6 ++-
> io_uring/opdef.c | 1 +
> io_uring/uring_cmd.c | 71 ++++++++++++++++++++++++++++++++++-
> 4 files changed, 103 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/io_uring/cmd.h b/include/linux/io_uring/cmd.h
> index cfa6d0c0c322..856d343b8e2a 100644
> --- a/include/linux/io_uring/cmd.h
> +++ b/include/linux/io_uring/cmd.h
> @@ -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,18 @@ 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 int io_uring_cmd_select_buffer(struct io_uring_cmd *ioucmd,
> + unsigned buf_group,
> + void **buf, size_t *len,
> + unsigned int issue_flags)
> +{
> + return -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
>
> /*
> diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
> index 6957dc539d83..1e935f8901c5 100644
> --- a/include/uapi/linux/io_uring.h
> +++ b/include/uapi/linux/io_uring.h
> @@ -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)
One other question: what is the purpose of this additional flag?
io_uring_cmd_prep() checks that it matches IOSQE_BUFFER_SELECT, so
could we just check that flag instead and drop the check that
IORING_URING_CMD_MULTISHOT matches REQ_F_BUFFER_SELECT?
Best,
Caleb
>
>
> /*
> diff --git a/io_uring/opdef.c b/io_uring/opdef.c
> index 9568785810d9..932319633eac 100644
> --- a/io_uring/opdef.c
> +++ b/io_uring/opdef.c
> @@ -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,
> diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
> index 053bac89b6c0..3cfb5d51b88a 100644
> --- a/io_uring/uring_cmd.c
> +++ b/io_uring/uring_cmd.c
> @@ -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);
> --
> 2.47.0
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V5 2/2] io_uring: uring_cmd: add multishot support
2025-08-21 16:23 ` Caleb Sander Mateos
@ 2025-08-21 16:37 ` Jens Axboe
0 siblings, 0 replies; 11+ messages in thread
From: Jens Axboe @ 2025-08-21 16:37 UTC (permalink / raw)
To: Caleb Sander Mateos, Ming Lei; +Cc: io-uring, Pavel Begunkov
On 8/21/25 10:23 AM, Caleb Sander Mateos wrote:
>> @@ -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 };
>
> Would this condition make more sense as a WARN_ON()? When would this
> be called for a non-IORING_URING_CMD_MULTISHOT io_uring_cmd?
>
>> +
>> + 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;
>
> Same here, a WARN_ON() seems like it would make more sense.
Honestly, I think the existing WARN_ON_ONCE() needs to go rather. I
guess the point is that it's an internal misuse, eg it should not
happen. But I think just passing the error should be enough, you'd know
something is wrong anyway. The reasoning for getting rid of them is that
if these end up being somehow triggerable, then a WARN_ON() is a
potential DOS issue.
IOW, anything WARN_*() should probably just go on that side...
--
Jens Axboe
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V5 2/2] io_uring: uring_cmd: add multishot support
2025-08-21 16:29 ` Caleb Sander Mateos
@ 2025-08-21 16:38 ` Jens Axboe
2025-08-22 0:52 ` Ming Lei
0 siblings, 1 reply; 11+ messages in thread
From: Jens Axboe @ 2025-08-21 16:38 UTC (permalink / raw)
To: Caleb Sander Mateos, Ming Lei; +Cc: io-uring, Pavel Begunkov
On 8/21/25 10:29 AM, Caleb Sander Mateos wrote:
> On Wed, Aug 20, 2025 at 9:02?PM Ming Lei <ming.lei@redhat.com> wrote:
>>
>> 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>
>> ---
>> include/linux/io_uring/cmd.h | 27 +++++++++++++
>> include/uapi/linux/io_uring.h | 6 ++-
>> io_uring/opdef.c | 1 +
>> io_uring/uring_cmd.c | 71 ++++++++++++++++++++++++++++++++++-
>> 4 files changed, 103 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/io_uring/cmd.h b/include/linux/io_uring/cmd.h
>> index cfa6d0c0c322..856d343b8e2a 100644
>> --- a/include/linux/io_uring/cmd.h
>> +++ b/include/linux/io_uring/cmd.h
>> @@ -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,18 @@ 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 int io_uring_cmd_select_buffer(struct io_uring_cmd *ioucmd,
>> + unsigned buf_group,
>> + void **buf, size_t *len,
>> + unsigned int issue_flags)
>> +{
>> + return -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
>>
>> /*
>> diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
>> index 6957dc539d83..1e935f8901c5 100644
>> --- a/include/uapi/linux/io_uring.h
>> +++ b/include/uapi/linux/io_uring.h
>> @@ -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)
>
> One other question: what is the purpose of this additional flag?
> io_uring_cmd_prep() checks that it matches IOSQE_BUFFER_SELECT, so
> could we just check that flag instead and drop the check that
> IORING_URING_CMD_MULTISHOT matches REQ_F_BUFFER_SELECT?
This is a good question - if we don't strictly needs to exist, eg it
overlaps 100% with IOSQE_BUFFER_SELECT, we should just drop it.
--
Jens Axboe
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V5 2/2] io_uring: uring_cmd: add multishot support
2025-08-21 16:38 ` Jens Axboe
@ 2025-08-22 0:52 ` Ming Lei
2025-08-22 0:58 ` Jens Axboe
0 siblings, 1 reply; 11+ messages in thread
From: Ming Lei @ 2025-08-22 0:52 UTC (permalink / raw)
To: Jens Axboe; +Cc: Caleb Sander Mateos, io-uring, Pavel Begunkov
On Thu, Aug 21, 2025 at 10:38:57AM -0600, Jens Axboe wrote:
> On 8/21/25 10:29 AM, Caleb Sander Mateos wrote:
> > On Wed, Aug 20, 2025 at 9:02?PM Ming Lei <ming.lei@redhat.com> wrote:
> >>
> >> 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>
> >> ---
> >> include/linux/io_uring/cmd.h | 27 +++++++++++++
> >> include/uapi/linux/io_uring.h | 6 ++-
> >> io_uring/opdef.c | 1 +
> >> io_uring/uring_cmd.c | 71 ++++++++++++++++++++++++++++++++++-
> >> 4 files changed, 103 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/include/linux/io_uring/cmd.h b/include/linux/io_uring/cmd.h
> >> index cfa6d0c0c322..856d343b8e2a 100644
> >> --- a/include/linux/io_uring/cmd.h
> >> +++ b/include/linux/io_uring/cmd.h
> >> @@ -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,18 @@ 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 int io_uring_cmd_select_buffer(struct io_uring_cmd *ioucmd,
> >> + unsigned buf_group,
> >> + void **buf, size_t *len,
> >> + unsigned int issue_flags)
> >> +{
> >> + return -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
> >>
> >> /*
> >> diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
> >> index 6957dc539d83..1e935f8901c5 100644
> >> --- a/include/uapi/linux/io_uring.h
> >> +++ b/include/uapi/linux/io_uring.h
> >> @@ -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)
> >
> > One other question: what is the purpose of this additional flag?
> > io_uring_cmd_prep() checks that it matches IOSQE_BUFFER_SELECT, so
> > could we just check that flag instead and drop the check that
> > IORING_URING_CMD_MULTISHOT matches REQ_F_BUFFER_SELECT?
>
> This is a good question - if we don't strictly needs to exist, eg it
> overlaps 100% with IOSQE_BUFFER_SELECT, we should just drop it.
Without this flag, who knows it is one mshot command?
Other mshot OPs use new OP for showing the purpose, here I just want to
avoid to add another uring_cmd variant.
Thanks,
Ming
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V5 2/2] io_uring: uring_cmd: add multishot support
2025-08-22 0:52 ` Ming Lei
@ 2025-08-22 0:58 ` Jens Axboe
0 siblings, 0 replies; 11+ messages in thread
From: Jens Axboe @ 2025-08-22 0:58 UTC (permalink / raw)
To: Ming Lei; +Cc: Caleb Sander Mateos, io-uring, Pavel Begunkov
On 8/21/25 6:52 PM, Ming Lei wrote:
> On Thu, Aug 21, 2025 at 10:38:57AM -0600, Jens Axboe wrote:
>> On 8/21/25 10:29 AM, Caleb Sander Mateos wrote:
>>> On Wed, Aug 20, 2025 at 9:02?PM Ming Lei <ming.lei@redhat.com> wrote:
>>>>
>>>> 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>
>>>> ---
>>>> include/linux/io_uring/cmd.h | 27 +++++++++++++
>>>> include/uapi/linux/io_uring.h | 6 ++-
>>>> io_uring/opdef.c | 1 +
>>>> io_uring/uring_cmd.c | 71 ++++++++++++++++++++++++++++++++++-
>>>> 4 files changed, 103 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/include/linux/io_uring/cmd.h b/include/linux/io_uring/cmd.h
>>>> index cfa6d0c0c322..856d343b8e2a 100644
>>>> --- a/include/linux/io_uring/cmd.h
>>>> +++ b/include/linux/io_uring/cmd.h
>>>> @@ -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,18 @@ 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 int io_uring_cmd_select_buffer(struct io_uring_cmd *ioucmd,
>>>> + unsigned buf_group,
>>>> + void **buf, size_t *len,
>>>> + unsigned int issue_flags)
>>>> +{
>>>> + return -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
>>>>
>>>> /*
>>>> diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
>>>> index 6957dc539d83..1e935f8901c5 100644
>>>> --- a/include/uapi/linux/io_uring.h
>>>> +++ b/include/uapi/linux/io_uring.h
>>>> @@ -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)
>>>
>>> One other question: what is the purpose of this additional flag?
>>> io_uring_cmd_prep() checks that it matches IOSQE_BUFFER_SELECT, so
>>> could we just check that flag instead and drop the check that
>>> IORING_URING_CMD_MULTISHOT matches REQ_F_BUFFER_SELECT?
>>
>> This is a good question - if we don't strictly needs to exist, eg it
>> overlaps 100% with IOSQE_BUFFER_SELECT, we should just drop it.
>
> Without this flag, who knows it is one mshot command?
>
> Other mshot OPs use new OP for showing the purpose, here I just want to
> avoid to add another uring_cmd variant.
Basically all other multishot command types use a flag, not a new
opcode. Read mshot is the odd one out, because it doesn't have private
flags. Hence I do agree with you, the current approach is fine. For some
reason I remembered it as a IO_URING_CMD_* buffer select flag, but it's
not. The other mshot commands also generally require
IOSQE_BUFFER_SELECT, rather than have it be implied by the command type.
--
Jens Axboe
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-08-22 0:58 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-21 4:02 [PATCH V5 0/2] io_uring: uring_cmd: add multishot support with provided buffer Ming Lei
2025-08-21 4:02 ` [PATCH V5 1/2] io-uring: move `struct io_br_sel` into io_uring_types.h Ming Lei
2025-08-21 4:02 ` [PATCH V5 2/2] io_uring: uring_cmd: add multishot support Ming Lei
2025-08-21 16:23 ` Caleb Sander Mateos
2025-08-21 16:37 ` Jens Axboe
2025-08-21 16:29 ` Caleb Sander Mateos
2025-08-21 16:38 ` Jens Axboe
2025-08-22 0:52 ` Ming Lei
2025-08-22 0:58 ` Jens Axboe
2025-08-21 11:41 ` [PATCH V5 0/2] io_uring: uring_cmd: add multishot support with provided buffer Jens Axboe
2025-08-21 11:44 ` Jens Axboe
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox