public inbox for [email protected]
 help / color / mirror / Atom feed
* [PATCHSET v2 0/2] Add support for sending sync MSG_RING
@ 2024-09-24 11:57 Jens Axboe
  2024-09-24 11:57 ` [PATCH 1/2] io_uring/msg_ring: refactor a few helper functions Jens Axboe
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Jens Axboe @ 2024-09-24 11:57 UTC (permalink / raw)
  To: io-uring

Hi,

Over the last 6 months, several people have asked for if it's possible
to send a MSG_RING request to a ring without having a source ring to do
it from. The answer is no, as you'd need a source ring to submit such a
request in the first place. However, we can easily support this use case
of allowing someone to send a message to a ring that their own, without
needing to setup a source ring just for that alone.

This adds support for "blind" register opcodes for io_uring_register(2),
which simply means that there's no io_uring ring fd being passed in. The
'fd' must be set to -1. IORING_REGISTER_SEND_MSG_RING is added, which
simply takes a pointer to an io_uring_sqe. That sqe must be setup just
like an sqe that would have been otherwise prepared via sending over a
normal ring. An sqe pointer is used to keep the app side trivial, as
they can just put an sqe on the stack, initialize it to zeroes, and then
call io_uring_prep_msg_ring() on it like they would for an async
MSG_RING.

Once setup, the app can call:

io_uring_register(-1, IORING_REGISTER_SEND_MSG_RING, &sqe, 1);

which would like like:

io_uring_send_msg_ring_sync(&sqe);

if using linuring. The return value of this syscall is what would have
been in cqe->res using the async approach - 0 on success, or a negative
error value in case of failure.

Patches can also be found in a kernel branch here:

https://git.kernel.dk/cgit/linux/log/?h=io_uring-sync-msg_ring

and a liburing branch with support (and test cases) is here:

https://git.kernel.dk/cgit/liburing/log/?h=sync-msg

Since v1:
- Cleanups
- Sanity check sqe->flags and the actual opcode
- Use fdget/fdput
- Add a few comments

 include/uapi/linux/io_uring.h |  3 ++
 io_uring/msg_ring.c           | 60 ++++++++++++++++++++++++++++-------
 io_uring/msg_ring.h           |  1 +
 io_uring/register.c           | 30 ++++++++++++++++++
 4 files changed, 83 insertions(+), 11 deletions(-)

-- 
Jens Axboe


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

* [PATCH 1/2] io_uring/msg_ring: refactor a few helper functions
  2024-09-24 11:57 [PATCHSET v2 0/2] Add support for sending sync MSG_RING Jens Axboe
@ 2024-09-24 11:57 ` Jens Axboe
  2024-09-24 11:57 ` [PATCH 2/2] io_uring/msg_ring: add support for sending a sync message Jens Axboe
  2024-09-30 14:28 ` [PATCHSET v2 0/2] Add support for sending sync MSG_RING Jens Axboe
  2 siblings, 0 replies; 4+ messages in thread
From: Jens Axboe @ 2024-09-24 11:57 UTC (permalink / raw)
  To: io-uring; +Cc: Jens Axboe

Mostly just to skip them taking an io_kiocb, rather just pass in the
ctx and io_msg directly.

In preparation for being able to issue a MSG_RING request without
having an io_kiocb. No functional changes in this patch.

Signed-off-by: Jens Axboe <[email protected]>
---
 io_uring/msg_ring.c | 31 ++++++++++++++++++++-----------
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/io_uring/msg_ring.c b/io_uring/msg_ring.c
index 7fd9badcfaf8..b8c527f08cd5 100644
--- a/io_uring/msg_ring.c
+++ b/io_uring/msg_ring.c
@@ -116,14 +116,13 @@ static struct io_kiocb *io_msg_get_kiocb(struct io_ring_ctx *ctx)
 	return kmem_cache_alloc(req_cachep, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
 }
 
-static int io_msg_data_remote(struct io_kiocb *req)
+static int io_msg_data_remote(struct io_ring_ctx *target_ctx,
+			      struct io_msg *msg)
 {
-	struct io_ring_ctx *target_ctx = req->file->private_data;
-	struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
 	struct io_kiocb *target;
 	u32 flags = 0;
 
-	target = io_msg_get_kiocb(req->ctx);
+	target = io_msg_get_kiocb(target_ctx);
 	if (unlikely(!target))
 		return -ENOMEM;
 
@@ -134,10 +133,9 @@ static int io_msg_data_remote(struct io_kiocb *req)
 					msg->user_data);
 }
 
-static int io_msg_ring_data(struct io_kiocb *req, unsigned int issue_flags)
+static int __io_msg_ring_data(struct io_ring_ctx *target_ctx,
+			      struct io_msg *msg, unsigned int issue_flags)
 {
-	struct io_ring_ctx *target_ctx = req->file->private_data;
-	struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
 	u32 flags = 0;
 	int ret;
 
@@ -149,7 +147,7 @@ static int io_msg_ring_data(struct io_kiocb *req, unsigned int issue_flags)
 		return -EBADFD;
 
 	if (io_msg_need_remote(target_ctx))
-		return io_msg_data_remote(req);
+		return io_msg_data_remote(target_ctx, msg);
 
 	if (msg->flags & IORING_MSG_RING_FLAGS_PASS)
 		flags = msg->cqe_flags;
@@ -166,6 +164,14 @@ static int io_msg_ring_data(struct io_kiocb *req, unsigned int issue_flags)
 	return ret;
 }
 
