mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
Merge branch 'eth-bnxt-fix-rx-buffer-leaks-under-oom'
Jakub Kicinski says:
====================
eth: bnxt: fix Rx buffer leaks under OOM
Commit bd3beb5c86 ("eth: bnxt: disable rx-copybreak by default")
changed the defaults putting users on buggy(ier) driver paths.
Fix various ways bnxt may leak buffers under OOM. The first patch
fixes the real bug that was hit in production. Second patch fixes
an issue I hit while testing the first one. The next 3 patches
fix other Rx buffer leaks pointed out by an LLM during review.
====================
Link: https://patch.msgid.link/20261027234940.1267225-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
59e72644a7
|
|
@ -1215,7 +1215,15 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
|
|||
bp->rx_dir);
|
||||
skb = napi_build_skb(frag_start, rxr->rx_page_size);
|
||||
if (!skb) {
|
||||
page_pool_recycle_direct(rxr->page_pool, page);
|
||||
struct page *new_page;
|
||||
|
||||
new_page = rxr->rx_buf_ring[RING_RX(bp, prod)].data;
|
||||
/* The caller may still need the XDP frags from shinfo at the
|
||||
* end of the head page. Release the new buffer instead and
|
||||
* put the head back on the ring.
|
||||
*/
|
||||
page_pool_recycle_direct(rxr->page_pool, new_page);
|
||||
bnxt_reuse_rx_data(rxr, cons, data);
|
||||
return NULL;
|
||||
}
|
||||
skb_mark_for_recycle(skb);
|
||||
|
|
@ -1419,16 +1427,19 @@ static u32 bnxt_rx_agg_netmems_xdp(struct bnxt *bp,
|
|||
struct skb_shared_info *shinfo = xdp_get_shared_info_from_buff(xdp);
|
||||
u32 total_frag_len = 0;
|
||||
|
||||
if (!xdp_buff_has_frags(xdp))
|
||||
if (!xdp_buff_has_frags(xdp)) {
|
||||
xdp_buff_set_frags_flag(xdp);
|
||||
shinfo->nr_frags = 0;
|
||||
}
|
||||
|
||||
total_frag_len = __bnxt_rx_agg_netmems(bp, cpr, idx, agg_bufs, tpa,
|
||||
NULL, xdp);
|
||||
if (total_frag_len) {
|
||||
xdp_buff_set_frags_flag(xdp);
|
||||
shinfo->nr_frags = agg_bufs;
|
||||
shinfo->xdp_frags_size = total_frag_len;
|
||||
if (!total_frag_len) {
|
||||
bnxt_xdp_buff_frags_free(cpr->bnapi->rx_ring, xdp);
|
||||
return 0;
|
||||
}
|
||||
shinfo->nr_frags = agg_bufs;
|
||||
shinfo->xdp_frags_size = total_frag_len;
|
||||
return total_frag_len;
|
||||
}
|
||||
|
||||
|
|
@ -1500,6 +1511,14 @@ static struct sk_buff *bnxt_copy_xdp(struct bnxt_napi *bnapi,
|
|||
__skb_pull(skb, metasize);
|
||||
}
|
||||
|
||||
if (unlikely(xdp_buff_has_frags(xdp))) {
|
||||
struct skb_shared_info *sinfo;
|
||||
|
||||
sinfo = xdp_get_shared_info_from_buff(xdp);
|
||||
memcpy(skb_shinfo(skb)->frags, sinfo->frags,
|
||||
sinfo->nr_frags * sizeof(skb_frag_t));
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
|
|
@ -2285,8 +2304,10 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
|
|||
cp_cons,
|
||||
agg_bufs,
|
||||
false);
|
||||
if (!frag_len)
|
||||
if (!frag_len) {
|
||||
bnxt_reuse_rx_data(rxr, cons, data);
|
||||
goto oom_next_rx;
|
||||
}
|
||||
|
||||
}
|
||||
xdp_active = true;
|
||||
|
|
@ -2313,17 +2334,8 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
|
|||
skb = bnxt_copy_xdp(bnapi, &bnxt_xdp.xdp, len,
|
||||
dma_addr);
|
||||
bnxt_reuse_rx_data(rxr, cons, data);
|
||||
if (!skb) {
|
||||
if (agg_bufs) {
|
||||
if (!xdp_active)
|
||||
bnxt_reuse_rx_agg_bufs(cpr, cp_cons, 0,
|
||||
agg_bufs, false);
|
||||
else
|
||||
bnxt_xdp_buff_frags_free(rxr,
|
||||
&bnxt_xdp.xdp);
|
||||
}
|
||||
goto oom_next_rx;
|
||||
}
|
||||
if (!skb)
|
||||
goto oom_next_rx_agg;
|
||||
} else {
|
||||
u32 payload;
|
||||
|
||||
|
|
@ -2334,7 +2346,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
|
|||
skb = bp->rx_skb_func(bp, rxr, cons, data, data_ptr, dma_addr,
|
||||
payload | len);
|
||||
if (!skb)
|
||||
goto oom_next_rx;
|
||||
goto oom_next_rx_agg;
|
||||
}
|
||||
|
||||
if (agg_bufs) {
|
||||
|
|
@ -2424,6 +2436,14 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
|
|||
|
||||
return rc;
|
||||
|
||||
oom_next_rx_agg:
|
||||
if (agg_bufs) {
|
||||
if (!xdp_active)
|
||||
bnxt_reuse_rx_agg_bufs(cpr, cp_cons, 0, agg_bufs,
|
||||
false);
|
||||
else
|
||||
bnxt_xdp_buff_frags_free(rxr, &bnxt_xdp.xdp);
|
||||
}
|
||||
oom_next_rx:
|
||||
cpr->sw_stats->rx.rx_oom_discards += 1;
|
||||
rc = -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -4601,6 +4601,7 @@ static int bnxt_set_tunable(struct net_device *dev,
|
|||
if (netif_running(dev))
|
||||
return -EBUSY;
|
||||
bp->rx_copybreak = rx_copybreak;
|
||||
bnxt_set_ring_params(bp);
|
||||
}
|
||||
return 0;
|
||||
case ETHTOOL_PFC_PREVENTION_TOUT:
|
||||
|
|
|
|||
|
|
@ -307,6 +307,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
|
|||
|
||||
if (xdp_do_redirect(bp->dev, xdp, xdp_prog)) {
|
||||
trace_xdp_exception(bp->dev, xdp_prog, act);
|
||||
bnxt_xdp_buff_frags_free(rxr, xdp);
|
||||
page_pool_recycle_direct(rxr->page_pool, page);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user