From: Shai Brandes <shaib...@amazon.com> Fixed an issue of double free of mbufs which is exposed in mbuf fast free mode when handling multi-mbuf packets.
The faulty patch mishandled free of non-head mbufs as it iterated over linked mbufs and collected them into an array, which was then passed to rte_pktmbuf_free_bulk. However, rte_pktmbuf_free_bulk already performs an internal iteration over mbufs that are linked together which led to double free. Fixes: 89b081e154c5 ("net/ena: fix fast mbuf free") Cc: sta...@dpdk.org Signed-off-by: Shai Brandes <shaib...@amazon.com> --- drivers/net/ena/ena_ethdev.c | 39 +++++++++++------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c index 7b697c150a..66fc287faf 100644 --- a/drivers/net/ena/ena_ethdev.c +++ b/drivers/net/ena/ena_ethdev.c @@ -48,10 +48,10 @@ #define MAX_WIDE_LLQ_DEPTH_UNSUPPORTED 0 /* - * We should try to keep ENA_CLEANUP_BUF_SIZE lower than + * We should try to keep ENA_CLEANUP_BUF_THRESH lower than * RTE_MEMPOOL_CACHE_MAX_SIZE, so we can fit this in mempool local cache. */ -#define ENA_CLEANUP_BUF_SIZE 256 +#define ENA_CLEANUP_BUF_THRESH 256 #define ENA_PTYPE_HAS_HASH (RTE_PTYPE_L4_TCP | RTE_PTYPE_L4_UDP) @@ -3180,32 +3180,12 @@ static int ena_xmit_mbuf(struct ena_ring *tx_ring, struct rte_mbuf *mbuf) return 0; } -static __rte_always_inline size_t -ena_tx_cleanup_mbuf_fast(struct rte_mbuf **mbufs_to_clean, - struct rte_mbuf *mbuf, - size_t mbuf_cnt, - size_t buf_size) -{ - struct rte_mbuf *m_next; - - while (mbuf != NULL) { - m_next = mbuf->next; - mbufs_to_clean[mbuf_cnt++] = mbuf; - if (mbuf_cnt == buf_size) { - rte_pktmbuf_free_bulk(mbufs_to_clean, mbuf_cnt); - mbuf_cnt = 0; - } - mbuf = m_next; - } - - return mbuf_cnt; -} - static int ena_tx_cleanup(void *txp, uint32_t free_pkt_cnt) { - struct rte_mbuf *mbufs_to_clean[ENA_CLEANUP_BUF_SIZE]; + struct rte_mbuf *pkts_to_clean[ENA_CLEANUP_BUF_THRESH]; struct ena_ring *tx_ring = (struct ena_ring *)txp; size_t mbuf_cnt = 0; + size_t pkt_cnt = 0; unsigned int total_tx_descs = 0; unsigned int total_tx_pkts = 0; uint16_t cleanup_budget; @@ -3236,8 +3216,13 @@ static int ena_tx_cleanup(void *txp, uint32_t free_pkt_cnt) mbuf = tx_info->mbuf; if (fast_free) { - mbuf_cnt = ena_tx_cleanup_mbuf_fast(mbufs_to_clean, mbuf, mbuf_cnt, - ENA_CLEANUP_BUF_SIZE); + pkts_to_clean[pkt_cnt++] = mbuf; + mbuf_cnt += mbuf->nb_segs; + if (mbuf_cnt >= ENA_CLEANUP_BUF_THRESH) { + rte_pktmbuf_free_bulk(pkts_to_clean, pkt_cnt); + mbuf_cnt = 0; + pkt_cnt = 0; + } } else { rte_pktmbuf_free(mbuf); } @@ -3260,7 +3245,7 @@ static int ena_tx_cleanup(void *txp, uint32_t free_pkt_cnt) } if (mbuf_cnt != 0) - rte_pktmbuf_free_bulk(mbufs_to_clean, mbuf_cnt); + rte_pktmbuf_free_bulk(pkts_to_clean, pkt_cnt); /* Notify completion handler that full cleanup was performed */ if (free_pkt_cnt == 0 || total_tx_pkts < cleanup_budget) -- 2.17.1