All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH liburing 0/4] Buffer ring API fixes
@ 2022-06-13 13:12 Dylan Yudaken
  2022-06-13 13:12 ` [PATCH liburing 1/4] remove non-existent manpage reference Dylan Yudaken
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Dylan Yudaken @ 2022-06-13 13:12 UTC (permalink / raw)
  To: axboe, asml.silence, io-uring; +Cc: Kernel-team, Dylan Yudaken

This set makes some changes to the new buf_ring API to help it's
usability.  Most importantly the _add function needs a mask parameter
to prevent buffer overflow. I added a _mask helper function to
calculate this. Even though its trivial it feels better to not force
the user to think about it.

Additionally _init is required as otherwise there is no provided way
to sync the tail with the kernel.

Lastly I add a test that showed up some issues found in 5.19-rc1.

Patch 1 is a small man fix
Patch 2/3 are the API changes
Patch 4 is the test.

Dylan Yudaken (4):
  remove non-existent manpage reference
  add mask parameter to io_uring_buf_ring_add
  add io_uring_buf_ring_init
  buf-ring: add tests that cycle through the provided buffer ring

 man/io_uring_buf_ring_add.3      |   5 ++
 man/io_uring_buf_ring_init.3     |  30 +++++++
 man/io_uring_buf_ring_mask.3     |  27 +++++++
 man/io_uring_register_buf_ring.3 |   6 +-
 src/include/liburing.h           |  18 ++++-
 test/buf-ring.c                  | 133 +++++++++++++++++++++++++++++++
 test/send_recvmsg.c              |   4 +-
 7 files changed, 218 insertions(+), 5 deletions(-)
 create mode 100644 man/io_uring_buf_ring_init.3
 create mode 100644 man/io_uring_buf_ring_mask.3


base-commit: 807c8169e153a3985f1a4deddc302846673ef979
-- 
2.30.2


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

* [PATCH liburing 1/4] remove non-existent manpage reference
  2022-06-13 13:12 [PATCH liburing 0/4] Buffer ring API fixes Dylan Yudaken
@ 2022-06-13 13:12 ` Dylan Yudaken
  2022-06-13 13:12 ` [PATCH liburing 2/4] add mask parameter to io_uring_buf_ring_add Dylan Yudaken
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Dylan Yudaken @ 2022-06-13 13:12 UTC (permalink / raw)
  To: axboe, asml.silence, io-uring; +Cc: Kernel-team, Dylan Yudaken

This function doesn't exist

Signed-off-by: Dylan Yudaken <dylany@fb.com>
---
 man/io_uring_register_buf_ring.3 | 1 -
 1 file changed, 1 deletion(-)

diff --git a/man/io_uring_register_buf_ring.3 b/man/io_uring_register_buf_ring.3
index 82a8efc..9e0b53d 100644
--- a/man/io_uring_register_buf_ring.3
+++ b/man/io_uring_register_buf_ring.3
@@ -131,7 +131,6 @@ On success
 returns 0. On failure it returns
 .BR -errno .
 .SH SEE ALSO
-.BR io_uring_buf_ring_alloc (3),
 .BR io_uring_buf_ring_add (3),
 .BR io_uring_buf_ring_advance (3),
 .BR io_uring_buf_ring_cq_advance (3)
-- 
2.30.2


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

* [PATCH liburing 2/4] add mask parameter to io_uring_buf_ring_add
  2022-06-13 13:12 [PATCH liburing 0/4] Buffer ring API fixes Dylan Yudaken
  2022-06-13 13:12 ` [PATCH liburing 1/4] remove non-existent manpage reference Dylan Yudaken
