[PATCH net v6 1/4] octeon_ep: free the dropped RX buffer pages
From: Maoyi Xie <hidden>
Date: 2026-07-22 15:51:43
Also in:
lkml
Subsystem:
networking drivers, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
octep_oq_drop_rx() drains a dropped multi-buffer RX packet but never
frees its pages. It unmaps each fragment descriptor and leaves the page
behind. It also reuses the head buff_info for every fragment.
octep_oq_next_pkt() then clears the head slot again instead of the
fragment slot. The fragment slots keep their page pointers. A later ring
teardown unmaps those descriptors a second time. The build_skb() failure
path frees no page either. The head page leaks too.
octep_oq_drop_rx() now indexes each fragment slot. It unmaps the slot and
frees its page. The unmap stays before the free to keep the DMA API
contract. The build_skb() failure path frees the head page.
buff_info->len comes from the device and is not bounded. The drain length
derives from it. A bad length could run the loop past the ring. It would
then free live pages of other packets. The loop now stops after
MAX_SKB_FRAGS fragments. A valid packet never holds more.
Fixes: eb592008f79b ("octeon_ep: Add SKB allocation failures handling in __octep_oq_process_rx()")
Co-developed-by: Kaixuan Li <redacted>
Signed-off-by: Kaixuan Li <redacted>
Signed-off-by: Maoyi Xie <redacted>
---
drivers/net/ethernet/marvell/octeon_ep/octep_rx.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
index e6ebc7e44a..b0162fb9d9 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c@@ -388,9 +388,15 @@ static void octep_oq_drop_rx(struct octep_oq *oq, u32 *read_idx, u32 *desc_used) { int data_len = buff_info->len - oq->max_single_buffer_size; + int i; + + for (i = 0; i < MAX_SKB_FRAGS && data_len > 0; i++) { + struct page *page; - while (data_len > 0) { + buff_info = (struct octep_rx_buffer *)&oq->buff_info[*read_idx]; + page = buff_info->page; octep_oq_next_pkt(oq, buff_info, read_idx, desc_used); + put_page(page); data_len -= oq->buffer_size; } }
@@ -457,6 +463,7 @@ static int __octep_oq_process_rx(struct octep_device *oct, if (!skb) { octep_oq_drop_rx(oq, buff_info, &read_idx, &desc_used); + put_page(virt_to_page(resp_hw)); oq->stats->alloc_failures++; continue; }
--
2.34.1