public inbox for [email protected]
 help / color / mirror / Atom feed
* [PATCH 0/3] trivial fixes and a cleanup of provided buffers
@ 2023-10-05  0:05 Gabriel Krisman Bertazi
  2023-10-05  0:05 ` [PATCH 1/3] io_uring: Fix check of BID wrapping in " Gabriel Krisman Bertazi
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Gabriel Krisman Bertazi @ 2023-10-05  0:05 UTC (permalink / raw)
  To: axboe; +Cc: io-uring, jmoyer, Gabriel Krisman Bertazi

Jens,

I'm resubmitting the slab conversion for provided buffers with the
suggestions from Jeff (thanks!) for your consideration, and appended 2
minor fixes related to kbuf in the patchset. Since the patchset grew
from 1 to 3 patches, i pretended it is not a v2 and restart the
counting from 1.

thanks,

Gabriel Krisman Bertazi (3):
  io_uring: Fix check of BID wrapping in provided buffers
  io_uring: Allow the full buffer id space for provided buffers
  io_uring: Use slab for struct io_buffer objects

 include/linux/io_uring_types.h |  2 --
 io_uring/io_uring.c            |  4 ++-
 io_uring/io_uring.h            |  1 +
 io_uring/kbuf.c                | 58 +++++++++++++++++++---------------
 4 files changed, 37 insertions(+), 28 deletions(-)

-- 
2.42.0


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

* [PATCH 1/3] io_uring: Fix check of BID wrapping in provided buffers
  2023-10-05  0:05 [PATCH 0/3] trivial fixes and a cleanup of provided buffers Gabriel Krisman Bertazi
@ 2023-10-05  0:05 ` Gabriel Krisman Bertazi
  2023-10-05  0:05 ` [PATCH 2/3] io_uring: Allow the full buffer id space for " Gabriel Krisman Bertazi
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Gabriel Krisman Bertazi @ 2023-10-05  0:05 UTC (permalink / raw)
  To: axboe; +Cc: io-uring, jmoyer, Gabriel Krisman Bertazi

Commit 3851d25c75ed0 ("io_uring: check for rollover of buffer ID when
providing buffers") introduced a check to prevent wrapping the BID
counter when sqe->off is provided, but it's off-by-one too
restrictive, rejecting the last possible BID (65534).

i.e., the following fails with -EINVAL.

     io_uring_prep_provide_buffers(sqe, addr, size, 0xFFFF, 0, 0);

Fixes: 3851d25c75ed ("io_uring: check for rollover of buffer ID when providing buffers")
Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
---
 io_uring/kbuf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c
index 556f4df25b0f..52dba81c3f50 100644
--- a/io_uring/kbuf.c
+++ b/io_uring/kbuf.c
@@ -352,7 +352,7 @@ int io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
 	tmp = READ_ONCE(sqe->off);
 	if (tmp > USHRT_MAX)
 		return -E2BIG;
-	if (tmp + p->nbufs >= USHRT_MAX)
+	if (tmp + p->nbufs > USHRT_MAX)
 		return -EINVAL;
 	p->bid = tmp;
 	return 0;
-- 
2.42.0


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

* [PATCH 2/3] io_uring: Allow the full buffer id space for provided buffers
  2023-10-05  0:05 [PATCH 0/3] trivial fixes and a cleanup of provided buffers Gabriel Krisman Bertazi
  2023-10-05  0:05 ` [PATCH 1/3] io_uring: Fix check of BID wrapping in " Gabriel Krisman Bertazi
@ 2023-10-05  0:05 ` Gabriel Krisman Bertazi
  2023-10-05  0:05 ` [PATCH 3/3] io_uring: Use slab for struct io_buffer objects Gabriel Krisman Bertazi
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Gabriel Krisman Bertazi @ 2023-10-05  0:05 UTC (permalink / raw)
  To: axboe; +Cc: io-uring, jmoyer, Gabriel Krisman Bertazi

nbufs tracks the number of buffers and not the last bgid. In 16-bit, we
have 2^16 valid buffers, but the check mistakenly rejects the last
bid. Let's fix it to make the interface consistent with the
documentation.

Fixes: ddf0322db79c ("io_uring: add IORING_OP_PROVIDE_BUFFERS")
Signed-off-by: Gabriel Krisman Bertazi <[email protected]>
---
 io_uring/kbuf.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c
index 52dba81c3f50..12a357348733 100644
--- a/io_uring/kbuf.c
+++ b/io_uring/kbuf.c
@@ -19,12 +19,15 @@
 
 #define BGID_ARRAY	64
 
+/* BIDs are addressed by a 16-bit field in a CQE */
+#define MAX_BIDS_PER_BGID (1 << 16)
+
 struct io_provide_buf {
 	struct file			*file;
 	__u64				addr;
 	__u32				len;
 	__u32				bgid;
-	__u16				nbufs;
+	__u32				nbufs;
 	__u16				bid;
 };
 
