Re: [PATCH net v2] page_pool: keep frag_offset aligned for odd-sized requests
From: Fabricio Gava
Date: Sun Aug 30 2026 - 17:23:20 EST
On Fri, Aug 28, 2026 at 08:08:22AM +0200, Florian Schauer wrote:
> Tracing page_pool_alloc_frag_netmem() over one such run shows the
> amplification -- two odd-sized requests, nine misaligned offsets:
>
> requested size & 7: 0: 17035 5: 1 7: 1
> frag_offset & 7: 0: 17028 3: 1 4: 1 5: 1 6: 1 7: 5
Two things you may not have: a competing patch for this same defect, and a
measurement of how far the amplification goes under a different load.
The competing patch fixes the caller instead of the allocator:
net: skbuff: keep the page_pool fragment offset aligned in skb_pp_cow_data()
Bruno Xavier <bfxavier@xxxxxxxxx>, 2026-08-27
https://lore.kernel.org/netdev/20260827122926.31123-1-bfxavier@xxxxxxxxx/
Its Notes: section describes your change as "the alternative" and offers to
send that version instead -- the two look to have been written
independently, a day apart. Both are in state "new" with no review comments
on either thread, so a maintainer opening one cannot see the other. I have
copied Bruno here.
On the numbers: an independent reproduction on a third configuration.
Fedora 44, kernels 7.1.8 / 7.1.9 / 7.1.10, Intel i5-13420H, NetBird v0.77.1,
which attaches a SEC("xdp.frags") program to lo and holds an unbound raw
IPPROTO_UDP socket. Eight panics, all skb_clone+0x159, six from
raw_v4_input() and two from ipv6_raw_deliver(). Same tracing as yours, over
a 12 s run of a reproducer generating UDP datagrams of 1400..63000 B on
loopback:
total aligned misaligned
size requested from
page_pool_alloc_frag_netmem() 1876609 23.7% 76.3%
*offset returned by the pool 1876609 31.9% 68.1%
skb->head from napi_build_skb() 2314689 91.8% 8.2%
Your trace shows 2 odd-sized requests out of 17037 (0.01%); driving
skb_pp_cow_data()'s fragment loop with varied datagram sizes puts it at 76%.
Once an odd-sized request has moved frag_offset off alignment, the
allocations carved out of that page afterwards are misaligned too, until the
accumulated sizes happen to land back on a multiple of 8 -- which is why the
share of misaligned offsets (68%) is so much higher than the rate of odd
requests alone would suggest. If the changelog needs an argument for the
stable backport, this is one: the rate is workload-dependent, and it is not
bounded by anything.
On coverage, which is the part that may bear on which fix is preferred:
skb_pp_cow_data() is not the only caller passing a raw length to the per-cpu
system_page_pool. xdp_copy_frags_from_zc() does the same, at
net/core/xdp.c:700:
const skb_frag_t *frag = &xinfo->frags[i];
u32 len = skb_frag_size(frag);
u32 offset, truesize = len;
struct page *page;
page = page_pool_dev_alloc(pp, &offset, &truesize);
and its caller xdp_build_skb_from_zc() takes that pp from
this_cpu_read(system_page_pool.pool) at xdp.c:753, then feeds
page_pool_dev_alloc_va() at xdp.c:754 into napi_build_skb() at xdp.c:758. So
that path both leaves odd frag_offsets behind and consumes the head
allocations that follow them, on the same per-cpu pool. All three callers
of page_pool_dev_alloc() in the tree pass an unrounded size --
enic_rq.c:277-291 asks for netdev->mtu + VLAN_ETH_HLEN, plus xdp.c:702 and
skbuff.c:988 -- and
where a caller is safe it is because it rounds on its own beforehand, as
virtio_net does with ALIGN(len, L1_CACHE_BYTES) at virtio_net.c:2710.
I measured the attribution rather than only arguing it, and it does not
settle the question: over ~75 s and some 8.6 million fragment requests, the
probe saw none originating outside skb_pp_cow_data(). That is what one
should expect on this box, which drives neither the AF_XDP zero-copy path
nor a page_pool-backed NIC driver, so no other producer was exercised. It
says the caller-side fix would be enough for this workload, not that it is
enough.
One observation for the changelog, if useful: the skbs that actually panic
are small and linear (48..222 B, data_len == 0, ordinary DNS traffic). The
large non-linear packets are what leave frag_offset odd; they are not the
victims. That makes the failure look unrelated to the traffic causing it,
and it is why reports of this are easy to misattribute to whatever process
happened to be running the softirq.
We have not built and run the patch here; a Tested-by: will follow
separately if we measure a patched kernel.
Thanks,
Fabricio Gava