Linux io-uring development
 help / color / mirror / Atom feed
From: Pavel Begunkov <asml.silence@gmail.com>
To: io-uring@vger.kernel.org
Cc: asml.silence@gmail.com, netdev@vger.kernel.org
Subject: [PATCH review-only 01/17] io_uring/zcrx: scale refilling with large pages
Date: Sat, 11 Jul 2026 10:11:24 +0100	[thread overview]
Message-ID: <dea84f254f89c7e799a24790f2ebc37a08b59720.1783616211.git.asml.silence@gmail.com> (raw)
In-Reply-To: <cover.1783616211.git.asml.silence@gmail.com>

io_zcrx_ring_refill() caps the loop by mixing the max number of
allocated netmems and the number of available RQEs together, which
caps the number of entries to process the pp cache size. As a result,
when niovs are heavily fragmented, the refilling logic allocates only a
small number of niovs per call on average and sometimes even none.

Keep a separate counter for the number of processed RQ entries, which is
capped by a roughly calculated from the page size value to keep the
cache full. And separately break if it allocates enough niovs.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 io_uring/zcrx.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c
index 6bd71435e475..8348413d6d24 100644
--- a/io_uring/zcrx.c
+++ b/io_uring/zcrx.c
@@ -28,6 +28,13 @@
 #include "zcrx.h"
 #include "rsrc.h"
 
+#define ZCRX_MAX_FRAGS_PER_PAGE MAX(PAGE_SIZE / 1024, 1)
+/*
+ * We need a reasonable limit to be able to fill in 64 entries on average
+ * for 1500 byte MTU. Over-estimate it to keep it pow2.
+ */
+#define ZCRX_REFILL_CAP MIN(64 * ZCRX_MAX_FRAGS_PER_PAGE, 1024)
+
 #define IO_ZCRX_AREA_SUPPORTED_FLAGS	(IORING_ZCRX_AREA_DMABUF)
 
 #define IO_DMA_ATTR (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
