mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: bjorn@kernel.org
Cc: magnus.karlsson@intel.com, maciej.fijalkowski@intel.com,
	sdf@fomichev.me, davem@davemloft.net, edumazet@kernel.org,
	kuba@kernel.org, pabeni@redhat.com, horms@kernel.org,
	corbet@lwn.net, skhan@linuxfoundation.org, rdunlap@infradead.org,
	alexanderduyck@fb.com, kernel-team@meta.com,
	andrew+netdev@lunn.ch, hawk@kernel.org,
	ilias.apalodimas@linaro.org, ast@kernel.org,
	daniel@iogearbox.net, john.fastabend@gmail.com,
	asml.silence@gmail.com, axboe@kernel.dk, andrii@kernel.org,
	eddyz87@gmail.com, memxor@gmail.com, martin.lau@linux.dev,
	song@kernel.org, yonghong.song@linux.dev, jolsa@kernel.org,
	emil@etsalapatis.com, ihor.solodrai@linux.dev,
	netdev@vger.kernel.org, bpf@vger.kernel.org,
	io-uring@vger.kernel.org, almasrymina@google.com,
	mike.marciniszyn@gmail.com, bestswngs@gmail.com,
	razor@blackwall.org, dw@davidwei.uk,
	aleksander.lobakin@intel.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, stuclar@meta.com
Subject: Re: [PATCH net-next v1 11/11] eth: fbnic: Support AF_XDP page pool zero copy
Date: Wed, 11 Nov 2026 22:41:41 +0000	[thread overview]
Message-ID: <179443690174.2199510.10806656670743256191@kernel.org> (raw)
In-Reply-To: <20261110102039.1002605-12-bjorn@kernel.org>

Thank you for your contribution! Sashiko AI review found 5 potential
issue(s) to consider.

Critical: 0 · High: 1 · Medium: 1 · Low: 3

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [High] Stale, unreferenced xsk_buff_pool pointer is used after a failed
  queue restart during AF_XDP unbind.
- [Medium] On an AF_XDP provider queue, an empty FILL ring is normal flow
  control, but fbnic counts it as a buffer allocation failure.
