Re: [PATCH bpf] xsk: Do not free ZC Rx buffer when the Rx ring is full
From: bot+bpf-ci
Date: Mon Oct 19 2026 - 05:05:00 EST
> xsk: Do not free ZC Rx buffer when the Rx ring is full
TL;DR: Since xsk_rcv_zc() no longer frees the buffer on a full Rx ring, gve
DQO zero-copy Rx may leak one UMEM frame per dropped packet and eventually
stall AF_XDP Rx; it likely needs xsk_buff_free().
> diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
> index 33475b180ea6..0edc160c660f 100644
> --- a/net/xdp/xsk.c
> +++ b/net/xdp/xsk.c
[ ... ]
> @@ -252,9 +246,6 @@ static int xsk_rcv_zc(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
> }
>
> return 0;
> -err:
> - xsk_buff_free(xdp);
> - return err;
> }
>
> static void *xsk_copy_xdp_start(struct xdp_buff *from)
Can this leak the UMEM frame in the gve DQO zero-copy Rx path?
With this change xsk_rcv_zc() no longer frees the buffer when the Rx ring
is full and it returns -ENOBUFS, so every zero-copy driver has to free or
keep the buffer itself when xdp_do_redirect() fails. i40e and ice are
updated here, but gve DQO also relied on the core free:
drivers/net/ethernet/google/gve/gve_rx_dqo.c:gve_xsk_done_dqo() {
...
case XDP_REDIRECT:
if (unlikely(xdp_do_redirect(priv->dev, xdp, xprog)))
goto err;
break;
...
err:
u64_stats_update_begin(&rx->statss);
...
if (xdp_act == XDP_REDIRECT)
rx->xdp_redirect_errors++;
u64_stats_update_end(&rx->statss);
}
The err: path only updates stats and never calls xsk_buff_free(xdp).
The caller, gve_rx_xsk_dqo(), then calls gve_free_buf_state(rx, buf_state),
which puts the buf_state back on the free list. gve_alloc_buf_state() later
sets buf_state->xsk_buff = NULL without freeing it, and the ring-stop cleanup
only frees xsk buffers attached to allocated buf_states, so nothing calls
xp_free() on this buffer.
The path that gets there is:
gve_rx_dqo()
gve_rx_xsk_dqo()
gve_xsk_done_dqo()
xdp_do_redirect()
__xdp_do_redirect_xsk()
__xsk_map_redirect()
xsk_rcv()
xsk_rcv_zc()
__xsk_rcv_zc()
xskq_prod_reserve_desc() returns -ENOBUFS
Before this patch the err: label in xsk_rcv_zc() freed the buffer in exactly
this case, which is the scenario the commit targets (user space not keeping
up with the Rx ring). After this patch gve DQO leaks one UMEM frame for
each packet dropped because the ring is full. The frame never returns to
the pool free list or to user space, so under sustained overload
xsk_buff_alloc() starts failing in gve_alloc_buffer() and AF_XDP Rx on that
queue stalls until the socket is torn down.
The commit message says "A failed xdp_do_redirect() leaves the buffer owned
by the caller, and drivers rely on that" and names only i40e and ice as
relying on the core free. Does gve_xsk_done_dqo() need an xsk_buff_free(xdp)
on the XDP_REDIRECT failure path as part of this change?
The other zero-copy drivers that were checked (ixgbe, igb, igc, libeth/idpf,
gve GQI, mlx5, tsnep, fec, dpaa2, nfp, stmmac, icssg and virtio_net) already
free, recycle or keep the buffer on redirect failure.
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/39223384647