mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Alex Markuze <amarkuze@redhat.com>
To: "David S . Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@kernel.org>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: Simon Horman <horms@kernel.org>,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [RFC PATCH net-next 3/4] net: skb_splice_from_iter(): walk ITER_BVEC segments directly
Date: Tue, 10 Nov 2026 11:23:24 +0000	[thread overview]
Message-ID: <20261110112325.3263078-4-amarkuze@redhat.com> (raw)
In-Reply-To: <20261110112325.3263078-1-amarkuze@redhat.com>

ITER_BVEC already describes source pages and byte ranges. Walk its
segments directly instead of extracting a temporary page array and
reconstructing those ranges.

Split at folio and representation boundaries, retaining page-bounded
fragments on HIGHMEM. Reuse the fragment append and checksum helpers.
Advance only by appended bytes, leaving a short request's remainder
available for another skb. Compare a positive limit with the unsigned
iterator count before assigning the bounded result to ssize_t.

Other iterator types keep the page-extraction path.

Signed-off-by: Alex Markuze <amarkuze@redhat.com>
---
 net/core/skbuff.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 3a66a50513a3..189fe25293ac 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -7550,6 +7550,75 @@ static void skb_splice_csum_range(struct sk_buff *skb, struct page *page,
 	}
 }
 
+/*
+ * Splice from an ITER_BVEC by walking its segments: there is no page array
+ * to fill.  Direct-mapped folio runs are split only at representation
+ * boundaries; CONFIG_HIGHMEM builds retain page-bounded fragments.
+ */
+static ssize_t skb_splice_from_bvec(struct sk_buff *skb, struct iov_iter *iter,
+				    ssize_t maxsize, size_t frag_limit)
+{
+	const struct bio_vec *bv = iter->bvec;
+	size_t skip = iter->iov_offset;
+	ssize_t spliced = 0, ret = 0;
+	unsigned long seg;
+
+	if (maxsize <= 0)
+		return 0;
+	maxsize = min_t(size_t, maxsize, iter->count);
+	for (seg = 0; seg < iter->nr_segs && maxsize > 0; seg++, skip = 0) {
+		size_t boff = bv[seg].bv_offset + skip;
+		size_t blen = min_t(size_t, bv[seg].bv_len - skip, maxsize);
+
+		while (blen) {
+			struct page *page, *fpage;
+			struct folio *folio;
+			size_t foff, part;
+
+			page = bv[seg].bv_page + (boff >> PAGE_SHIFT);
+			folio = page_folio(page);
+			if (IS_ENABLED(CONFIG_HIGHMEM)) {
+				fpage = page;
+				foff = offset_in_page(boff);
+				part = min_t(size_t, blen, PAGE_SIZE - foff);
+			} else {
+				struct skb_splice_frag range;
+				u64 pos = ((u64)folio_page_idx(folio, page) << PAGE_SHIFT) +
+					  offset_in_page(boff);
+
+				part = min_t(u64, blen, folio_size(folio) - pos);
+				range = skb_splice_frag_normalize(pos, part);
+				fpage = folio_page(folio, range.anchor >> PAGE_SHIFT);
+				foff = range.offset;
+				part = range.len;
+			}
+
+			ret = -EIO;
+			if (WARN_ON_ONCE(!sendpage_ok(fpage)))
+				goto out;
+
+			ret = skb_append_pagefrags(skb, fpage, foff, part, frag_limit);
+			if (ret < 0)
+				goto out;
+
+			if (skb->ip_summed == CHECKSUM_NONE)
+				skb_splice_csum_range(skb, page,
+						      offset_in_page(boff),
+						      part, skb->len + spliced);
+
+			boff += part;
+			blen -= part;
+			spliced += part;
+			maxsize -= part;
+		}
+	}
+
+out:
+	iov_iter_advance(iter, spliced);
+	skb_len_add(skb, spliced);
+	return spliced ?: ret;
+}
+
 /**
  * skb_splice_from_iter - Splice (or copy) pages to skbuff
  * @skb: The buffer to add pages to
@@ -7564,6 +7633,7 @@ static void skb_splice_csum_range(struct sk_buff *skb, struct page *page,
  * or a tail page of that folio and holds one reference on the folio either
  * way.  On CONFIG_HIGHMEM builds a fragment stays within one actual page
  * of the folio, because kmap_local_page() maps only one page.
+ * A bvec iterator is walked directly, without extracting a page array.
  *
  * Returns the amount of data spliced/copied or -EMSGSIZE if there's
  * insufficient space in the buffer to transfer anything.
@@ -7579,6 +7649,9 @@ ssize_t skb_splice_from_iter(struct sk_buff *skb, struct iov_iter *iter,
 	if (!maxsize)
 		return 0;
 
+	if (iov_iter_is_bvec(iter))
+		return skb_splice_from_bvec(skb, iter, maxsize, frag_limit);
+
 	while (iter->count > 0) {
 		ssize_t space, nr, len;
 		size_t off;
-- 
2.34.1


  parent reply	other threads:[~2026-11-10 11:23 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 11:23 [RFC PATCH net-next 0/4] net: streamline skb_splice_from_iter() Alex Markuze
2026-11-10 11:23 ` [RFC PATCH net-next 1/4] net: preserve splice iterator progress on rejection Alex Markuze
2026-11-10 11:23 ` [RFC PATCH net-next 2/4] net: skb_splice_from_iter(): group consecutive pages of a folio Alex Markuze
2026-11-10 11:23 ` Alex Markuze [this message]
2026-11-10 11:23 ` [RFC PATCH net-next 4/4] net: add basic splice KUnit tests Alex Markuze
2026-11-10 11:26 ` [RFC PATCH net-next 0/4] net: streamline skb_splice_from_iter() netdev-bot+sinfo

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=20261110112325.3263078-4-amarkuze@redhat.com \
    --to=amarkuze@redhat.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    /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

all inboxes | Powered by JetHome®