@ 2022-06-13 13:12 ` Dylan Yudaken
  2022-06-13 13:12 ` [PATCH liburing 3/4] add io_uring_buf_ring_init Dylan Yudaken
  2022-06-13 13:12 ` [PATCH liburing 4/4] buf-ring: add tests that cycle through the provided buffer ring Dylan Yudaken
  3 siblings, 0 replies; 5+ messages in thread
From: Dylan Yudaken @ 2022-06-13 13:12 UTC (permalink / raw)
  To: axboe, asml.silence, io-uring; +Cc: Kernel-team, Dylan Yudaken

Without the mask parameter, it's not feasible to use this API without
knowing where the tail is and performing some arithmetic

Signed-off-by: Dylan Yudaken <dylany@fb.com>
---
 man/io_uring_buf_ring_add.3  |  5 +++++
 man/io_uring_buf_ring_mask.3 | 27 +++++++++++++++++++++++++++
 src/include/liburing.h       | 13 +++++++++++--
 test/send_recvmsg.c          |  3 ++-
 4 files changed, 45 insertions(+), 3 deletions(-)
 create mode 100644 man/io_uring_buf_ring_mask.3

diff --git a/man/io_uring_buf_ring_add.3 b/man/io_uring_buf_ring_add.3
index 741cba6..9d8283b 100644
--- a/man/io_uring_buf_ring_add.3
+++ b/man/io_uring_buf_ring_add.3
@@ -13,6 +13,7 @@ io_uring_buf_ring_add \- add buffers to a shared buffer ring
 .BI "                          void *" addr ",
 .BI "                          unsigned int " len ",
 .BI "                          unsigned short " bid ",
+.BI "                          int " mask ",
 .BI "                          int " buf_offset ");"
 .fi
 .SH DESCRIPTION
@@ -28,6 +29,9 @@ and is of
 bytes of length.
 .I bid
 is the buffer ID, which will be returned in the CQE.
+.I mask
+is the size mask of the ring, available from
+.BR io_uring_buf_ring_mask (3) .
 .I buf_offset
 is the offset to insert at from the current tail. If just one buffer is provided
 before the ring tail is committed with
@@ -44,5 +48,6 @@ must be incremented by one for each buffer added.
 None
 .SH SEE ALSO
 .BR io_uring_register_buf_ring (3),
+.BR io_uring_buf_ring_mask (3),
 .BR io_uring_buf_ring_advance (3),
 .BR io_uring_buf_ring_cq_advance (3)
diff --git a/man/io_uring_buf_ring_mask.3 b/man/io_uring_buf_ring_mask.3
new file mode 100644
index 0000000..9160663
--- /dev/null
+++ b/man/io_uring_buf_ring_mask.3
@@ -0,0 +1,27 @@
+.\" Copyright (C) 2022 Dylan Yudaken <dylany@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+.TH io_uring_buf_ring_mask 3 "June 13, 2022" "liburing-2.2" "liburing Manual"
+.SH NAME
+io_uring_buf_ring_mask \- Calculate buffer ring mask size
+.SH SYNOPSIS
+.nf
+.B #include <liburing.h>
+.PP
+.BI "int io_uring_buf_ring_mask(__u32 " ring_entries ");"
+.fi
+.SH DESCRIPTION
+.PP
+.BR io_uring_buf_ring_mask (3)
+calculates the appropriate size mask for a buffer ring.
+.IR ring_entries
+is the ring entries as specified in
+.BR io_uring_register_buf_ring (3) .
+
+.SH RETURN VALUE
+Size mask for the buffer ring.
+
+.SH SEE ALSO
+.BR io_uring_register_buf_ring (3),
+.BR io_uring_buf_ring_add (3)
diff --git a/src/include/liburing.h b/src/include/liburing.h
index 6eece30..9beef0b 100644
--- a/src/include/liburing.h
+++ b/src/include/liburing.h
@@ -1089,14 +1089,23 @@ static inline struct io_uring_sqe *_io_uring_get_sqe(struct io_uring *ring)
 	return NULL;
 }
 
+/*
+ * Return the appropriate mask for a buffer ring of size 'ring_entries'
+ */
+static inline int io_uring_buf_ring_mask(__u32 ring_entries)
+{
+	return ring_entries - 1;
+}
+
 /*
  * Assign 'buf' with the addr/len/buffer ID supplied
  */
 static inline void io_uring_buf_ring_add(struct io_uring_buf_ring *br,
 					 void *addr, unsigned int len,
-					 unsigned short bid, int buf_offset)
+					 unsigned short bid, int mask,
+					 int buf_offset)
 {
-	struct io_uring_buf *buf = &br->bufs[br->tail + buf_offset];
+	struct io_uring_buf *buf = &br->bufs[(br->tail + buf_offset) & mask];
 
 	buf->addr = (unsigned long) (uintptr_t) addr;
 	buf->len = len;
diff --git a/test/send_recvmsg.c b/test/send_recvmsg.c
index 44a01b0..6f18bae 100644
--- a/test/send_recvmsg.c
+++ b/test/send_recvmsg.c
@@ -199,7 +199,8 @@ static void *recv_fn(void *data)
 			}
 
 			br = ptr;
-			io_uring_buf_ring_add(br, buf, sizeof(buf), BUF_BID, 0);
+			io_uring_buf_ring_add(br, buf, sizeof(buf), BUF_BID,
+					      io_uring_buf_ring_mask(1), 0);
 			io_uring_buf_ring_advance(br, 1);
 		} else {
 			struct io_uring_sqe *sqe;
-- 
2.30.2


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

* [PATCH liburing 3/4] add io_uring_buf_ring_init
  2022-06-13 13:12 [PATCH liburing 0/4] Buffer ring API fixes Dylan Yudaken
  2022-06-13 13:12 ` [PATCH liburing 1/4] remove non-existent manpage reference Dylan Yudaken
  2022-06-13 13:12 ` [PATCH liburing 2/4] add mask parameter to io_uring_buf_ring_add Dylan Yudaken
@ 2022-06-13 13:12 ` Dylan Yudaken
  2022-06-13 13:12 ` [PATCH liburing 4/4] buf-ring: add tests that cycle through the provided buffer ring Dylan Yudaken
  3 siblings, 0 replies; 5+ messages in thread
From: Dylan Yudaken @ 2022-06-13 13:12 UTC (permalink / raw)
  To: axboe, asml.silence, io-uring; +Cc: Kernel-team, Dylan Yudaken

Kernel expects the tail to start at 0, so provide an API to init the
ring appropriately.

Signed-off-by: Dylan Yudaken <dylany@fb.com>
---
 man/io_uring_buf_ring_init.3     | 30 ++++++++++++++++++++++++++++++
 man/io_uring_register_buf_ring.3 |  5 ++++-
 src/include/liburing.h           |  5 +++++
 test/send_recvmsg.c              |  1 +
 4 files changed, 40 insertions(+), 1 deletion(-)
 create mode 100644 man/io_uring_buf_ring_init.3

diff --git a/man/io_uring_buf_ring_init.3 b/man/io_uring_buf_ring_init.3
new file mode 100644
index 0000000..50cf69a
--- /dev/null
+++ b/man/io_uring_buf_ring_init.3
@@ -0,0 +1,30 @@
+.\" Copyright (C) 2022 Dylan Yudaken <dylany@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+.TH io_uring_buf_ring_init 3 "June 13, 2022" "liburing-2.2" "liburing Manual"
+.SH NAME
+io_uring_buf_ring_init \- Initialise a  buffer ring
+.SH SYNOPSIS
+.nf
+.B #include <liburing.h>
+.PP
+.BI "void io_uring_buf_ring_init(struct io_uring_buf_ring *" br ");"
+.fi
+.SH DESCRIPTION
+.PP
+.BR io_uring_buf_ring_init (3)
+initialises
+.IR br
+so that it is ready to be used. It may be called after
+.BR io_uring_register_buf_ring (3)
+but must be called before the buffer ring is used in any other way.
+
+.SH RETURN VALUE
+None
+
+.SH SEE ALSO
+.BR io_uring_register_buf_ring (3),
+.BR io_uring_buf_ring_add (3)
+.BR io_uring_buf_ring_advance (3),
+.BR io_uring_buf_ring_cq_advance (3)
diff --git a/man/io_uring_register_buf_ring.3 b/man/io_uring_register_buf_ring.3
index 9e0b53d..9e520bf 100644
--- a/man/io_uring_register_buf_ring.3
+++ b/man/io_uring_register_buf_ring.3
@@ -115,7 +115,9 @@ is the length of the buffer in bytes, and
 .I bid
 is the buffer ID that will be returned in the CQE once consumed.
 
-Reserved fields must not be touched. Applications may use
+Reserved fields must not be touched. Applications must use
+.BR io_uring_buf_ring_init (3)
+to initialise the buffer ring. Applications may use
 .BR io_uring_buf_ring_add (3)
 and
 .BR io_uring_buf_ring_advance (3)
@@ -131,6 +133,7 @@ On success
 returns 0. On failure it returns
 .BR -errno .
 .SH SEE ALSO
+.BR io_uring_buf_ring_init (3),
 .BR io_uring_buf_ring_add (3),
 .BR io_uring_buf_ring_advance (3),
 .BR io_uring_buf_ring_cq_advance (3)
diff --git a/src/include/liburing.h b/src/include/liburing.h
index 9beef0b..c31ece2 100644
--- a/src/include/liburing.h
+++ b/src/include/liburing.h
@@ -1097,6 +1097,11 @@ static inline int io_uring_buf_ring_mask(__u32 ring_entries)
 	return ring_entries - 1;
 }
 
+static inline void io_uring_buf_ring_init(struct io_uring_buf_ring *br)
+{
+	br->tail = 0;
+}
+
 /*
  * Assign 'buf' with the addr/len/buffer ID supplied
  */
diff --git a/test/send_recvmsg.c b/test/send_recvmsg.c
index 6f18bae..cce6c45 100644
--- a/test/send_recvmsg.c
+++ b/test/send_recvmsg.c
@@ -199,6 +199,7 @@ static void *recv_fn(void *data)
 			}
 
 			br = ptr;
+			io_uring_buf_ring_init(br);
 			io_uring_buf_ring_add(br, buf, sizeof(buf), BUF_BID,
 					      io_uring_buf_ring_mask(1), 0);
 			io_uring_buf_ring_advance(br, 1);
-- 
2.30.2


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

* [PATCH liburing 4/4] buf-ring: add tests that cycle through the provided buffer ring
  2022-06-13 13:12 [PATCH liburing 0/4] Buffer ring API fixes Dylan Yudaken
                   ` (2 preceding siblings ...)
  2022-06-13 13:12 ` [PATCH liburing 3/4] add io_uring_buf_ring_init Dylan Yudaken
@ 2022-06-13 13:12 ` Dylan Yudaken
  3 siblings, 0 replies; 5+ messages in thread