@@ -289,7 +292,7 @@ int io_remove_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 		return -EINVAL;
 
 	tmp = READ_ONCE(sqe->fd);
-	if (!tmp || tmp > USHRT_MAX)
+	if (!tmp || tmp > MAX_BIDS_PER_BGID)
 		return -EINVAL;
 
 	memset(p, 0, sizeof(*p));
@@ -332,7 +335,7 @@ int io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
 		return -EINVAL;
 
 	tmp = READ_ONCE(sqe->fd);
-	if (!tmp || tmp > USHRT_MAX)
+	if (!tmp || tmp > MAX_BIDS_PER_BGID)
 		return -E2BIG;
 	p->nbufs = tmp;
 	p->addr = READ_ONCE(sqe->addr);
@@ -352,7 +355,7 @@ int io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
 	tmp = READ_ONCE(sqe->off);
 	if (tmp > USHRT_MAX)
 		return -E2BIG;
-	if (tmp + p->nbufs > USHRT_MAX)
+	if (tmp + p->nbufs > MAX_BIDS_PER_BGID)
 		return -EINVAL;
 	p->bid = tmp;
 	return 0;
-- 
2.42.0


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

* [PATCH 3/3] io_uring: Use slab for struct io_buffer objects
  2023-10-05  0:05 [PATCH 0/3] trivial fixes and a cleanup of provided buffers Gabriel Krisman Bertazi
  2023-10-05  0:05 ` [PATCH 1/3] io_uring: Fix check of BID wrapping in " Gabriel Krisman Bertazi
  2023-10-05  0:05 ` [PATCH 2/3] io_uring: Allow the full buffer id space for " Gabriel Krisman Bertazi
