[PATCH net v6 1/4] octeon_ep: free the dropped RX buffer pages

From: Maoyi Xie

Date: Wed Jul 22 2026 - 12:17:17 EST


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 <kaixuan.li@xxxxxxxxxx>
Signed-off-by: Kaixuan Li <kaixuan.li@xxxxxxxxxx>
Signed-off-by: Maoyi Xie <maoyixie.tju@xxxxxxxxx>
---
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