From: Dylan Yudaken @ 2022-06-13 13:12 UTC (permalink / raw)
  To: axboe, asml.silence, io-uring; +Cc: Kernel-team, Dylan Yudaken

Add tests that make sure that the buffer ring logic works properly
without actually using the data in each buffer.

This exposes some bugs in 5.19-rc1

Signed-off-by: Dylan Yudaken <dylany@fb.com>
---
 test/buf-ring.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 133 insertions(+)

diff --git a/test/buf-ring.c b/test/buf-ring.c
index 5fd1e53..2fcc360 100644
--- a/test/buf-ring.c
+++ b/test/buf-ring.c
@@ -206,9 +206,134 @@ static int test_reg_unreg(int bgid)
 	return 0;
 }
 
+static int test_one_nop(int bgid, struct io_uring *ring)
+{
+	int ret;
+	struct io_uring_cqe *cqe;
+	struct io_uring_sqe *sqe;
+
+	sqe = io_uring_get_sqe(ring);
+	if (!sqe) {
+		fprintf(stderr, "get sqe failed\n");
+		return -1;
+	}
+
+	io_uring_prep_nop(sqe);
+	sqe->flags |= IOSQE_BUFFER_SELECT;
+	sqe->buf_group = bgid;
+	ret = io_uring_submit(ring);
+	if (ret <= 0) {
+		fprintf(stderr, "sqe submit failed: %d\n", ret);
+		ret = -1;
+		goto out;
+	}
+
+	ret = io_uring_wait_cqe(ring, &cqe);
+	if (ret < 0) {
+		fprintf(stderr, "wait completion %d\n", ret);
+		ret = -1;
+		goto out;
+	}
+
+	if (cqe->res == -ENOBUFS) {
+		ret = cqe->res;
+		goto out;
+	}
+
+	if (cqe->res != 0) {
+		fprintf(stderr, "nop result %d\n", ret);
+		ret = -1;
+		goto out;
+	}
+
+	ret = cqe->flags >> 16;
+
+out:
+	io_uring_cqe_seen(ring, cqe);
+	return ret;
+}
+
+static int test_running(int bgid, int entries, int loops)
+{
+	struct io_uring_buf_reg reg = { };
+	struct io_uring ring;
+	void *ptr;
+	int ret;
+	int ring_size = (entries * sizeof(struct io_uring_buf) + 4095) & (~4095);
+	int ring_mask = io_uring_buf_ring_mask(entries);
+
+	int loop, idx;
+	bool *buffers;
+	struct io_uring_buf_ring *br;
+
+	ret = t_create_ring(1, &ring, 0);
+	if (ret == T_SETUP_SKIP)
+		return 0;
+	else if (ret != T_SETUP_OK)
+		return 1;
+
+	if (posix_memalign(&ptr, 4096, ring_size))
+		return 1;
+
+	br = (struct io_uring_buf_ring *)ptr;
+	io_uring_buf_ring_init(br);
+
+	buffers = malloc(sizeof(bool) * entries);
+	if (!buffers)
+		return 1;
+
+	reg.ring_addr = (unsigned long) ptr;
+	reg.ring_entries = entries;
+	reg.bgid = bgid;
+
+	ret = io_uring_register_buf_ring(&ring, &reg, 0);
+	if (ret) {
+		/* by now should have checked if this is supported or not */
+		fprintf(stderr, "Buffer ring register failed %d\n", ret);
+		return 1;
+	}
+
+	for (loop = 0; loop < loops; loop++) {
+		memset(buffers, 0, sizeof(bool) * entries);
+		for (idx = 0; idx < entries; idx++)
+			io_uring_buf_ring_add(br, ptr, 1, idx, ring_mask, idx);
+		io_uring_buf_ring_advance(br, entries);
+
+		for (idx = 0; idx < entries; idx++) {
+			ret = test_one_nop(bgid, &ring);
+			if (ret < 0) {
+				fprintf(stderr, "bad run %d/%d = %d\n", loop, idx, ret);
+				return ret;
+			}
+			if (buffers[ret]) {
+				fprintf(stderr, "reused buffer %d/%d = %d!\n", loop, idx, ret);
+				return 1;
+			}
+			buffers[ret] = true;
+		}
+		ret = test_one_nop(bgid, &ring);
+		if (ret != -ENOBUFS) {
+			fprintf(stderr, "expected enobufs run %d = %d\n", loop, ret);
+			return 1;
+		}
+
+	}
+
+	ret = io_uring_unregister_buf_ring(&ring, bgid);
+	if (ret) {
+		fprintf(stderr, "Buffer ring register failed %d\n", ret);
+		return 1;
+	}
+
+	io_uring_queue_exit(&ring);
+	free(buffers);
+	return 0;
+}
+
 int main(int argc, char *argv[])
 {
 	int bgids[] = { 1, 127, -1 };
+	int entries[] = {1, 32768, 4096, -1 };
 	int ret, i;
 
 	if (argc > 1)
@@ -242,5 +367,13 @@ int main(int argc, char *argv[])
 		}
 	}
 
+	for (i = 0; !no_buf_ring && entries[i] != -1; i++) {
+		ret = test_running(2, entries[i], 3);
+		if (ret) {
+			fprintf(stderr, "test_running(%d) failed\n", entries[i]);
+			return 1;
+		}
+	}
+
 	return 0;
 }
-- 
2.30.2


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

end of thread, other threads:[~2022-06-13 17:44 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-13 13:12 [PATCH liburing 0/4] Buffer ring API fixes Dylan Yudaken
2022-06-13 13:12 ` [PATCH liburing 1/4] remove non-existent manpage reference Dylan Yudaken
2022-06-13 13:12 ` [PATCH liburing 2/4] add mask parameter to io_uring_buf_ring_add Dylan Yudaken
2022-06-13 13:12 ` [PATCH liburing 3/4] add io_uring_buf_ring_init Dylan Yudaken
2022-06-13 13:12 ` [PATCH liburing 4/4] buf-ring: add tests that cycle through the provided buffer ring Dylan Yudaken

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.