- [Low] The commit message presents the balanced header/payload refill as
  something for the shared provider page pool ("Header and payload rings…
- [Low] The new "Zero-copy through page pool" section of
  Documentation/networking/af_xdp.rst says "MTU and XDP program changes…
- [Low] The new af_xdp.rst text says: "If the device cannot do zero-copy
  for the socket, a bind with XDP_ZEROCOPY fails with EOPNOTSUPP, while…

--

eth: fbnic: Support AF_XDP page pool zero copy

This adds AF_XDP zero-copy support to fbnic through a page pool memory
provider. The header and payload BDQs share one provider page pool and
use a new balanced refill policy, and socket TX descriptors go out on
the XDP TX ring from the RX NAPI after RX processing. It also adds
per-queue rx_headroom support and documents the page pool zero-copy mode
in af_xdp.rst.

> diff --git a/Documentation/networking/af_xdp.rst b/Documentation/networking/af_xdp.rst
> index e73a0005e169c..f152ae8812d17 100644
> --- a/Documentation/networking/af_xdp.rst
> +++ b/Documentation/networking/af_xdp.rst
> @@ -346,6 +346,64 @@ Note that a UMEM can be shared between sockets on the same queue id

[ ... ]

> +If the device cannot do zero-copy for the socket, a bind with
> +XDP_ZEROCOPY fails with EOPNOTSUPP, while a bind without it falls back
> +to copy mode. MTU and XDP program changes that a bound socket cannot
> +handle are refused.

[Severity: Low]
Does the page pool bind path always behave this way?

xsk_pp_bind() in net/xdp/xsk_pp.c returns -EBUSY when another queue has
an unreadable memory provider:

    if (!netif_all_mps_have_cap(dev, MP_CAP_READABLE))
        return -EBUSY;

It also passes on errors from the driver's XDP_VALIDATE_XSK_POOL check,
xp_dma_map(), xsk_pp_create() (-ENOMEM, -ERANGE) and netif_mp_open_rxq()
(for example -EEXIST, -EINVAL, -ENOMEM).

The copy-mode fallback is also conditional. In xp_assign_dev():

    if (!force_zc && !pool->pp)
        err = xp_alloc_heads(pool); /* fallback to copy mode */

Suppose netif_mp_open_rxq() fails, and then either xp_alloc_heads()
fails or xsk_pp_abandon() finds an old page pool still holding chunks.
In that case xsk_pp_bind() leaves pool->pp set, and a bind without
XDP_ZEROCOPY fails instead of falling back to copy mode.

Could the text mention the other errnos, and the case where copy mode is
not available?

[ ... ]

> +* advertises NETDEV_XDP_ACT_XSK_ZEROCOPY and xdp_zc_max_segs,
> +* checks the setup in XDP_VALIDATE_XSK_POOL, and sets xsk_page_pool
> +  in its netdev_queue_mgmt_ops.

[Severity: Low]
Should this list also say that the driver must call xsk_validate_dev()
from its own ndo_change_mtu?

In net/core/dev.c, the only callers of xsk_validate_dev() are the XDP
program install paths. No core MTU path calls it. fbnic refuses such MTU
changes only because this patch adds this to fbnic_change_mtu():

    err = xsk_validate_dev(dev, new_mtu, NULL, XDP_MODE_DRV, NULL);

A driver that follows only this list would accept MTU changes that a
bound socket cannot handle. One example is raising the MTU above the
header buffer size for a non-SG socket. The statement above that such
MTU changes are refused would then not hold.

[ ... ]

> diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
> index d96c957d6fbad..c358003f053b6 100644
> --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
> +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c

[ ... ]

> @@ -938,66 +969,146 @@ static void fbnic_bd_prep(struct fbnic_ring *bdq, u16 id, netmem_ref netmem)
>  	} while (--i);
>  }
>  
> +static bool fbnic_fill_bdq_one(struct fbnic_ring *bdq, unsigned int *tail)
> +{
> +	netmem_ref netmem;
> +
> +	netmem = page_pool_dev_alloc_netmems(bdq->page_pool);
> +	if (!netmem) {
> +		u64_stats_update_begin(&bdq->stats.syncp);
> +		bdq->stats.bdq.alloc_failed++;
> +		u64_stats_update_end(&bdq->stats.syncp);
> +
> +		return false;
> +	}

[Severity: Medium]
On an AF_XDP provider queue, xsk_pp_alloc_netmems() returns 0 whenever
the reuse stack and the FILL ring are empty. That is normal flow control
for the socket. Is it intended to count it as alloc_failed?

Without XDP_USE_NEED_WAKEUP, xsk_pp_refill_done() returns false in this
case:

    more = pp->reuse_cnt || xskq_cons_nb_entries(pp->fq, 1);
    WRITE_ONCE(pp->starved, !more);
    spin_unlock_bh(&pp->lock);

    return !more && wait;

fbnic_fill_bdqs() then returns false, fbnic_clean_rcq() returns budget,
and NAPI polls again at once. Each poll fails the allocation again and
increments the counter again.

This counter reaches userspace through the standard queue stats in
fbnic_netdev.c:

    rx->alloc_fail = fbn->rx_stats.rx.alloc_failed +
        fbn->bdq_stats.bdq.alloc_failed;

Won't an idle xsk queue then report a fast-growing alloc_fail count that
has nothing to do with memory pressure? With need_wakeup, each wakeup
that finds the FILL ring empty would also be counted.

[ ... ]

> +static bool fbnic_fill_bdqs(struct fbnic_q_triad *qt)
> +{
> +	struct fbnic_ring *hpq = &qt->sub0, *ppq = &qt->sub1;
> +	enum pp_refill state;
> +	bool done;
>  
> -		writel(i * fbnic_bd_page_count(bdq), bdq->doorbell);
> +	if (hpq->page_pool == ppq->page_pool) {
> +		fbnic_fill_shared_bdqs(hpq, ppq);

[Severity: Low]
The commit message says:

    Header and payload rings share one provider page pool, so refills even
    them out, and a short pool does not starve one of them.

In the default configuration, without AF_XDP, fbnic_alloc_qt_page_pools()
already shares one regular page pool between sub0 and sub1, through this
unchanged branch:

    } else {
        page_pool_get(pp);
    }
    qt->sub1.page_pool = pp;

So this test is true for every normal RX queue as well.
fbnic_fill_shared_bdqs() replaces the old policy, which filled the HPQ
fully and then filled the PPQ, on the default datapath. The new policy
interleaves per buffer through fbnic_hpq_takes_next(), which does u64
multiplications for each buffer. Filling of both rings also stops at the
first allocation failure.

Should the commit message mention this change to the existing datapath?
It also does not mention two other changes: QCFG_RX_HEADROOM is now
accepted, and RDE_CTL0 MIN_HROOM is programmed per queue.

> +		state = fbnic_bdq_state(hpq);
> +		if (state == PP_REFILL_FULL)
> +			state = fbnic_bdq_state(ppq);
> +		return page_pool_refill_done(hpq->page_pool, state);
>  	}

[ ... ]

> @@ -1674,8 +1901,29 @@ fbnic_alloc_qt_page_pools(struct fbnic_net *fbn, struct fbnic_q_triad *qt,
>  		.netdev	= fbn->netdev,
>  		.queue_idx = rxq_idx,
>  	};
> +	struct xsk_buff_pool *xsk;
>  	struct page_pool *pp;
>  

[ ... ]

> +	/* Payload buffers come from UMEM only for multi-buffer sockets */
> +	xsk = xsk_rxq_pool(fbn->netdev, rxq_idx);
> +	qt->xsk_pool = xsk;

[Severity: High]
This stores the xsk_buff_pool pointer without taking a reference, and
fbnic_queue_start() copies it into the live triad. What happens to this
pointer if the queue restart during unbind fails?

On socket close, this chain can fail:

__xp_clear_dev()
  xsk_pp_unbind()
    netif_mp_close_rxq()
      __netif_mp_close_rxq()
        netdev_rx_queue_reconfig()

Some ways it can fail:

- fbnic_queue_mem_alloc() returns -ENOMEM from page_pool_create(),
  kvzalloc() or the descriptor ring allocation.
- fbnic_queue_stop() fails through fbnic_wait_queue_idle().
- ndo_queue_start() fails and the old queue is restarted.

__netif_mp_close_rxq() only warns:

    err = netdev_rx_queue_reconfig(dev, rxq_idx, &qcfg[0], &qcfg[1]);
    if (err == -ENETDOWN)
        return 0;
    WARN_ON(err);
    return err;

xsk_pp_unbind() then ignores the result:

    netif_mp_close_rxq(pool->netdev, pool->queue_id, &mp);
    xsk_pp_detach(pp);

xsk_pp_detach() unmaps the DMA through xp_dma_unmap(), and xp_destroy()
later frees the pool. Meanwhile the old fbnic triad keeps running with
qt->xsk_pool still set.

On every poll, fbnic_poll()->fbnic_xsk_tx()->fbnic_xsk_tx_pool() calls
xsk_set_tx_need_wakeup(), xsk_tx_peek_release_desc_batch() and
xsk_buff_raw_get_dma() on that pool. Wouldn't these then read and write
freed memory? In-flight entries in ring->xdp_buf[].xsk would also be
passed to xsk_tx_completed() from fbnic_clean_twq1().

The xsk_rxq_pool() comment says "The pool stays valid while the queue
that the caller allocates runs", but that does not seem to hold on this
failure path. Part of the cause is the core error handling. Still, the
fbnic TX code added here is what keeps using the raw pointer.

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261110102039.1002605-1-bjorn%40kernel.org

      reply	other threads:[~2026-11-11 22:41 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 10:20 [PATCH net-next v1 00/11] xsk: Zero copy through page-pool memory providers Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 01/11] net: Get skb fragment addresses through netmem Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 02/11] net: Add memory provider capabilities Björn Töpel
