quoted
+static int fec_enet_rx_queue_xdp(struct fec_enet_private *fep, int queue,
+ int budget, struct bpf_prog *prog)
+{
[ ... ]
quoted
+ switch (act) {
+ case XDP_PASS:
+ rxq->stats[RX_XDP_PASS]++;
+ /* The packet length includes FCS, but we don't want to
+ * include that when passing upstream as it messes up
+ * bridging applications.
+ */
+ skb = fec_build_skb(fep, rxq, bdp, page, pkt_len);
+ if (!skb) {
+ fec_xdp_drop(rxq, &xdp, sync);
+ trace_xdp_exception(ndev, prog, XDP_PASS);
+ } else {
+ napi_gro_receive(&fep->napi, skb);
+ }
+ break;
When fec_build_skb() fails, it already returns the page to the page pool
via page_pool_recycle_direct():
static struct sk_buff *fec_build_skb(...)
{
skb = build_skb(page_address(page), ...);
if (unlikely(!skb)) {
page_pool_recycle_direct(rxq->page_pool, page);
...
return NULL;
}
...
}
Calling fec_xdp_drop() after fec_build_skb() returns NULL will return
the same page to the pool a second time. Can this cause page pool
corruption under memory pressure when build_skb() fails?
Thanks for pointing this potential issue, I will fix it.