+static int io_msg_ring_data(struct io_kiocb *req, unsigned int issue_flags)
+{
+	struct io_ring_ctx *target_ctx = req->file->private_data;
+	struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
+
+	return __io_msg_ring_data(target_ctx, msg, issue_flags);
+}
+
 static struct file *io_msg_grab_file(struct io_kiocb *req, unsigned int issue_flags)
 {
 	struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
@@ -271,10 +277,8 @@ static int io_msg_send_fd(struct io_kiocb *req, unsigned int issue_flags)
 	return io_msg_install_complete(req, issue_flags);
 }
 
-int io_msg_ring_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+static int __io_msg_ring_prep(struct io_msg *msg, const struct io_uring_sqe *sqe)
 {
-	struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
-
 	if (unlikely(sqe->buf_index || sqe->personality))
 		return -EINVAL;
 
@@ -291,6 +295,11 @@ int io_msg_ring_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 	return 0;
 }
 
+int io_msg_ring_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+	return __io_msg_ring_prep(io_kiocb_to_cmd(req, struct io_msg), sqe);
+}
+
 int io_msg_ring(struct io_kiocb *req, unsigned int issue_flags)
 {
 	struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
-- 
2.45.2


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

* [PATCH 2/2] io_uring/msg_ring: add support for sending a sync message
  2024-09-24 11:57 [PATCHSET v2 0/2] Add support for sending sync MSG_RING Jens Axboe
  2024-09-24 11:57 ` [PATCH 1/2] io_uring/msg_ring: refactor a few helper functions Jens Axboe
@ 2024-09-24 11:57 ` Jens Axboe
  2024-09-30 14:28 ` [PATCHSET v2 0/2] Add support for sending sync MSG_RING Jens Axboe
  2 siblings, 0 replies; 4+ messages in thread
From: Jens Axboe @ 2024-09-24 11:57 UTC (permalink / raw)
  To: io-uring; +Cc: Jens Axboe

Normally MSG_RING requires both a source and a destination ring. But
some users don't always have a ring avilable to send a message from, yet
they still need to notify a target ring.

Add support for using io_uring_register(2) without having a source ring,
using a file descriptor of -1 for that. Internally those are called
blind registration opcodes. Implement IORING_REGISTER_SEND_MSG_RING as a
blind opcode, which simply takes an sqe that the application can put on
the stack and use the normal liburing helpers to initialize it. Then the
app can call:

io_uring_register(-1, IORING_REGISTER_SEND_MSG_RING, &sqe, 1);

and get the same behavior in terms of the target, where a CQE is posted
with the details given in the sqe.

For now this takes a single sqe pointer argument, and hence arg must
be set to that, and nr_args must be 1. Could easily be extended to take
an array of sqes, but for now let's keep it simple.

Signed-off-by: Jens Axboe <[email protected]>
---
 include/uapi/linux/io_uring.h |  3 +++
 io_uring/msg_ring.c           | 29 +++++++++++++++++++++++++++++
 io_uring/msg_ring.h           |  1 +
 io_uring/register.c           | 30 ++++++++++++++++++++++++++++++
 4 files changed, 63 insertions(+)

diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 1fe79e750470..86cb385fe0b5 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -612,6 +612,9 @@ enum io_uring_register_op {
 	/* clone registered buffers from source ring to current ring */
 	IORING_REGISTER_CLONE_BUFFERS		= 30,
 
+	/* send MSG_RING without having a ring */
+	IORING_REGISTER_SEND_MSG_RING		= 31,
+
 	/* this goes last */
 	IORING_REGISTER_LAST,
 
diff --git a/io_uring/msg_ring.c b/io_uring/msg_ring.c
index b8c527f08cd5..edea1ffd501c 100644
--- a/io_uring/msg_ring.c
+++ b/io_uring/msg_ring.c
@@ -331,6 +331,35 @@ int io_msg_ring(struct io_kiocb *req, unsigned int issue_flags)
 	return IOU_OK;
 }
 
+int io_uring_sync_msg_ring(struct io_uring_sqe *sqe)
+{
+	struct io_msg io_msg = { };
+	struct fd f;
+	int ret;
+
+	ret = __io_msg_ring_prep(&io_msg, sqe);
+	if (unlikely(ret))
+		return ret;
+
+	/*
+	 * Only data sending supported, not IORING_MSG_SEND_FD as that one
+	 * doesn't make sense without a source ring to send files from.
+	 */
+	if (io_msg.cmd != IORING_MSG_DATA)
+		return -EINVAL;
+
+	ret = -EBADF;
+	f = fdget(sqe->fd);
+	if (fd_file(f)) {
+		ret = -EBADFD;
+		if (io_is_uring_fops(fd_file(f)))
+			ret = __io_msg_ring_data(fd_file(f)->private_data,
+						 &io_msg, IO_URING_F_UNLOCKED);
+		fdput(f);
+	}
+	return ret;
+}
+
 void io_msg_cache_free(const void *entry)
 {
 	struct io_kiocb *req = (struct io_kiocb *) entry;
diff --git a/io_uring/msg_ring.h b/io_uring/msg_ring.h
index 3030f3942f0f..38e7f8f0c944 100644
--- a/io_uring/msg_ring.h
+++ b/io_uring/msg_ring.h
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 
+int io_uring_sync_msg_ring(struct io_uring_sqe *sqe);
 int io_msg_ring_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
 int io_msg_ring(struct io_kiocb *req, unsigned int issue_flags);
 void io_msg_ring_cleanup(struct io_kiocb *req);
diff --git a/io_uring/register.c b/io_uring/register.c
index eca26d4884d9..52b2f9b74af8 100644
--- a/io_uring/register.c
+++ b/io_uring/register.c
@@ -28,6 +28,7 @@
 #include "kbuf.h"
 #include "napi.h"
 #include "eventfd.h"
+#include "msg_ring.h"
 
 #define IORING_MAX_RESTRICTIONS	(IORING_RESTRICTION_LAST + \
 				 IORING_REGISTER_LAST + IORING_OP_LAST)
@@ -588,6 +589,32 @@ struct file *io_uring_register_get_file(unsigned int fd, bool registered)
 	return ERR_PTR(-EOPNOTSUPP);
 }
 
+/*
+ * "blind" registration opcodes are ones where there's no ring given, and
+ * hence the source fd must be -1.
+ */
+static int io_uring_register_blind(unsigned int opcode, void __user *arg,
+				   unsigned int nr_args)
+{
+	switch (opcode) {
+	case IORING_REGISTER_SEND_MSG_RING: {
+		struct io_uring_sqe sqe;
+
+		if (!arg || nr_args != 1)
+			return -EINVAL;
+		if (copy_from_user(&sqe, arg, sizeof(sqe)))
+			return -EFAULT;
+		/* no flags supported */
+		if (sqe.flags)
+			return -EINVAL;
+		if (sqe.opcode == IORING_OP_MSG_RING)
+			return io_uring_sync_msg_ring(&sqe);
+		}
+	}
+
+	return -EINVAL;
+}
+
 SYSCALL_DEFINE4(io_uring_register, unsigned int, fd, unsigned int, opcode,
 		void __user *, arg, unsigned int, nr_args)
 {
@@ -602,6 +629,9 @@ SYSCALL_DEFINE4(io_uring_register, unsigned int, fd, unsigned int, opcode,
 	if (opcode >= IORING_REGISTER_LAST)
 		return -EINVAL;
 
+	if (fd == -1)
+		return io_uring_register_blind(opcode, arg, nr_args);
+
 	file = io_uring_register_get_file(fd, use_registered_ring);
 	if (IS_ERR(file))
 		return PTR_ERR(file);
-- 
2.45.2


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

* Re: [PATCHSET v2 0/2] Add support for sending sync MSG_RING
  2024-09-24 11:57 [PATCHSET v2 0/2] Add support for sending sync MSG_RING Jens Axboe
  2024-09-24 11:57 ` [PATCH 1/2] io_uring/msg_ring: refactor a few helper functions Jens Axboe
  2024-09-24 11:57 ` [PATCH 2/2] io_uring/msg_ring: add support for sending a sync message Jens Axboe
@ 2024-09-30 14:28 ` Jens Axboe
  2 siblings, 0 replies; 4+ messages in thread
From: Jens Axboe @ 2024-09-30 14:28 UTC (permalink / raw)
  To: io-uring, Jens Axboe


On Tue, 24 Sep 2024 05:57:29 -0600, Jens Axboe wrote:
> Over the last 6 months, several people have asked for if it's possible
> to send a MSG_RING request to a ring without having a source ring to do
> it from. The answer is no, as you'd need a source ring to submit such a
> request in the first place. However, we can easily support this use case
> of allowing someone to send a message to a ring that their own, without
> needing to setup a source ring just for that alone.
> 
> [...]

Applied, thanks!

[1/2] io_uring/msg_ring: refactor a few helper functions
      commit: 6516c5008c88eda9137f0985f419e40d3fc7cee1
[2/2] io_uring/msg_ring: add support for sending a sync message
      commit: d1e55003c13ca95878afe380ad3da89d37d63b1e

Best regards,
-- 
Jens Axboe




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

end of thread, other threads:[~2024-09-30 14:28 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-24 11:57 [PATCHSET v2 0/2] Add support for sending sync MSG_RING Jens Axboe
2024-09-24 11:57 ` [PATCH 1/2] io_uring/msg_ring: refactor a few helper functions Jens Axboe
2024-09-24 11:57 ` [PATCH 2/2] io_uring/msg_ring: add support for sending a sync message Jens Axboe
2024-09-30 14:28 ` [PATCHSET v2 0/2] Add support for sending sync MSG_RING Jens Axboe

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