Thread (8 messages) 8 messages, 2 authors, 3d ago
WARM3d
Revisions (3)
  1. v4 [diff vs current]
  2. v5 [diff vs current]
  3. v6 current

[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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help