@ 2023-10-05  0:05 ` Gabriel Krisman Bertazi
  2023-10-05  2:18 ` [PATCH 0/3] trivial fixes and a cleanup of provided buffers Jens Axboe
  2023-10-05 14:38 ` Jens Axboe
  4 siblings, 0 replies; 7+ messages in thread
From: Gabriel Krisman Bertazi @ 2023-10-05  0:05 UTC (permalink / raw)
  To: axboe; +Cc: io-uring, jmoyer, Gabriel Krisman Bertazi

The allocation of struct io_buffer for metadata of provided buffers is
done through a custom allocator that directly gets pages and
fragments them.  But, slab would do just fine, as this is not a hot path
(in fact, it is a deprecated feature) and, by keeping a custom allocator
implementation we lose benefits like tracking, poisoning,
sanitizers. Finally, the custom code is more complex and requires
keeping the list of pages in struct ctx for no good reason.  This patch
cleans this path up and just uses slab.

I microbenchmarked it by forcing the allocation of a large number of
objects with the least number of io_uring commands possible (keeping
nbufs=USHRT_MAX), with and without the patch.  There is a slight
increase in time spent in the allocation with slab, of course, but even
when allocating to system resources exhaustion, which is not very
realistic and happened around 1/2 billion provided buffers for me, it
wasn't a significant hit in system time.  Specially if we think of a
real-world scenario, an application doing register/unregister of
provided buffers will hit ctx->io_buffers_cache more often than actually
going to slab.

Signed-off-by: Gabriel Krisman Bertazi <[email protected]>

---
changes from v1
  - reduce batch size to limit stack usage. (Jeff)
  - Don't check kmem_cache_alloc_bulk return for < 0 (Jeff)
---
 include/linux/io_uring_types.h |  2 --
 io_uring/io_uring.c            |  4 ++-
 io_uring/io_uring.h            |  1 +
 io_uring/kbuf.c                | 47 +++++++++++++++++++---------------
 4 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/include/linux/io_uring_types.h b/include/linux/io_uring_types.h
index 13d19b9be9f4..9dca731b1ca8 100644
--- a/include/linux/io_uring_types.h
+++ b/include/linux/io_uring_types.h
@@ -342,8 +342,6 @@ struct io_ring_ctx {
 	struct wait_queue_head		rsrc_quiesce_wq;
 	unsigned			rsrc_quiesce;
 
-	struct list_head		io_buffers_pages;
-
 	#if defined(CONFIG_UNIX)
 		struct socket		*ring_sock;
 	#endif
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 783ed0fff71b..548c32fc1e28 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -338,7 +338,6 @@ static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
 	spin_lock_init(&ctx->completion_lock);
 	spin_lock_init(&ctx->timeout_lock);
 	INIT_WQ_LIST(&ctx->iopoll_list);
-	INIT_LIST_HEAD(&ctx->io_buffers_pages);
 	INIT_LIST_HEAD(&ctx->io_buffers_comp);
 	INIT_LIST_HEAD(&ctx->defer_list);
 	INIT_LIST_HEAD(&ctx->timeout_list);
@@ -4681,6 +4680,9 @@ static int __init io_uring_init(void)
 				SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU,
 				offsetof(struct io_kiocb, cmd.data),
 				sizeof_field(struct io_kiocb, cmd.data), NULL);
+	io_buf_cachep = kmem_cache_create("io_buffer", sizeof(struct io_buffer), 0,
+					  SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT,
+					  NULL);
 
 #ifdef CONFIG_SYSCTL
 	register_sysctl_init("kernel", kernel_io_uring_disabled_table);
diff --git a/io_uring/io_uring.h b/io_uring/io_uring.h
index 547c30582fb8..2ff719ae1b57 100644
--- a/io_uring/io_uring.h
+++ b/io_uring/io_uring.h
@@ -330,6 +330,7 @@ static inline bool io_req_cache_empty(struct io_ring_ctx *ctx)
 }
 
 extern struct kmem_cache *req_cachep;
+extern struct kmem_cache *io_buf_cachep;
 
 static inline struct io_kiocb *io_extract_req(struct io_ring_ctx *ctx)
 {
diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c
index 12a357348733..d5a04467666f 100644
--- a/io_uring/kbuf.c
+++ b/io_uring/kbuf.c
@@ -22,6 +22,8 @@
 /* BIDs are addressed by a 16-bit field in a CQE */
 #define MAX_BIDS_PER_BGID (1 << 16)
 
+struct kmem_cache *io_buf_cachep;
+
 struct io_provide_buf {
 	struct file			*file;
 	__u64				addr;
@@ -258,6 +260,8 @@ static int __io_remove_buffers(struct io_ring_ctx *ctx,
 void io_destroy_buffers(struct io_ring_ctx *ctx)
 {
 	struct io_buffer_list *bl;
+	struct list_head *item, *tmp;
+	struct io_buffer *buf;
 	unsigned long index;
 	int i;
 
@@ -273,12 +277,9 @@ void io_destroy_buffers(struct io_ring_ctx *ctx)
 		kfree(bl);
 	}
 
-	while (!list_empty(&ctx->io_buffers_pages)) {
-		struct page *page;
-
-		page = list_first_entry(&ctx->io_buffers_pages, struct page, lru);
-		list_del_init(&page->lru);
-		__free_page(page);
+	list_for_each_safe(item, tmp, &ctx->io_buffers_cache) {
+		buf = list_entry(item, struct io_buffer, list);
+		kmem_cache_free(io_buf_cachep, buf);
 	}
 }
 
@@ -361,11 +362,12 @@ int io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
 	return 0;
 }
 
+#define IO_BUFFER_ALLOC_BATCH 64
+
 static int io_refill_buffer_cache(struct io_ring_ctx *ctx)
 {
-	struct io_buffer *buf;
-	struct page *page;
-	int bufs_in_page;
+	struct io_buffer *bufs[IO_BUFFER_ALLOC_BATCH];
+	int allocated;
 
 	/*
 	 * Completions that don't happen inline (eg not under uring_lock) will
@@ -385,22 +387,25 @@ static int io_refill_buffer_cache(struct io_ring_ctx *ctx)
 
 	/*
 	 * No free buffers and no completion entries either. Allocate a new
-	 * page worth of buffer entries and add those to our freelist.
+	 * batch of buffer entries and add those to our freelist.
 	 */
-	page = alloc_page(GFP_KERNEL_ACCOUNT);
-	if (!page)
-		return -ENOMEM;
 
-	list_add(&page->lru, &ctx->io_buffers_pages);
-
-	buf = page_address(page);
-	bufs_in_page = PAGE_SIZE / sizeof(*buf);
-	while (bufs_in_page) {
-		list_add_tail(&buf->list, &ctx->io_buffers_cache);
-		buf++;
-		bufs_in_page--;
+	allocated = kmem_cache_alloc_bulk(io_buf_cachep, GFP_KERNEL_ACCOUNT,
+					  ARRAY_SIZE(bufs), (void **) bufs);
+	if (unlikely(!allocated)) {
+		/*
+		 * Bulk alloc is all-or-nothing. If we fail to get a batch,
+		 * retry single alloc to be on the safe side.
+		 */
+		bufs[0] = kmem_cache_alloc(io_buf_cachep, GFP_KERNEL);
+		if (!bufs[0])
+			return -ENOMEM;
+		allocated = 1;
 	}
 
+	while (allocated)
+		list_add_tail(&bufs[--allocated]->list, &ctx->io_buffers_cache);
+
 	return 0;
 }
 
-- 
2.42.0


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

* Re: [PATCH 0/3] trivial fixes and a cleanup of provided buffers
  2023-10-05  0:05 [PATCH 0/3] trivial fixes and a cleanup of provided buffers Gabriel Krisman Bertazi
                   ` (2 preceding siblings ...)
  2023-10-05  0:05 ` [PATCH 3/3] io_uring: Use slab for struct io_buffer objects Gabriel Krisman Bertazi
@ 2023-10-05  2:18 ` Jens Axboe
  2023-10-05 14:25   ` Gabriel Krisman Bertazi
  2023-10-05 14:38 ` Jens Axboe
  4 siblings, 1 reply; 7+ messages in thread