@@ -1125,17 +1132,15 @@ static unsigned io_zcrx_ring_refill(struct page_pool *pp,
 {
 	struct zcrx_rq *rq = &ifq->rq;
 	unsigned int mask = rq->nr_entries - 1;
-	unsigned int entries;
+	unsigned int rqes_left;
 	unsigned allocated = 0;
 
 	guard(spinlock_bh)(&rq->lock);
 
-	entries = zcrx_rq_entries(rq);
-	entries = min_t(unsigned, entries, to_alloc);
-	if (unlikely(!entries))
-		return 0;
+	rqes_left = zcrx_rq_entries(rq);
+	rqes_left = min_t(unsigned, rqes_left, ZCRX_REFILL_CAP);
 
-	do {
+	for (; rqes_left; rqes_left--) {
 		struct io_uring_zcrx_rqe *rqe = zcrx_next_rqe(rq, mask);
 		struct net_iov *niov;
 		netmem_ref netmem;
@@ -1156,7 +1161,9 @@ static unsigned io_zcrx_ring_refill(struct page_pool *pp,
 
 		netmems[allocated] = netmem;
 		allocated++;
-	} while (--entries);
+		if (allocated >= to_alloc)
+			break;
+	}
 
 	smp_store_release(&rq->ring->head, rq->cached_head);
 	return allocated;
-- 
2.54.0


WARNING: multiple messages have this Message-ID (diff)
From: Pavel Begunkov <asml.silence@gmail.com>
To: io-uring@vger.kernel.org
Cc: asml.silence@gmail.com, netdev@vger.kernel.org
Subject: [PATCH review-only 01/17] io_uring/zcrx: scale refilling with large pages
Date: Sat, 11 Jul 2026 11:39:54 +0100	[thread overview]
Message-ID: <dea84f254f89c7e799a24790f2ebc37a08b59720.1783616211.git.asml.silence@gmail.com> (raw)
Message-ID: <20260711103954.puRwlXkJVgPKH-HXv8WY4-TzJ5YHVCl29j0xSYRRq5A@z> (raw)
In-Reply-To: <cover.1783616211.git.asml.silence@gmail.com>

io_zcrx_ring_refill() caps the loop by mixing the max number of
allocated netmems and the number of available RQEs together, which
caps the number of entries to process the pp cache size. As a result,
when niovs are heavily fragmented, the refilling logic allocates only a
small number of niovs per call on average and sometimes even none.

Keep a separate counter for the number of processed RQ entries, which is
capped by a roughly calculated from the page size value to keep the
cache full. And separately break if it allocates enough niovs.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 io_uring/zcrx.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c
index 6bd71435e475..8348413d6d24 100644
--- a/io_uring/zcrx.c
+++ b/io_uring/zcrx.c
@@ -28,6 +28,13 @@
 #include "zcrx.h"
 #include "rsrc.h"
 
+#define ZCRX_MAX_FRAGS_PER_PAGE MAX(PAGE_SIZE / 1024, 1)
+/*
+ * We need a reasonable limit to be able to fill in 64 entries on average
+ * for 1500 byte MTU. Over-estimate it to keep it pow2.
+ */
+#define ZCRX_REFILL_CAP MIN(64 * ZCRX_MAX_FRAGS_PER_PAGE, 1024)
+
 #define IO_ZCRX_AREA_SUPPORTED_FLAGS	(IORING_ZCRX_AREA_DMABUF)
 
 #define IO_DMA_ATTR (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
@@ -1125,17 +1132,15 @@ static unsigned io_zcrx_ring_refill(struct page_pool *pp,
 {
 	struct zcrx_rq *rq = &ifq->rq;
 	unsigned int mask = rq->nr_entries - 1;
-	unsigned int entries;
+	unsigned int rqes_left;
 	unsigned allocated = 0;
 
 	guard(spinlock_bh)(&rq->lock);
 
-	entries = zcrx_rq_entries(rq);
-	entries = min_t(unsigned, entries, to_alloc);
-	if (unlikely(!entries))
-		return 0;
+	rqes_left = zcrx_rq_entries(rq);
+	rqes_left = min_t(unsigned, rqes_left, ZCRX_REFILL_CAP);
 
-	do {
+	for (; rqes_left; rqes_left--) {
 		struct io_uring_zcrx_rqe *rqe = zcrx_next_rqe(rq, mask);
 		struct net_iov *niov;
 		netmem_ref netmem;
@@ -1156,7 +1161,9 @@ static unsigned io_zcrx_ring_refill(struct page_pool *pp,
 
 		netmems[allocated] = netmem;
 		allocated++;
-	} while (--entries);
+		if (allocated >= to_alloc)
+			break;
+	}
 
 	smp_store_release(&rq->ring->head, rq->cached_head);
 	return allocated;
-- 
2.54.0


  reply	other threads:[~2026-07-11  9:12 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-11  9:11 [PATCH review-only 00/17] zcrx RQ improvements and dynamic memory provisioning Pavel Begunkov
2026-07-11  9:11 ` Pavel Begunkov [this message]
2026-07-11 10:39   ` [PATCH review-only 01/17] io_uring/zcrx: scale refilling with large pages Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 02/17] io_uring/zcrx: move RQ head/tail to separate cache lines Pavel Begunkov
2026-07-11 10:39   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 03/17] io_uring/zcrx: add RQ iterator Pavel Begunkov
2026-07-11 10:39   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 04/17] io_uring/zcrx: cache RQ tail Pavel Begunkov
2026-07-11 10:39   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 05/17] io_uring/zcrx: coalesce same-niov RQEs on refill Pavel Begunkov
2026-07-11 10:39   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 06/17] io_uring/zcrx: constify area_reg on import Pavel Begunkov
2026-07-11 10:39   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 07/17] io_uring/zcrx: add helper for deriving area token Pavel Begunkov
2026-07-11 10:40   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 08/17] io_uring/zcrx: don't pass ifq_reg to area creation Pavel Begunkov
2026-07-11 10:40   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 09/17] io_uring/zcrx: split dmabuf unmap and release Pavel Begunkov
2026-07-11 10:40   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 10/17] io_uring/zcrx: unmap under netdev lock Pavel Begunkov
2026-07-11 10:40   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 11/17] io_uring/zcrx: split append out of area creation Pavel Begunkov
2026-07-11 10:40   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 12/17] io_uring/zcrx: move freelist lock to struct zcrx Pavel Begunkov
2026-07-11 10:40   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 13/17] io_uring/zcrx: array of areas Pavel Begunkov
2026-07-11 10:40   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 14/17] io_uring/zcrx: pass area_id to __zcrx_create_area() Pavel Begunkov
2026-07-11 10:40   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 15/17] io_uring/zcrx: add dynamic area creation Pavel Begunkov
2026-07-11 10:40   ` Pavel Begunkov
2026-07-11  9:11 ` [PATCH review-only 16/17] io_urint/zcrx: narrow var scope in io_zcrx_recv_skb() Pavel Begunkov
2026-07-11 10:40   ` Pavel Begunkov
2026-07-11 10:39 ` [PATCH review-only 00/17] zcrx RQ improvements and dynamic memory provisioning Pavel Begunkov
2026-07-11 10:39 ` [PATCH RESEND " Pavel Begunkov
2026-07-11 10:40 ` [PATCH review-only 17/17] io_uring/zcrx: don't reload skb_shinfo Pavel Begunkov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=dea84f254f89c7e799a24790f2ebc37a08b59720.1783616211.git.asml.silence@gmail.com \
    --to=asml.silence@gmail.com \
    --cc=io-uring@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox