BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Dudu Lu" <phx0fer@gmail.com>
Cc: bpf@vger.kernel.org
Subject: Re: [PATCH bpf] net: return page_pool frags to the pool in bpf_xdp_shrink_data()
Date: Wed, 21 Oct 2026 16:32:10 +0000	[thread overview]
Message-ID: <sashiko-outbox-180468@kernel.org> (raw)
In-Reply-To: <20261021155645.69120-1-phx0fer@gmail.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] net: bpf_xdp_shrink_data() unrefs page_pool on non-recycled shared frags
- [Low] bpf: multi-line comment style violation in bpf_xdp_shrink_data()
--

commit a0cb1ce1fd03b9aff34c23b2b43d38801d791b8d
Author: Dudu Lu <phx0fer@gmail.com>

net: return page_pool frags to the pool in bpf_xdp_shrink_data()

This commit updates bpf_xdp_shrink_data() in net/core/filter.c to check
whether a released fragment with MEM_TYPE_PAGE_SHARED is backed by a
page_pool and recycle it via napi_pp_put_page() before falling back to
__xdp_return(). This avoids freeing page_pool-backed fragments allocated
by skb_pp_cow_data() through page_frag_free() under generic xdp when the
rxq has no registered memory model.

> diff --git a/net/core/filter.c b/net/core/filter.c
> index b7ac145b68b1f..f17113ff29874 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c

[ ... ]

> @@ -4408,6 +4409,18 @@ static bool bpf_xdp_shrink_data(struct xdp_buff *xdp, skb_frag_t *frag,
>  	}
>  
>  	if (release) {
> +		/* The frag may be page_pool-backed even when the rxq's
> +		 * xdp_rxq_info carries no mem model (generic XDP on a
> +		 * driver that never registers one, e.g. loopback).  In that
> +		 * case mem_type is MEM_TYPE_PAGE_SHARED and __xdp_return()
> +		 * would free the page through page_frag_free(), leaving the
> +		 * page_pool's accounting dangling -- "page_pool leak".  Route
> +		 * page_pool pages back through the pool instead.
> +		 */

[Severity: Low]
This isn't a bug, but in bpf subsystem files such as net/core/filter.c,
should multi-line comments in bpf_xdp_shrink_data() have the opening /* on
its own line with the comment text starting on the following line?

> +		if (IS_ENABLED(CONFIG_PAGE_POOL) &&
> +		    mem_type == MEM_TYPE_PAGE_SHARED && napi_pp_put_page(netmem))
> +			return release;
> +
>  		__xdp_return(netmem, mem_type, false, zc_frag);

[Severity: High]
Can calling napi_pp_put_page(netmem) in bpf_xdp_shrink_data() when
mem_type == MEM_TYPE_PAGE_SHARED corrupt reference counts if the xdp_buff
owns a page->_refcount reference rather than a pp_ref_count reference?

On a veth interface with native xdp enabled, veth_xdp_rcv_skb() calls
veth_convert_skb_to_xdp_buff() -> skb_pp_cow_data(). For any trailing
fragment with size <= PAGE_SIZE / 2 (such as a 4000-byte packet),
page_pool_dev_alloc() -> page_pool_alloc_netmem() calls
page_pool_alloc_frag_netmem(), which fragments the page with BIAS_MAX:

net/core/page_pool.c:page_pool_alloc_frag_netmem() {
    ...
		pool->frag_page = netmem;

frag_reset:
		pool->frag_users = 1;
		*offset = 0;
		pool->frag_offset = size;
		page_pool_fragment_netmem(netmem, BIAS_MAX);
		return netmem;
}

When bpf_prog_run_xdp() returns XDP_TX or XDP_REDIRECT, veth_xdp_rcv_skb()
transfers ownership from the skb to the xdp_buff and switches the memory
model to rq->xdp_mem (which has type MEM_TYPE_PAGE_SHARED):

drivers/net/veth.c:veth_xdp_rcv_skb() {
    ...
	case XDP_TX:
		veth_xdp_get(xdp);
		consume_skb(skb);
		xdp->rxq->mem = rq->xdp_mem;
		if (unlikely(veth_xdp_tx(rq, xdp, bq) < 0)) {
    ...
}

Here, veth_xdp_get(xdp) increments page->_refcount via __skb_frag_ref(),
and consume_skb(skb) releases the skb's pp_ref_count reference via
napi_pp_put_page() (decrementing pp_ref_count from BIAS_MAX to
BIAS_MAX - 1). Because rq->page_pool->frag_page (or another skb sharing
the fragmented page) still holds the remaining pp_ref_count references,
pp_ref_count does not reach 0 and netmem_is_pp(netmem) remains true.

When a downstream program in veth_xdp_rcv_one(), dev_map_bpf_prog_run(),
or cpu_map_bpf_prog_run_xdp() shrinks and releases that fragment via
bpf_xdp_adjust_tail() or bpf_xdp_pull_data(), bpf_xdp_shrink_data() sees
mem_type == MEM_TYPE_PAGE_SHARED and netmem_is_pp(netmem) == true. Calling
napi_pp_put_page(netmem) decrements pp_ref_count a second time instead of
calling __xdp_return() -> page_frag_free() to drop the page->_refcount
reference.

Wouldn't this leak page->_refcount and cause page_pool_unref_netmem() to
underflow pp_ref_count (or prematurely recycle the page while other skbs
still hold fragments of it) when rq->page_pool drains frag_page?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261021155645.69120-1-phx0fer@gmail.com?part=1

  reply	other threads:[~2026-10-21 16:32 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-21 15:56 [PATCH bpf] net: return page_pool frags to the pool in bpf_xdp_shrink_data() Dudu Lu
2026-10-21 16:32 ` sashiko-bot [this message]
2026-10-21 16:59 ` bot+bpf-ci
2026-10-21 17:40 ` Alexei Starovoitov

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=sashiko-outbox-180468@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=phx0fer@gmail.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /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