From: Jens Axboe @ 2023-10-05  2:18 UTC (permalink / raw)
  To: Gabriel Krisman Bertazi; +Cc: io-uring, jmoyer

On 10/4/23 6:05 PM, Gabriel Krisman Bertazi wrote:
> Jens,
> 
> I'm resubmitting the slab conversion for provided buffers with the
> suggestions from Jeff (thanks!) for your consideration, and appended 2
> minor fixes related to kbuf in the patchset. Since the patchset grew
> from 1 to 3 patches, i pretended it is not a v2 and restart the
> counting from 1.

Thanks, this looks good. For patches 1-2, do you have test cases you
could send for liburing?

-- 
Jens Axboe


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

* Re: [PATCH 0/3] trivial fixes and a cleanup of provided buffers
  2023-10-05  2:18 ` [PATCH 0/3] trivial fixes and a cleanup of provided buffers Jens Axboe
@ 2023-10-05 14:25   ` Gabriel Krisman Bertazi
  0 siblings, 0 replies; 7+ messages in thread
From: Gabriel Krisman Bertazi @ 2023-10-05 14:25 UTC (permalink / raw)
  To: Jens Axboe; +Cc: io-uring, jmoyer

Jens Axboe <[email protected]> writes:

> On 10/4/23 6:05 PM, Gabriel Krisman Bertazi wrote:
>> Jens,
>> 
>> I'm resubmitting the slab conversion for provided buffers with the
>> suggestions from Jeff (thanks!) for your consideration, and appended 2
>> minor fixes related to kbuf in the patchset. Since the patchset grew
>> from 1 to 3 patches, i pretended it is not a v2 and restart the
>> counting from 1.
>
> Thanks, this looks good. For patches 1-2, do you have test cases you
> could send for liburing?

Sure. I'll adapt them to liburing and submit shortly.

-- 
Gabriel Krisman Bertazi

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

* Re: [PATCH 0/3] trivial fixes and a cleanup of provided buffers
  2023-10-05  0:05 [PATCH 0/3] trivial fixes and a cleanup of provided buffers Gabriel Krisman Bertazi
                   ` (3 preceding siblings ...)
  2023-10-05  2:18 ` [PATCH 0/3] trivial fixes and a cleanup of provided buffers Jens Axboe
@ 2023-10-05 14:38 ` Jens Axboe
  4 siblings, 0 replies; 7+ messages in thread
From: Jens Axboe @ 2023-10-05 14:38 UTC (permalink / raw)
  To: Gabriel Krisman Bertazi; +Cc: io-uring, jmoyer


On Wed, 04 Oct 2023 20:05:28 -0400, Gabriel Krisman Bertazi wrote:
> Jens,
> 
> I'm resubmitting the slab conversion for provided buffers with the
> suggestions from Jeff (thanks!) for your consideration, and appended 2
> minor fixes related to kbuf in the patchset. Since the patchset grew
> from 1 to 3 patches, i pretended it is not a v2 and restart the
> counting from 1.
> 
> [...]

Applied, thanks!

[1/3] io_uring: Fix check of BID wrapping in provided buffers
      commit: ab69838e7c75b0edb699c1a8f42752b30333c46f
[2/3] io_uring: Allow the full buffer id space for provided buffers
      commit: f74c746e476b9dad51448b9a9421aae72b60e25f
[3/3] io_uring: Use slab for struct io_buffer objects
      commit: b3a4dbc89d4021b3f90ff6a13537111a004f9d07

Best regards,
-- 
Jens Axboe




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

end of thread, other threads:[~2023-10-05 15:48 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-05  0:05 [PATCH 0/3] trivial fixes and a cleanup of provided buffers Gabriel Krisman Bertazi
2023-10-05  0:05 ` [PATCH 1/3] io_uring: Fix check of BID wrapping in " Gabriel Krisman Bertazi
2023-10-05  0:05 ` [PATCH 2/3] io_uring: Allow the full buffer id space for " Gabriel Krisman Bertazi
2023-10-05  0:05 ` [PATCH 3/3] io_uring: Use slab for struct io_buffer objects Gabriel Krisman Bertazi
2023-10-05  2:18 ` [PATCH 0/3] trivial fixes and a cleanup of provided buffers Jens Axboe
2023-10-05 14:25   ` Gabriel Krisman Bertazi
2023-10-05 14:38 ` Jens Axboe

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