[PATCH net v2 2/2] net: add a KUnit test for the alloc_skb_with_frags() tail split
From: Haishuang Yan
Date: Tue Nov 10 2026 - 03:41:44 EST
Allocate MAX_SKB_FRAGS - 2 full chunks of PAGE_ALLOC_COSTLY_ORDER plus
a 7 page tail. Rounding the tail down to 4 + 2 + 1 pages would need
one frag more than MAX_SKB_FRAGS, which made the allocation fail with
-ENOBUFS before "net: do not run out of frags in
alloc_skb_with_frags()".
If the allocation fails and no order-3 page can be had either, skip the
test instead of failing it, so that a host with fragmented memory does
not report this as a regression.
Signed-off-by: Haishuang Yan <yanhaishuang@xxxxxxxxxxxxxxxxxxxx>
---
net/core/net_test.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/net/core/net_test.c b/net/core/net_test.c
index 2b5080c226636..de4d246f2f7ab 100644
--- a/net/core/net_test.c
+++ b/net/core/net_test.c
@@ -1721,7 +1721,42 @@ static void netmem_ref_test_tcp_devmem_recv(struct kunit *test)
#endif
#endif
+static void alloc_skb_with_frags_test_tail(struct kunit *test)
+{
+ /* MAX_SKB_FRAGS - 2 full chunks plus a 7 page tail: rounding the
+ * tail down to 4 + 2 + 1 pages would need one frag too many.
+ */
+ unsigned long len = (MAX_SKB_FRAGS - 2) *
+ (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER) +
+ 7 * PAGE_SIZE;
+ unsigned long frags_len = 0;
+ struct sk_buff *skb;
+ int err, i;
+
+ skb = alloc_skb_with_frags(0, len, PAGE_ALLOC_COSTLY_ORDER, &err,
+ GFP_KERNEL);
+ if (!skb) {
+ struct page *page;
+
+ /* Don't report a lack of high-order pages as a failure. */
+ page = alloc_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY,
+ PAGE_ALLOC_COSTLY_ORDER);
+ if (!page)
+ kunit_skip(test, "no order-%d pages",
+ PAGE_ALLOC_COSTLY_ORDER);
+ __free_pages(page, PAGE_ALLOC_COSTLY_ORDER);
+ }
+ KUNIT_ASSERT_NOT_NULL_MSG(test, skb, "err %d", err);
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+ frags_len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
+ KUNIT_EXPECT_EQ(test, frags_len, len);
+
+ kfree_skb(skb);
+}
+
static struct kunit_case net_test_cases[] = {
+ KUNIT_CASE(alloc_skb_with_frags_test_tail),
KUNIT_CASE_PARAM(gso_test_func, gso_test_gen_params),
KUNIT_CASE_PARAM(ip_tunnel_flags_test_run,
ip_tunnel_flags_test_gen_params),
--
2.43.0