2026-11-10 22:19   ` Stanislav Fomichev
2026-11-11 12:41     ` Björn Töpel
2026-11-11 23:01       ` Stanislav Fomichev
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 03/11] xdp: Copy buffers with restricted lifetime Björn Töpel
2026-11-10 22:32   ` Stanislav Fomichev
2026-11-11 13:27     ` Björn Töpel
2026-11-11 23:05       ` Stanislav Fomichev
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 04/11] xsk: Allocate UMEM chunks through page_pool Björn Töpel
2026-11-10 15:08   ` Magnus Karlsson
2026-11-11 13:51     ` Björn Töpel
2026-11-10 23:02   ` Stanislav Fomichev
2026-11-11 13:59     ` Björn Töpel
2026-11-11 23:09       ` Stanislav Fomichev
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 05/11] xsk: Install UMEM page pool providers in the core Björn Töpel
2026-11-10 23:50   ` Stanislav Fomichev
2026-11-11 14:01     ` Björn Töpel
2026-11-11  8:59   ` Magnus Karlsson
2026-11-11 19:26     ` Björn Töpel
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 06/11] page_pool: Coordinate refill with memory providers Björn Töpel
2026-11-10 23:51   ` Stanislav Fomichev
2026-11-11 19:37     ` Björn Töpel
2026-11-11 23:13       ` Stanislav Fomichev
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 07/11] xsk: Deliver provider chunks without copying Björn Töpel
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-11 23:20   ` Stanislav Fomichev
2026-11-10 10:20 ` [PATCH net-next v1 08/11] eth: fbnic: Support XDP redirect Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 09/11] eth: fbnic: Use netmem for RX headers and XDP_TX Björn Töpel
2026-11-10 10:20 ` [PATCH net-next v1 10/11] eth: fbnic: Support RX buffers it cannot split Björn Töpel
2026-11-11 21:45   ` Dimitri Daskalakis
2026-11-11 22:41   ` netdev-bot+sashiko
2026-11-10 10:20 ` [PATCH net-next v1 11/11] eth: fbnic: Support AF_XDP page pool zero copy Björn Töpel
2026-11-11 22:41   ` netdev-bot+sashiko [this message]

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=179443690174.2199510.10806656670743256191@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=aleksander.lobakin@intel.com \
    --cc=alexanderduyck@fb.com \
    --cc=almasrymina@google.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=andrii@kernel.org \
    --cc=asml.silence@gmail.com \
    --cc=ast@kernel.org \
    --cc=axboe@kernel.dk \
    --cc=bestswngs@gmail.com \
    --cc=bjorn@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=corbet@lwn.net \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=dw@davidwei.uk \
    --cc=eddyz87@gmail.com \
    --cc=edumazet@kernel.org \
    --cc=emil@etsalapatis.com \
    --cc=hawk@kernel.org \
    --cc=horms@kernel.org \
    --cc=ihor.solodrai@linux.dev \
    --cc=ilias.apalodimas@linaro.org \
    --cc=io-uring@vger.kernel.org \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kernel-team@meta.com \
    --cc=kuba@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maciej.fijalkowski@intel.com \
    --cc=magnus.karlsson@intel.com \
    --cc=martin.lau@linux.dev \
    --cc=memxor@gmail.com \
    --cc=mike.marciniszyn@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=razor@blackwall.org \
    --cc=rdunlap@infradead.org \
    --cc=sdf@fomichev.me \
    --cc=skhan@linuxfoundation.org \
    --cc=song@kernel.org \
    --cc=stuclar@meta.com \
    --cc=yonghong.song@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

all inboxes | Powered by JetHome®