DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/20] pktmbuf free bulk cleanups
@ 2026-05-08 20:33 Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 01/20] devtools/cocci: add transform for rte_pktmbuf_free_bulk Stephen Hemminger
                   ` (19 more replies)
  0 siblings, 20 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Looking at one driver noticed that rte_pktmbuf_free_bulk
was not being used. That motivated me to make a coccinelle
script to do a tree wide cleanup.

Then noticed that callers were having to check for NULL
before calling rte_pktmbuf_free_bulk, so changed it to
handle NULL array similar to free() and rte_free().

Do another tree wide pass to fix that and catch some
other unnecessary null checks in code.

Stephen Hemminger (20):
  devtools/cocci: add transform for rte_pktmbuf_free_bulk
  eventdev: use rte_pktmbuf_free_bulk
  gso: use rte_pktmbuf_free_bulk
  ip_frag: use rte_pktmbuf_free_bulk
  pipeline: use rte_pktmbuf_free_bulk
  port: use rte_pktmbuf_free_bulk
  net/af_xdp: use rte_pktmbuf_free_bulk
  net/cnxk: use rte_pktmbuf_free_bulk
  net/pfe: use rte_pktmbuf_free_bulk
  net/virtio: use rte_pktmbuf_free_bulk
  net/zxdh: use rte_pktmbuf_free_bulk
  app/compress-perf: use rte_pktmbuf_free_bulk
  mbuf: allow NULL array in rte_pktmbuf_free_bulk
  net/zxdh: remove unnecessary null check
  net/ice: remove unnecessary null check
  net/bnxt: remove unnecessary null check
  test: use rte_pktmbuf_free_bulk
  app/test-dma-perf: remove unnecessary null check
  app/test-compress-perf: remove unnecessary null check
  examples: use rte_pktmbuf_free_bulk

 .../comp_perf_test_common.c                   |  8 +--
 app/test-compress-perf/main.c                 |  6 +-
 app/test-dma-perf/benchmark.c                 |  6 +-
 app/test/sample_packet_forward.c              |  5 +-
 app/test/test_distributor.c                   |  4 +-
 app/test/test_dmadev.c                        |  6 +-
 app/test/test_ipfrag.c                        |  4 +-
 app/test/test_link_bonding.c                  | 13 ++---
 app/test/test_pmd_perf.c                      |  3 +-
 app/test/test_pmd_tap.c                       |  3 +-
 app/test/test_reorder.c                       | 12 ++--
 app/test/test_table_ports.c                   | 12 ++--
 app/test/test_table_tables.c                  | 21 +++----
 devtools/cocci/free_bulk.cocci                | 57 +++++++++++++++++++
 devtools/cocci/nullfree.cocci                 |  5 +-
 doc/guides/rel_notes/release_26_07.rst        |  5 ++
 drivers/net/af_xdp/rte_eth_af_xdp.c           |  3 +-
 drivers/net/bnxt/tf_core/v3/tfo.c             |  6 +-
 drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c          |  6 +-
 drivers/net/cnxk/cnxk_ethdev.c                |  5 +-
 drivers/net/intel/ice/ice_dcf_sched.c         |  6 +-
 drivers/net/pfe/pfe_ethdev.c                  |  4 +-
 drivers/net/virtio/virtio_rxtx.c              | 20 +++----
 drivers/net/zxdh/zxdh_np.c                    |  3 +-
 drivers/net/zxdh/zxdh_queue.c                 |  7 +--
 drivers/net/zxdh/zxdh_rxtx.c                  |  3 +-
 examples/bbdev_app/main.c                     |  4 +-
 examples/l2fwd-crypto/main.c                  |  4 +-
 .../client_server_mp/mp_client/client.c       |  7 +--
 .../client_server_mp/mp_server/main.c         |  5 +-
 examples/ntb/ntb_fwd.c                        | 12 ++--
 examples/packet_ordering/main.c               |  5 +-
 examples/server_node_efd/efd_node/node.c      |  7 +--
 examples/server_node_efd/efd_server/main.c    |  5 +-
 examples/vhost/main.c                         |  3 +-
 lib/eventdev/rte_event_eth_tx_adapter.c       |  4 +-
 lib/gso/gso_common.c                          |  5 +-
 lib/ip_frag/rte_ipv6_fragmentation.c          |  4 +-
 lib/mbuf/rte_mbuf.c                           |  3 +
 lib/mbuf/rte_mbuf.h                           |  1 +
 lib/pipeline/rte_pipeline.c                   |  4 +-
 lib/port/rte_port_fd.c                        |  6 +-
 lib/port/rte_swx_port_fd.c                    |  8 +--
 lib/port/rte_swx_port_source_sink.c           |  6 +-
 44 files changed, 152 insertions(+), 174 deletions(-)
 create mode 100644 devtools/cocci/free_bulk.cocci

-- 
2.53.0


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 01/20] devtools/cocci: add transform for rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 02/20] eventdev: use rte_pktmbuf_free_bulk Stephen Hemminger
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Convert simple loops freeing mbufs one at a time into a
single rte_pktmbuf_free_bulk() call.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 devtools/cocci/free_bulk.cocci | 57 ++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 devtools/cocci/free_bulk.cocci

diff --git a/devtools/cocci/free_bulk.cocci b/devtools/cocci/free_bulk.cocci
new file mode 100644
index 0000000000..51ce58400a
--- /dev/null
+++ b/devtools/cocci/free_bulk.cocci
@@ -0,0 +1,57 @@
+//
+// Replace simple loops freeing mbufs one-by-one with rte_pktmbuf_free_bulk().
+//
+// rte_pktmbuf_free_bulk() handles NULL entries internally, so per-element
+// NULL guards are folded in as well.  Loops whose body does more than the
+// free (clearing the slot, bookkeeping, etc.) are not matched.
+//
+@@
+expression A, N;
+identifier i;
+@@
+
+(
+- for (i = 0; i < N; i++)
+-     rte_pktmbuf_free(A[i]);
++ rte_pktmbuf_free_bulk(A, N);
+|
+- for (i = 0; i < N; ++i)
+-     rte_pktmbuf_free(A[i]);
++ rte_pktmbuf_free_bulk(A, N);
+|
+- for (i = 0; i < N; i++)
+-     if (A[i] != NULL)
+-         rte_pktmbuf_free(A[i]);
++ rte_pktmbuf_free_bulk(A, N);
+|
+- for (i = 0; i < N; i++)
+-     if (A[i])
+-         rte_pktmbuf_free(A[i]);
++ rte_pktmbuf_free_bulk(A, N);
+)
+
+@@
+expression A, N;
+identifier i;
+type T;
+@@
+
+(
+- for (T i = 0; i < N; i++)
+-     rte_pktmbuf_free(A[i]);
++ rte_pktmbuf_free_bulk(A, N);
+|
+- for (T i = 0; i < N; ++i)
+-     rte_pktmbuf_free(A[i]);
++ rte_pktmbuf_free_bulk(A, N);
+|
+- for (T i = 0; i < N; i++)
+-     if (A[i] != NULL)
+-         rte_pktmbuf_free(A[i]);
++ rte_pktmbuf_free_bulk(A, N);
+|
+- for (T i = 0; i < N; i++)
+-     if (A[i])
+-         rte_pktmbuf_free(A[i]);
++ rte_pktmbuf_free_bulk(A, N);
+)
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 02/20] eventdev: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 01/20] devtools/cocci: add transform for rte_pktmbuf_free_bulk Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 03/20] gso: " Stephen Hemminger
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Naga Harish K S V, Jerin Jacob

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/eventdev/rte_event_eth_tx_adapter.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lib/eventdev/rte_event_eth_tx_adapter.c b/lib/eventdev/rte_event_eth_tx_adapter.c
index 91c7be55c7..2de96a02c2 100644
--- a/lib/eventdev/rte_event_eth_tx_adapter.c
+++ b/lib/eventdev/rte_event_eth_tx_adapter.c
@@ -914,12 +914,10 @@ static inline void
 txa_txq_buffer_drain(struct txa_service_queue_info *tqi)
 {
 	struct rte_eth_dev_tx_buffer *b;
-	uint16_t i;
 
 	b = tqi->tx_buf;
 
-	for (i = 0; i < b->length; i++)
-		rte_pktmbuf_free(b->pkts[i]);
+	rte_pktmbuf_free_bulk(b->pkts, b->length);
 
 	b->length = 0;
 }
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 03/20] gso: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 01/20] devtools/cocci: add transform for rte_pktmbuf_free_bulk Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 02/20] eventdev: use rte_pktmbuf_free_bulk Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 04/20] ip_frag: " Stephen Hemminger
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Jiayu Hu

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/gso/gso_common.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/lib/gso/gso_common.c b/lib/gso/gso_common.c
index 378bf2c6aa..6ccaa7103a 100644
--- a/lib/gso/gso_common.c
+++ b/lib/gso/gso_common.c
@@ -31,10 +31,7 @@ hdr_segment_init(struct rte_mbuf *hdr_segment, struct rte_mbuf *pkt,
 static inline void
 free_gso_segment(struct rte_mbuf **pkts, uint16_t nb_pkts)
 {
-	uint16_t i;
-
-	for (i = 0; i < nb_pkts; i++)
-		rte_pktmbuf_free(pkts[i]);
+	rte_pktmbuf_free_bulk(pkts, nb_pkts);
 }
 
 int
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 04/20] ip_frag: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (2 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 03/20] gso: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 05/20] pipeline: " Stephen Hemminger
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Konstantin Ananyev

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/ip_frag/rte_ipv6_fragmentation.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lib/ip_frag/rte_ipv6_fragmentation.c b/lib/ip_frag/rte_ipv6_fragmentation.c
index c81f2402e3..4d8fb05233 100644
--- a/lib/ip_frag/rte_ipv6_fragmentation.c
+++ b/lib/ip_frag/rte_ipv6_fragmentation.c
@@ -38,9 +38,7 @@ __fill_ipv6hdr_frag(struct rte_ipv6_hdr *dst,
 static inline void
 __free_fragments(struct rte_mbuf *mb[], uint32_t num)
 {
-	uint32_t i;
-	for (i = 0; i < num; i++)
-		rte_pktmbuf_free(mb[i]);
+	rte_pktmbuf_free_bulk(mb, num);
 }
 
 /**
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 05/20] pipeline: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (3 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 04/20] ip_frag: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 06/20] port: " Stephen Hemminger
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Cristian Dumitrescu

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/pipeline/rte_pipeline.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lib/pipeline/rte_pipeline.c b/lib/pipeline/rte_pipeline.c
index fa3c8b77ee..1fadae01d8 100644
--- a/lib/pipeline/rte_pipeline.c
+++ b/lib/pipeline/rte_pipeline.c
@@ -1305,10 +1305,8 @@ rte_pipeline_action_handler_drop(struct rte_pipeline *p, uint64_t pkts_mask)
 {
 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
 		uint64_t n_pkts = rte_popcount64(pkts_mask);
-		uint32_t i;
 
-		for (i = 0; i < n_pkts; i++)
-			rte_pktmbuf_free(p->pkts[i]);
+		rte_pktmbuf_free_bulk(p->pkts, n_pkts);
 	} else {
 		uint32_t i;
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 06/20] port: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (4 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 05/20] pipeline: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 07/20] net/af_xdp: " Stephen Hemminger
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Cristian Dumitrescu

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/port/rte_port_fd.c              | 6 ++----
 lib/port/rte_swx_port_fd.c          | 8 ++------
 lib/port/rte_swx_port_source_sink.c | 6 +-----
 3 files changed, 5 insertions(+), 15 deletions(-)

diff --git a/lib/port/rte_port_fd.c b/lib/port/rte_port_fd.c
index dbc9efef1b..2b021710d4 100644
--- a/lib/port/rte_port_fd.c
+++ b/lib/port/rte_port_fd.c
@@ -212,8 +212,7 @@ send_burst(struct rte_port_fd_writer *p)
 
 	RTE_PORT_FD_WRITER_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - i);
 
-	for (i = 0; i < p->tx_buf_count; i++)
-		rte_pktmbuf_free(p->tx_buf[i]);
+	rte_pktmbuf_free_bulk(p->tx_buf, p->tx_buf_count);
 
 	p->tx_buf_count = 0;
 }
@@ -397,8 +396,7 @@ send_burst_nodrop(struct rte_port_fd_writer_nodrop *p)
 
 	RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - i);
 
-	for (i = 0; i < p->tx_buf_count; i++)
-		rte_pktmbuf_free(p->tx_buf[i]);
+	rte_pktmbuf_free_bulk(p->tx_buf, p->tx_buf_count);
 
 	p->tx_buf_count = 0;
 }
diff --git a/lib/port/rte_swx_port_fd.c b/lib/port/rte_swx_port_fd.c
index 72783d2b0f..937b1e0945 100644
--- a/lib/port/rte_swx_port_fd.c
+++ b/lib/port/rte_swx_port_fd.c
@@ -73,14 +73,11 @@ static void
 reader_free(void *port)
 {
 	struct reader *p = port;
-	uint32_t i;
 
 	if (!p)
 		return;
 
-	for (i = 0; i < p->n_pkts; i++)
-		rte_pktmbuf_free(p->pkts[i]);
-
+	rte_pktmbuf_free_bulk(p->pkts, p->n_pkts);
 	free(p->pkts);
 	free(p);
 }
@@ -218,8 +215,7 @@ __writer_flush(struct writer *p)
 		(uint32_t)p->params.fd,
 		p->n_pkts);
 
-	for (i = 0; i < p->n_pkts; i++)
-		rte_pktmbuf_free(p->pkts[i]);
+	rte_pktmbuf_free_bulk(p->pkts, p->n_pkts);
 
 	p->n_pkts = 0;
 }
diff --git a/lib/port/rte_swx_port_source_sink.c b/lib/port/rte_swx_port_source_sink.c
index af8b9ec68d..f651d5b5ad 100644
--- a/lib/port/rte_swx_port_source_sink.c
+++ b/lib/port/rte_swx_port_source_sink.c
@@ -52,16 +52,12 @@ static void
 source_free(void *port)
 {
 	struct source *p = port;
-	uint32_t i;
 
 	if (!p)
 		return;
 
-	for (i = 0; i < p->n_pkts; i++)
-		rte_pktmbuf_free(p->pkts[i]);
-
+	rte_pktmbuf_free_bulk(p->pkts, p->n_pkts);
 	free(p->pkts);
-
 	free(p);
 }
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 07/20] net/af_xdp: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (5 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 06/20] port: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 08/20] net/cnxk: " Stephen Hemminger
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Ciara Loftus, Maryam Tahhan

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/af_xdp/rte_eth_af_xdp.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/af_xdp/rte_eth_af_xdp.c b/drivers/net/af_xdp/rte_eth_af_xdp.c
index 10dbcf1333..4f55887963 100644
--- a/drivers/net/af_xdp/rte_eth_af_xdp.c
+++ b/drivers/net/af_xdp/rte_eth_af_xdp.c
@@ -263,8 +263,7 @@ reserve_fill_queue_zc(struct xsk_umem_info *umem, uint16_t reserve_size,
 	uint16_t i;
 
 	if (unlikely(!xsk_ring_prod__reserve(fq, reserve_size, &idx))) {
-		for (i = 0; i < reserve_size; i++)
-			rte_pktmbuf_free(bufs[i]);
+		rte_pktmbuf_free_bulk(bufs, reserve_size);
 		AF_XDP_LOG_LINE(DEBUG, "Failed to reserve enough fq descs.");
 		return -1;
 	}
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 08/20] net/cnxk: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (6 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 07/20] net/af_xdp: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 09/20] net/pfe: " Stephen Hemminger
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev
  Cc: Stephen Hemminger, Nithin Dabilpuram, Kiran Kumar K,
	Sunil Kumar Kori, Satha Rao, Harman Kalra

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/cnxk/cnxk_ethdev.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/cnxk/cnxk_ethdev.c b/drivers/net/cnxk/cnxk_ethdev.c
index 06d1c9b362..3330dd5051 100644
--- a/drivers/net/cnxk/cnxk_ethdev.c
+++ b/drivers/net/cnxk/cnxk_ethdev.c
@@ -1913,7 +1913,7 @@ cnxk_nix_dev_stop(struct rte_eth_dev *eth_dev)
 	const struct eth_dev_ops *dev_ops = eth_dev->dev_ops;
 	struct rte_mbuf *rx_pkts[32];
 	struct rte_eth_link link;
-	int count, i, j, rc;
+	int count, i, rc;
 	void *rxq;
 
 	/* In case of Inline IPSec, will need to avoid disabling the MCAM rules and NPC Rx
@@ -1951,8 +1951,7 @@ cnxk_nix_dev_stop(struct rte_eth_dev *eth_dev)
 		rxq = eth_dev->data->rx_queues[i];
 		count = dev->rx_pkt_burst_no_offload(rxq, rx_pkts, 32);
 		while (count) {
-			for (j = 0; j < count; j++)
-				rte_pktmbuf_free(rx_pkts[j]);
+			rte_pktmbuf_free_bulk(rx_pkts, count);
 			count = dev->rx_pkt_burst_no_offload(rxq, rx_pkts, 32);
 		}
 	}
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 09/20] net/pfe: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (7 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 08/20] net/cnxk: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 10/20] net/virtio: " Stephen Hemminger
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Gagandeep Singh

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/pfe/pfe_ethdev.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/net/pfe/pfe_ethdev.c b/drivers/net/pfe/pfe_ethdev.c
index 1efa17539e..4c0f9e63a0 100644
--- a/drivers/net/pfe/pfe_ethdev.c
+++ b/drivers/net/pfe/pfe_ethdev.c
@@ -281,9 +281,7 @@ pfe_eth_open(struct rte_eth_dev *dev)
 			ret = hif_lib_receive_pkt(&client->rx_q[0],
 						  hif_shm->pool, rx_pkts, 32);
 			while (ret) {
-				int i;
-				for (i = 0; i < ret; i++)
-					rte_pktmbuf_free(rx_pkts[i]);
+				rte_pktmbuf_free_bulk(rx_pkts, ret);
 				ret = hif_lib_receive_pkt(&client->rx_q[0],
 							  hif_shm->pool,
 							  rx_pkts, 32);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 10/20] net/virtio: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (8 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 09/20] net/pfe: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 11/20] net/zxdh: " Stephen Hemminger
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Maxime Coquelin, Chenbo Xia

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/virtio/virtio_rxtx.c | 20 +++++++-------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index edecd2011f..a1fbdd9f34 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -723,7 +723,7 @@ virtio_dev_rx_queue_setup_finish(struct rte_eth_dev *dev, uint16_t queue_idx)
 	struct virtnet_rx *rxvq = &vq->rxq;
 	struct rte_mbuf *m;
 	uint16_t desc_idx;
-	int error, nbufs, i;
+	int error, nbufs;
 	bool in_order = virtio_with_feature(hw, VIRTIO_F_IN_ORDER);
 
 	PMD_INIT_FUNC_TRACE();
@@ -764,8 +764,7 @@ virtio_dev_rx_queue_setup_finish(struct rte_eth_dev *dev, uint16_t queue_idx)
 						pkts,
 						free_cnt);
 				if (unlikely(error)) {
-					for (i = 0; i < free_cnt; i++)
-						rte_pktmbuf_free(pkts[i]);
+					rte_pktmbuf_free_bulk(pkts, free_cnt);
 				} else {
 					nbufs += free_cnt;
 				}
@@ -1071,8 +1070,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 			error = virtqueue_enqueue_recv_refill(vq, new_pkts,
 					free_cnt);
 			if (unlikely(error)) {
-				for (i = 0; i < free_cnt; i++)
-					rte_pktmbuf_free(new_pkts[i]);
+				rte_pktmbuf_free_bulk(new_pkts, free_cnt);
 			}
 			nb_enqueued += free_cnt;
 		} else {
@@ -1176,8 +1174,7 @@ virtio_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 			error = virtqueue_enqueue_recv_refill_packed(vq,
 					new_pkts, free_cnt);
 			if (unlikely(error)) {
-				for (i = 0; i < free_cnt; i++)
-					rte_pktmbuf_free(new_pkts[i]);
+				rte_pktmbuf_free_bulk(new_pkts, free_cnt);
 			}
 			nb_enqueued += free_cnt;
 		} else {
@@ -1358,8 +1355,7 @@ virtio_recv_pkts_inorder(void *rx_queue,
 			error = virtqueue_enqueue_refill_inorder(vq, new_pkts,
 					free_cnt);
 			if (unlikely(error)) {
-				for (i = 0; i < free_cnt; i++)
-					rte_pktmbuf_free(new_pkts[i]);
+				rte_pktmbuf_free_bulk(new_pkts, free_cnt);
 			}
 			nb_enqueued += free_cnt;
 		} else {
@@ -1535,8 +1531,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 			error = virtqueue_enqueue_recv_refill(vq, new_pkts,
 					free_cnt);
 			if (unlikely(error)) {
-				for (i = 0; i < free_cnt; i++)
-					rte_pktmbuf_free(new_pkts[i]);
+				rte_pktmbuf_free_bulk(new_pkts, free_cnt);
 			}
 			nb_enqueued += free_cnt;
 		} else {
@@ -1707,8 +1702,7 @@ virtio_recv_mergeable_pkts_packed(void *rx_queue,
 			error = virtqueue_enqueue_recv_refill_packed(vq,
 					new_pkts, free_cnt);
 			if (unlikely(error)) {
-				for (i = 0; i < free_cnt; i++)
-					rte_pktmbuf_free(new_pkts[i]);
+				rte_pktmbuf_free_bulk(new_pkts, free_cnt);
 			}
 			nb_enqueued += free_cnt;
 		} else {
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 11/20] net/zxdh: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (9 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 10/20] net/virtio: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 12/20] app/compress-perf: " Stephen Hemminger
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Junlong Wang, Lijie Shan

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/zxdh/zxdh_queue.c | 7 ++-----
 drivers/net/zxdh/zxdh_rxtx.c  | 3 +--
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/net/zxdh/zxdh_queue.c b/drivers/net/zxdh/zxdh_queue.c
index 7162593b16..543f626e6f 100644
--- a/drivers/net/zxdh/zxdh_queue.c
+++ b/drivers/net/zxdh/zxdh_queue.c
@@ -445,11 +445,8 @@ int32_t zxdh_dev_rx_queue_setup_finish(struct rte_eth_dev *dev, uint16_t queue_i
 
 		if (likely(rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt) == 0)) {
 			error = zxdh_enqueue_recv_refill_packed(vq, new_pkts, free_cnt);
-			if (unlikely(error)) {
-				int32_t i;
-				for (i = 0; i < free_cnt; i++)
-					rte_pktmbuf_free(new_pkts[i]);
-			}
+			if (unlikely(error))
+				rte_pktmbuf_free_bulk(new_pkts, free_cnt);
 		} else {
 			PMD_DRV_LOG(ERR, "port %d rxq %d allocated bufs from %s failed",
 				hw->port_id, logic_qidx, rxvq->mpool->name);
diff --git a/drivers/net/zxdh/zxdh_rxtx.c b/drivers/net/zxdh/zxdh_rxtx.c
index db86922aea..cb324336d0 100644
--- a/drivers/net/zxdh/zxdh_rxtx.c
+++ b/drivers/net/zxdh/zxdh_rxtx.c
@@ -970,8 +970,7 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 		if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
 			error = zxdh_enqueue_recv_refill_packed(vq, new_pkts, free_cnt);
 			if (unlikely(error)) {
-				for (i = 0; i < free_cnt; i++)
-					rte_pktmbuf_free(new_pkts[i]);
+				rte_pktmbuf_free_bulk(new_pkts, free_cnt);
 			}
 
 			if (unlikely(zxdh_queue_kick_prepare_packed(vq)))
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 12/20] app/compress-perf: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (10 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 11/20] net/zxdh: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 13/20] mbuf: allow NULL array in rte_pktmbuf_free_bulk Stephen Hemminger
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 app/test-compress-perf/comp_perf_test_common.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/app/test-compress-perf/comp_perf_test_common.c b/app/test-compress-perf/comp_perf_test_common.c
index 78487196ad..12c2a7bbd0 100644
--- a/app/test-compress-perf/comp_perf_test_common.c
+++ b/app/test-compress-perf/comp_perf_test_common.c
@@ -84,12 +84,10 @@ comp_perf_free_memory(struct comp_test_data *test_data,
 	uint32_t i;
 
 	if (mem->decomp_bufs != NULL)
-		for (i = 0; i < mem->total_bufs; i++)
-			rte_pktmbuf_free(mem->decomp_bufs[i]);
+		rte_pktmbuf_free_bulk(mem->decomp_bufs, mem->total_bufs);
 
 	if (mem->comp_bufs != NULL)
-		for (i = 0; i < mem->total_bufs; i++)
-			rte_pktmbuf_free(mem->comp_bufs[i]);
+		rte_pktmbuf_free_bulk(mem->comp_bufs, mem->total_bufs);
 
 	rte_free(mem->decomp_bufs);
 	rte_free(mem->comp_bufs);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 13/20] mbuf: allow NULL array in rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (11 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 12/20] app/compress-perf: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-09  8:47   ` Morten Brørup
  2026-05-08 20:33 ` [PATCH 14/20] net/zxdh: remove unnecessary null check Stephen Hemminger
                   ` (6 subsequent siblings)
  19 siblings, 1 reply; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Morten Brørup

This allows callers to avoid NULL checks and just call
rte_pktmbuf_free_bulk, similar to rte_pktmbuf_free.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 devtools/cocci/nullfree.cocci          | 5 ++++-
 doc/guides/rel_notes/release_26_07.rst | 5 +++++
 lib/mbuf/rte_mbuf.c                    | 3 +++
 lib/mbuf/rte_mbuf.h                    | 1 +
 4 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/devtools/cocci/nullfree.cocci b/devtools/cocci/nullfree.cocci
index e7417b69ff..78e30f730a 100644
--- a/devtools/cocci/nullfree.cocci
+++ b/devtools/cocci/nullfree.cocci
@@ -4,7 +4,7 @@
 // free(NULL) as a no-op.
 //
 @@
-expression E;
+expression E, N;
 @@
 (
 - if (E != NULL) cmdline_free(E);
@@ -79,6 +79,9 @@ expression E;
 - if (E != NULL) rte_pktmbuf_free(E);
 + rte_pktmbuf_free(E);
 |
+- if (E != NULL) rte_pktmbuf_free_bulk(E, N);
++ rte_pktmbuf_free_bulk(E, N);
+|
 - if (E != NULL) rte_rib_free(E);
 + rte_rib_free(E);
 |
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index f012d47a4b..6f2f7f849f 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -63,6 +63,11 @@ New Features
     ``rte_eal_init`` and the application is responsible for probing each device,
   * ``--auto-probing`` enables the initial bus probing, which is the current default behavior.
 
+* **mbuf: rte_pktmbuf_free_bulk now accepts NULL array pointer.**
+
+  Calling ``rte_pktmbuf_free_bulk`` with a NULL ``mbufs`` argument  is a no-op,
+  matching the behavior of ``rte_pktmbuf_free()`` and ``rte_free()``.
+
 
 Removed Items
 -------------
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index c2476e7704..8ec3bb53bb 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -562,6 +562,9 @@ void rte_pktmbuf_free_bulk(struct rte_mbuf **mbufs, unsigned int count)
 	struct rte_mbuf *m, *m_next, *pending[RTE_PKTMBUF_FREE_PENDING_SZ];
 	unsigned int idx, nb_pending = 0;
 
+	if (mbufs == NULL)
+		return;
+
 	rte_mbuf_history_mark_bulk(mbufs, count, RTE_MBUF_HISTORY_OP_LIB_FREE);
 
 	for (idx = 0; idx < count; idx++) {
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index e7c3bbadd4..e9f8932e80 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -1534,6 +1534,7 @@ static inline void rte_pktmbuf_free(struct rte_mbuf *m)
  *  @param mbufs
  *    Array of pointers to packet mbufs.
  *    The array may contain NULL pointers.
+ *    The array pointer is NULL function does nothing.
  *  @param count
  *    Array size.
  */
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 14/20] net/zxdh: remove unnecessary null check
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (12 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 13/20] mbuf: allow NULL array in rte_pktmbuf_free_bulk Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 15/20] net/ice: " Stephen Hemminger
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Junlong Wang, Lijie Shan

Remove unnecessary if check before calling free.

Generated by devtools/cocci/null_free.cocci

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/zxdh/zxdh_np.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/zxdh/zxdh_np.c b/drivers/net/zxdh/zxdh_np.c
index efb57e34f2..b078ec5b6c 100644
--- a/drivers/net/zxdh/zxdh_np.c
+++ b/drivers/net/zxdh/zxdh_np.c
@@ -12383,8 +12383,7 @@ zxdh_np_dtb_acl_data_clear(uint32_t dev_id, uint32_t queue_id,
 				&element_id);
 	free(data_buff);
 	free(mask_buff);
-	if (eram_buff)
-		free(eram_buff);
+	free(eram_buff);
 
 	free(p_entry_arr);
 	ZXDH_COMM_CHECK_DEV_RC(dev_id, rc, "zxdh_np_dtb_acl_dma_insert");
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 15/20] net/ice: remove unnecessary null check
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (13 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 14/20] net/zxdh: remove unnecessary null check Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 16/20] net/bnxt: " Stephen Hemminger
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Anatoly Burakov

Remove unnecessary if check before calling free.

Generated by devtools/cocci/null_free.cocci

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/intel/ice/ice_dcf_sched.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/intel/ice/ice_dcf_sched.c b/drivers/net/intel/ice/ice_dcf_sched.c
index 948774a282..14e902edbe 100644
--- a/drivers/net/intel/ice/ice_dcf_sched.c
+++ b/drivers/net/intel/ice/ice_dcf_sched.c
@@ -877,10 +877,8 @@ static int ice_dcf_hierarchy_commit(struct rte_eth_dev *dev,
 	return ret_val;
 
 fail_clear:
-	if (vf_bw != NULL)
-		free(vf_bw);
-	if (tc_bw != NULL)
-		free(tc_bw);
+	free(vf_bw);
+	free(tc_bw);
 
 	/* clear all the traffic manager configuration */
 	if (clear_on_fail) {
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 16/20] net/bnxt: remove unnecessary null check
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (14 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 15/20] net/ice: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 17/20] test: use rte_pktmbuf_free_bulk Stephen Hemminger
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Kishore Padmanabha, Ajit Khaparde

Remove unnecessary if check before calling rte_free.

Generated by devtools/cocci/null_free.cocci

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/bnxt/tf_core/v3/tfo.c    | 6 ++----
 drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c | 6 ++----
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/net/bnxt/tf_core/v3/tfo.c b/drivers/net/bnxt/tf_core/v3/tfo.c
index 4b1f545476..681d1dd8d3 100644
--- a/drivers/net/bnxt/tf_core/v3/tfo.c
+++ b/drivers/net/bnxt/tf_core/v3/tfo.c
@@ -183,13 +183,11 @@ void tfo_close(void **tfo)
 				}
 			}
 		}
-		if (tim)
-			rte_free(tim);
+		rte_free(tim);
 		tfco->ts_tim = NULL;
 		tfco->tfgo = NULL;
 
-		if (*tfo)
-			rte_free(*tfo);
+		rte_free(*tfo);
 		*tfo = NULL;
 	}
 }
diff --git a/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c b/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c
index 23e1b59ca4..3707cd1a2d 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c
+++ b/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c
@@ -169,11 +169,9 @@ ulp_sc_mgr_deinit(struct bnxt_ulp_context *ctxt)
 
 	ulp_sc_mgr_thread_cancel(ctxt);
 
-	if (ulp_sc_info->stats_cache_tbl)
-		rte_free(ulp_sc_info->stats_cache_tbl);
+	rte_free(ulp_sc_info->stats_cache_tbl);
 
-	if (ulp_sc_info->read_data)
-		rte_free(ulp_sc_info->read_data);
+	rte_free(ulp_sc_info->read_data);
 
 	rte_free(ulp_sc_info);
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 17/20] test: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (15 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 16/20] net/bnxt: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 18/20] app/test-dma-perf: remove unnecessary null check Stephen Hemminger
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev
  Cc: Stephen Hemminger, Reshma Pattan, Chengwen Feng, Kevin Laatz,
	Bruce Richardson, Konstantin Ananyev, Chas Williams,
	Min Hu (Connor), Volodymyr Fialko, Cristian Dumitrescu

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 app/test/sample_packet_forward.c |  5 +----
 app/test/test_distributor.c      |  4 +---
 app/test/test_dmadev.c           |  6 ++----
 app/test/test_ipfrag.c           |  4 +---
 app/test/test_link_bonding.c     | 13 ++++---------
 app/test/test_pmd_perf.c         |  3 +--
 app/test/test_pmd_tap.c          |  3 +--
 app/test/test_reorder.c          | 12 ++++--------
 app/test/test_table_ports.c      | 12 ++++--------
 app/test/test_table_tables.c     | 21 +++++++--------------
 10 files changed, 26 insertions(+), 57 deletions(-)

diff --git a/app/test/sample_packet_forward.c b/app/test/sample_packet_forward.c
index aa897274d8..70bb75e321 100644
--- a/app/test/sample_packet_forward.c
+++ b/app/test/sample_packet_forward.c
@@ -115,10 +115,7 @@ test_get_mbuf_from_pool(struct rte_mempool **mp, struct rte_mbuf **pbuf,
 void
 test_put_mbuf_to_pool(struct rte_mempool *mp, struct rte_mbuf **pbuf)
 {
-	int itr = 0;
-
-	for (itr = 0; itr < NUM_PACKETS; itr++)
-		rte_pktmbuf_free(pbuf[itr]);
+	rte_pktmbuf_free_bulk(pbuf, NUM_PACKETS);
 	rte_mempool_free(mp);
 }
 
diff --git a/app/test/test_distributor.c b/app/test/test_distributor.c
index da0a21ea83..ed37ca80f1 100644
--- a/app/test/test_distributor.c
+++ b/app/test/test_distributor.c
@@ -309,7 +309,6 @@ handle_work_with_free_mbufs(void *arg)
 	alignas(RTE_CACHE_LINE_SIZE) struct rte_mbuf *buf[8];
 	struct worker_params *wp = arg;
 	struct rte_distributor *d = wp->dist;
-	unsigned int i;
 	unsigned int num;
 	unsigned int id = rte_atomic_fetch_add_explicit(&worker_idx, 1, rte_memory_order_relaxed);
 
@@ -317,8 +316,7 @@ handle_work_with_free_mbufs(void *arg)
 	while (!quit) {
 		rte_atomic_fetch_add_explicit(&worker_stats[id].handled_packets, num,
 				rte_memory_order_relaxed);
-		for (i = 0; i < num; i++)
-			rte_pktmbuf_free(buf[i]);
+		rte_pktmbuf_free_bulk(buf, num);
 		num = rte_distributor_get_pkt(d, id, buf, NULL, 0);
 	}
 	rte_atomic_fetch_add_explicit(&worker_stats[id].handled_packets, num,
diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 5488a1af33..a5772cc843 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -499,10 +499,8 @@ test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
 				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
 						id, 0);
 
-			for (i = 0; i < n_src; i++)
-				rte_pktmbuf_free(src[i]);
-			for (i = 0; i < n_dst; i++)
-				rte_pktmbuf_free(dst[i]);
+			rte_pktmbuf_free_bulk(src, n_src);
+			rte_pktmbuf_free_bulk(dst, n_dst);
 
 			/* Verify that completion returns nothing more */
 			if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
diff --git a/app/test/test_ipfrag.c b/app/test/test_ipfrag.c
index 247575d6c5..2c553222c2 100644
--- a/app/test/test_ipfrag.c
+++ b/app/test/test_ipfrag.c
@@ -240,9 +240,7 @@ v6_allocate_packet_of(struct rte_mbuf *b, int fill, size_t s, uint8_t ttl,
 static inline void
 test_free_fragments(struct rte_mbuf *mb[], uint32_t num)
 {
-	uint32_t i;
-	for (i = 0; i < num; i++)
-		rte_pktmbuf_free(mb[i]);
+	rte_pktmbuf_free_bulk(mb, num);
 }
 
 static inline void
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index 19b064771a..eac785610a 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -1476,10 +1476,7 @@ verify_mbufs_ref_count(struct rte_mbuf **mbufs, int nb_mbufs, int val)
 static void
 free_mbufs(struct rte_mbuf **mbufs, int nb_mbufs)
 {
-	int i;
-
-	for (i = 0; i < nb_mbufs; i++)
-		rte_pktmbuf_free(mbufs[i]);
+	rte_pktmbuf_free_bulk(mbufs, nb_mbufs);
 }
 
 #define TEST_RR_MEMBER_TX_FAIL_MEMBER_COUNT		(2)
@@ -4193,7 +4190,7 @@ testsuite_teardown(void)
 static void
 free_virtualpmd_tx_queue(void)
 {
-	int i, member_port, to_free_cnt;
+	int member_port, to_free_cnt;
 	struct rte_mbuf *pkts_to_free[MAX_PKT_BURST];
 
 	/* Free tx queue of virtual pmd */
@@ -4202,8 +4199,7 @@ free_virtualpmd_tx_queue(void)
 		to_free_cnt = virtual_ethdev_get_mbufs_from_tx_queue(
 				test_params->member_port_ids[member_port],
 				pkts_to_free, MAX_PKT_BURST);
-		for (i = 0; i < to_free_cnt; i++)
-			rte_pktmbuf_free(pkts_to_free[i]);
+		rte_pktmbuf_free_bulk(pkts_to_free, to_free_cnt);
 	}
 }
 
@@ -4381,8 +4377,7 @@ test_tlb_rx_burst(void)
 		}
 
 		/* free mbufs */
-		for (i = 0; i < burst_size; i++)
-			rte_pktmbuf_free(rx_pkt_burst[i]);
+		rte_pktmbuf_free_bulk(rx_pkt_burst, burst_size);
 
 		/* reset bonding device stats */
 		rte_eth_stats_reset(test_params->bonding_port_id);
diff --git a/app/test/test_pmd_perf.c b/app/test/test_pmd_perf.c
index 995b0a6f20..dab1751b9a 100644
--- a/app/test/test_pmd_perf.c
+++ b/app/test/test_pmd_perf.c
@@ -602,8 +602,7 @@ poll_burst(void *args)
 	       total, MAX_IDLE - timeout);
 	/* clean up */
 	total = pkt_per_port * conf->nb_ports - total;
-	for (i = 0; i < total; i++)
-		rte_pktmbuf_free(pkts_burst[i]);
+	rte_pktmbuf_free_bulk(pkts_burst, total);
 
 	rte_free(pkts_burst);
 
diff --git a/app/test/test_pmd_tap.c b/app/test/test_pmd_tap.c
index 6d0e8b4f54..f48b69de3b 100644
--- a/app/test/test_pmd_tap.c
+++ b/app/test/test_pmd_tap.c
@@ -192,8 +192,7 @@ test_tap_send_receive(void)
 	printf("Received %u packets on port %d\n", nb_rx, tap_port0);
 
 	/* Free received packets */
-	for (i = 0; i < nb_rx; i++)
-		rte_pktmbuf_free(rx_mbufs[i]);
+	rte_pktmbuf_free_bulk(rx_mbufs, nb_rx);
 
 	return TEST_SUCCESS;
 }
diff --git a/app/test/test_reorder.c b/app/test/test_reorder.c
index 8c68e00869..fc922650d6 100644
--- a/app/test/test_reorder.c
+++ b/app/test/test_reorder.c
@@ -208,8 +208,7 @@ test_reorder_insert(void)
 	ret = 0;
 exit:
 	rte_reorder_free(b);
-	for (i = 0; i < INSERT_NUM_BUFS; i++)
-		rte_pktmbuf_free(bufs[i]);
+	rte_pktmbuf_free_bulk(bufs, INSERT_NUM_BUFS);
 
 	return ret;
 }
@@ -382,8 +381,7 @@ test_reorder_drain_up_to_seqn(void)
 		ret = -1;
 		goto exit;
 	}
-	for (i = 0; i < 2; i++)
-		rte_pktmbuf_free(robufs[i]);
+	rte_pktmbuf_free_bulk(robufs, 2);
 	memset(robufs, 0, sizeof(robufs));
 
 	/* Insert more packets
@@ -406,8 +404,7 @@ test_reorder_drain_up_to_seqn(void)
 		ret = -1;
 		goto exit;
 	}
-	for (i = 0; i < 2; i++)
-		rte_pktmbuf_free(robufs[i]);
+	rte_pktmbuf_free_bulk(robufs, 2);
 	memset(robufs, 0, sizeof(robufs));
 
 	ret = 0;
@@ -483,8 +480,7 @@ test_reorder_set_seqn(void)
 	ret = 0;
 exit:
 	rte_reorder_free(b);
-	for (i = 0; i < SET_SEQN_NUM_BUFS; i++)
-		rte_pktmbuf_free(bufs[i]);
+	rte_pktmbuf_free_bulk(bufs, SET_SEQN_NUM_BUFS);
 
 	return ret;
 }
diff --git a/app/test/test_table_ports.c b/app/test/test_table_ports.c
index 282ec2a3d2..d617e73810 100644
--- a/app/test/test_table_ports.c
+++ b/app/test/test_table_ports.c
@@ -73,8 +73,7 @@ test_port_ring_reader(void)
 	if (received_pkts < expected_pkts)
 		return -6;
 
-	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
-		rte_pktmbuf_free(res_mbuf[i]);
+	rte_pktmbuf_free_bulk(res_mbuf, RTE_PORT_IN_BURST_SIZE_MAX);
 
 	return 0;
 }
@@ -156,8 +155,7 @@ test_port_ring_writer(void)
 	if (received_pkts < expected_pkts)
 		return -8;
 
-	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
-		rte_pktmbuf_free(res_mbuf[i]);
+	rte_pktmbuf_free_bulk(res_mbuf, RTE_PORT_IN_BURST_SIZE_MAX);
 
 	/* TX Bulk */
 	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
@@ -171,8 +169,7 @@ test_port_ring_writer(void)
 	if (received_pkts < expected_pkts)
 		return -8;
 
-	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
-		rte_pktmbuf_free(res_mbuf[i]);
+	rte_pktmbuf_free_bulk(res_mbuf, RTE_PORT_IN_BURST_SIZE_MAX);
 
 	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
 		mbuf[i] = rte_pktmbuf_alloc(pool);
@@ -186,8 +183,7 @@ test_port_ring_writer(void)
 	if (received_pkts < expected_pkts)
 		return -9;
 
-	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
-		rte_pktmbuf_free(res_mbuf[i]);
+	rte_pktmbuf_free_bulk(res_mbuf, RTE_PORT_IN_BURST_SIZE_MAX);
 
 	return 0;
 }
diff --git a/app/test/test_table_tables.c b/app/test/test_table_tables.c
index 920aa555cb..d2c09c360f 100644
--- a/app/test/test_table_tables.c
+++ b/app/test/test_table_tables.c
@@ -162,8 +162,7 @@ test_table_stub(void)
 		return -2;
 
 	/* Free resources */
-	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
-		rte_pktmbuf_free(mbufs[i]);
+	rte_pktmbuf_free_bulk(mbufs, RTE_PORT_IN_BURST_SIZE_MAX);
 
 	return 0;
 }
@@ -276,8 +275,7 @@ test_table_array(void)
 				return -13;
 
 	/* Free resources */
-	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
-		rte_pktmbuf_free(mbufs[i]);
+	rte_pktmbuf_free_bulk(mbufs, RTE_PORT_IN_BURST_SIZE_MAX);
 
 	status = rte_table_array_ops.f_free(table);
 
@@ -442,8 +440,7 @@ test_table_lpm(void)
 		return -23;
 
 	/* Free resources */
-	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
-		rte_pktmbuf_free(mbufs[i]);
+	rte_pktmbuf_free_bulk(mbufs, RTE_PORT_IN_BURST_SIZE_MAX);
 
 	status = rte_table_lpm_ops.f_free(table);
 
@@ -620,8 +617,7 @@ test_table_lpm_ipv6(void)
 		return -24;
 
 	/* Free resources */
-	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
-		rte_pktmbuf_free(mbufs[i]);
+	rte_pktmbuf_free_bulk(mbufs, RTE_PORT_IN_BURST_SIZE_MAX);
 
 	status = rte_table_lpm_ipv6_ops.f_free(table);
 
@@ -723,8 +719,7 @@ test_table_hash_lru_generic(struct rte_table_ops *ops, uint32_t key_size)
 		return -13;
 
 	/* Free resources */
-	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
-		rte_pktmbuf_free(mbufs[i]);
+	rte_pktmbuf_free_bulk(mbufs, RTE_PORT_IN_BURST_SIZE_MAX);
 
 	status = ops->f_free(table);
 
@@ -833,8 +828,7 @@ test_table_hash_ext_generic(struct rte_table_ops *ops, uint32_t key_size)
 		return -13;
 
 	/* Free resources */
-	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
-		rte_pktmbuf_free(mbufs[i]);
+	rte_pktmbuf_free_bulk(mbufs, RTE_PORT_IN_BURST_SIZE_MAX);
 
 	status = ops->f_free(table);
 
@@ -1047,8 +1041,7 @@ test_table_hash_cuckoo(void)
 		return -20;
 
 	/* Free resources */
-	for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
-		rte_pktmbuf_free(mbufs[i]);
+	rte_pktmbuf_free_bulk(mbufs, RTE_PORT_IN_BURST_SIZE_MAX);
 
 	status = rte_table_hash_cuckoo_ops.f_free(table);
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 18/20] app/test-dma-perf: remove unnecessary null check
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (16 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 17/20] test: use rte_pktmbuf_free_bulk Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-11  1:16   ` fengchengwen
  2026-05-08 20:33 ` [PATCH 19/20] app/test-compress-perf: " Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 20/20] examples: use rte_pktmbuf_free_bulk Stephen Hemminger
  19 siblings, 1 reply; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Cheng Jiang, Chengwen Feng

Remove unnecessary if check before calling rte_pktmbuf_free_bulk.

Generated by devtools/cocci/null_free.cocci

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 app/test-dma-perf/benchmark.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/app/test-dma-perf/benchmark.c b/app/test-dma-perf/benchmark.c
index c0ffc859bd..576c59faff 100644
--- a/app/test-dma-perf/benchmark.c
+++ b/app/test-dma-perf/benchmark.c
@@ -690,10 +690,8 @@ teardown_memory_env(uint32_t nr_buf, struct rte_mbuf **srcs, struct rte_mbuf **d
 		    struct rte_dma_op **dma_ops)
 {
 	/* free mbufs used in the test */
-	if (srcs != NULL)
-		rte_pktmbuf_free_bulk(srcs, nr_buf);
-	if (dsts != NULL)
-		rte_pktmbuf_free_bulk(dsts, nr_buf);
+	rte_pktmbuf_free_bulk(srcs, nr_buf);
+	rte_pktmbuf_free_bulk(dsts, nr_buf);
 
 	/* free the points for the mbufs */
 	rte_free(srcs);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 19/20] app/test-compress-perf: remove unnecessary null check
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (17 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 18/20] app/test-dma-perf: remove unnecessary null check Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  2026-05-08 20:33 ` [PATCH 20/20] examples: use rte_pktmbuf_free_bulk Stephen Hemminger
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Remove unnecessary if check before calling rte_free
and rte_pktmbuf_free_bulk.

Generated by devtools/cocci/null_free.cocci

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 app/test-compress-perf/comp_perf_test_common.c | 6 ++----
 app/test-compress-perf/main.c                  | 6 ++----
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/app/test-compress-perf/comp_perf_test_common.c b/app/test-compress-perf/comp_perf_test_common.c
index 12c2a7bbd0..90eb98166e 100644
--- a/app/test-compress-perf/comp_perf_test_common.c
+++ b/app/test-compress-perf/comp_perf_test_common.c
@@ -83,11 +83,9 @@ comp_perf_free_memory(struct comp_test_data *test_data,
 {
 	uint32_t i;
 
-	if (mem->decomp_bufs != NULL)
-		rte_pktmbuf_free_bulk(mem->decomp_bufs, mem->total_bufs);
+	rte_pktmbuf_free_bulk(mem->decomp_bufs, mem->total_bufs);
 
-	if (mem->comp_bufs != NULL)
-		rte_pktmbuf_free_bulk(mem->comp_bufs, mem->total_bufs);
+	rte_pktmbuf_free_bulk(mem->comp_bufs, mem->total_bufs);
 
 	rte_free(mem->decomp_bufs);
 	rte_free(mem->comp_bufs);
diff --git a/app/test-compress-perf/main.c b/app/test-compress-perf/main.c
index c9ead02cb4..bc2b185da4 100644
--- a/app/test-compress-perf/main.c
+++ b/app/test-compress-perf/main.c
@@ -392,15 +392,13 @@ comp_perf_dump_dictionary_data(struct comp_test_data *td)
 
 		if (fread(data, data_to_read, 1, f) != 1) {
 			RTE_LOG(ERR, USER1, "Input file could not be read\n");
-			if (td->dictionary_data)
-				rte_free(td->dictionary_data);
+			rte_free(td->dictionary_data);
 			goto end;
 		}
 		if (fseek(f, 0, SEEK_SET) != 0) {
 			RTE_LOG(ERR, USER1,
 				"Size of input could not be calculated\n");
-			if (td->dictionary_data)
-				rte_free(td->dictionary_data);
+			rte_free(td->dictionary_data);
 			goto end;
 		}
 		remaining_data -= data_to_read;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 20/20] examples: use rte_pktmbuf_free_bulk
  2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
                   ` (18 preceding siblings ...)
  2026-05-08 20:33 ` [PATCH 19/20] app/test-compress-perf: " Stephen Hemminger
@ 2026-05-08 20:33 ` Stephen Hemminger
  19 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-08 20:33 UTC (permalink / raw)
  To: dev
  Cc: Stephen Hemminger, Nicolas Chautru, Akhil Goyal, Fan Zhang,
	Anatoly Burakov, Jingjing Wu, Volodymyr Fialko, Yipeng Wang,
	Maxime Coquelin, Chenbo Xia

Replace open-coded loop with rte_pktmbuf_free_bulk().

Generated by devtools/cocci/free_bulk.cocci.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 examples/bbdev_app/main.c                            |  4 +---
 examples/l2fwd-crypto/main.c                         |  4 ++--
 .../client_server_mp/mp_client/client.c              |  7 +++----
 .../multi_process/client_server_mp/mp_server/main.c  |  5 ++---
 examples/ntb/ntb_fwd.c                               | 12 +++++-------
 examples/packet_ordering/main.c                      |  5 +----
 examples/server_node_efd/efd_node/node.c             |  7 +++----
 examples/server_node_efd/efd_server/main.c           |  5 ++---
 examples/vhost/main.c                                |  3 +--
 9 files changed, 20 insertions(+), 32 deletions(-)

diff --git a/examples/bbdev_app/main.c b/examples/bbdev_app/main.c
index 03f15f91cc..4602f8012d 100644
--- a/examples/bbdev_app/main.c
+++ b/examples/bbdev_app/main.c
@@ -291,9 +291,7 @@ print_mac(unsigned int portid, struct rte_ether_addr *bbdev_ports_eth_address)
 static inline void
 pktmbuf_free_bulk(struct rte_mbuf **mbufs, unsigned int nb_to_free)
 {
-	unsigned int i;
-	for (i = 0; i < nb_to_free; ++i)
-		rte_pktmbuf_free(mbufs[i]);
+	rte_pktmbuf_free_bulk(mbufs, nb_to_free);
 }
 
 static inline void
diff --git a/examples/l2fwd-crypto/main.c b/examples/l2fwd-crypto/main.c
index a441312f55..3b2c23f29a 100644
--- a/examples/l2fwd-crypto/main.c
+++ b/examples/l2fwd-crypto/main.c
@@ -931,8 +931,8 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
 						RTE_CRYPTO_OP_TYPE_SYMMETRIC,
 						ops_burst, nb_rx) !=
 								nb_rx) {
-					for (j = 0; j < nb_rx; j++)
-						rte_pktmbuf_free(pkts_burst[j]);
+					rte_pktmbuf_free_bulk(pkts_burst,
+							      nb_rx);
 
 					nb_rx = 0;
 				}
diff --git a/examples/multi_process/client_server_mp/mp_client/client.c b/examples/multi_process/client_server_mp/mp_client/client.c
index 087c38ef73..9353ab7fda 100644
--- a/examples/multi_process/client_server_mp/mp_client/client.c
+++ b/examples/multi_process/client_server_mp/mp_client/client.c
@@ -117,15 +117,14 @@ parse_app_args(int argc, char *argv[])
  */
 static void
 flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count,
-		void *userdata) {
-	int i;
+		void *userdata)
+{
 	uint16_t port_id = (uintptr_t)userdata;
 
 	tx_stats->tx_drop[port_id] += count;
 
 	/* free the mbufs which failed from transmit */
-	for (i = 0; i < count; i++)
-		rte_pktmbuf_free(unsent[i]);
+	rte_pktmbuf_free_bulk(unsent, count);
 
 }
 
diff --git a/examples/multi_process/client_server_mp/mp_server/main.c b/examples/multi_process/client_server_mp/mp_server/main.c
index 691d453d0e..aa8b759aca 100644
--- a/examples/multi_process/client_server_mp/mp_server/main.c
+++ b/examples/multi_process/client_server_mp/mp_server/main.c
@@ -195,7 +195,6 @@ clear_stats(void)
 static void
 flush_rx_queue(uint16_t client)
 {
-	uint16_t j;
 	struct client *cl;
 
 	if (cl_rx_buf[client].count == 0)
@@ -204,8 +203,8 @@ flush_rx_queue(uint16_t client)
 	cl = &clients[client];
 	if (rte_ring_enqueue_bulk(cl->rx_q, (void **)cl_rx_buf[client].buffer,
 			cl_rx_buf[client].count, NULL) == 0){
-		for (j = 0; j < cl_rx_buf[client].count; j++)
-			rte_pktmbuf_free(cl_rx_buf[client].buffer[j]);
+		rte_pktmbuf_free_bulk(cl_rx_buf[client].buffer,
+				      cl_rx_buf[client].count);
 		cl->stats.rx_drop += cl_rx_buf[client].count;
 	}
 	else
diff --git a/examples/ntb/ntb_fwd.c b/examples/ntb/ntb_fwd.c
index 33f3c1ef17..fe2b1e6b2b 100644
--- a/examples/ntb/ntb_fwd.c
+++ b/examples/ntb/ntb_fwd.c
@@ -253,8 +253,7 @@ cmd_send_parsed(void *parsed_result,
 						(void *)queue_id);
 		if (ret < 0) {
 			printf("Enqueue failed with err %d\n", ret);
-			for (j = 0; j < nb_pkt; j++)
-				rte_pktmbuf_free(mbuf_send[j]);
+			rte_pktmbuf_free_bulk(mbuf_send, nb_pkt);
 			goto clean;
 		}
 		nb_tx = ret;
@@ -387,8 +386,8 @@ start_iofwd_per_lcore(void *param)
 				if (ret < 0) {
 					printf("Enqueue failed with err %d\n",
 						ret);
-					for (j = 0; j < nb_rx; j++)
-						rte_pktmbuf_free(pkts_burst[j]);
+					rte_pktmbuf_free_bulk(pkts_burst,
+							      nb_rx);
 					goto clean;
 				}
 				nb_tx = ret;
@@ -476,7 +475,7 @@ start_txonly_per_lcore(void *param)
 	struct ntb_fwd_lcore_conf *conf = param;
 	struct ntb_fwd_stream fs;
 	uint16_t nb_pkt, nb_tx;
-	int i, j, ret;
+	int i, ret;
 
 	for (i = 0; i < NTB_MAX_PKT_BURST; i++)
 		ntb_buf[i] = (struct rte_rawdev_buf *)
@@ -517,8 +516,7 @@ start_txonly_per_lcore(void *param)
 					nb_pkt, (void *)(size_t)fs.qp_id);
 			if (ret < 0) {
 				printf("Enqueue failed with err %d\n", ret);
-				for (j = 0; j < nb_pkt; j++)
-					rte_pktmbuf_free(pkts_burst[j]);
+				rte_pktmbuf_free_bulk(pkts_burst, nb_pkt);
 				goto clean;
 			}
 			nb_tx = ret;
diff --git a/examples/packet_ordering/main.c b/examples/packet_ordering/main.c
index 748fe0826a..f2097a90d4 100644
--- a/examples/packet_ordering/main.c
+++ b/examples/packet_ordering/main.c
@@ -128,10 +128,7 @@ get_previous_lcore_id(unsigned int id)
 static inline void
 pktmbuf_free_bulk(struct rte_mbuf *mbuf_table[], unsigned n)
 {
-	unsigned int i;
-
-	for (i = 0; i < n; i++)
-		rte_pktmbuf_free(mbuf_table[i]);
+	rte_pktmbuf_free_bulk(mbuf_table, n);
 }
 
 /* display usage */
diff --git a/examples/server_node_efd/efd_node/node.c b/examples/server_node_efd/efd_node/node.c
index fc2aa5ffef..5805e049b2 100644
--- a/examples/server_node_efd/efd_node/node.c
+++ b/examples/server_node_efd/efd_node/node.c
@@ -121,15 +121,14 @@ parse_app_args(int argc, char *argv[])
  */
 static void
 flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count,
-		void *userdata) {
-	int i;
+		void *userdata)
+{
 	uint16_t port_id = (uintptr_t)userdata;
 
 	tx_stats->tx_drop[port_id] += count;
 
 	/* free the mbufs which failed from transmit */
-	for (i = 0; i < count; i++)
-		rte_pktmbuf_free(unsent[i]);
+	rte_pktmbuf_free_bulk(unsent, count);
 
 }
 
diff --git a/examples/server_node_efd/efd_server/main.c b/examples/server_node_efd/efd_server/main.c
index 70a7372d4a..384bcfa780 100644
--- a/examples/server_node_efd/efd_server/main.c
+++ b/examples/server_node_efd/efd_server/main.c
@@ -218,7 +218,6 @@ clear_stats(void)
 static void
 flush_rx_queue(uint16_t node)
 {
-	uint16_t j;
 	struct node *cl;
 
 	if (cl_rx_buf[node].count == 0)
@@ -227,8 +226,8 @@ flush_rx_queue(uint16_t node)
 	cl = &nodes[node];
 	if (rte_ring_enqueue_bulk(cl->rx_q, (void **)cl_rx_buf[node].buffer,
 			cl_rx_buf[node].count, NULL) != cl_rx_buf[node].count){
-		for (j = 0; j < cl_rx_buf[node].count; j++)
-			rte_pktmbuf_free(cl_rx_buf[node].buffer[j]);
+		rte_pktmbuf_free_bulk(cl_rx_buf[node].buffer,
+				      cl_rx_buf[node].count);
 		cl->stats.rx_drop += cl_rx_buf[node].count;
 	} else
 		cl->stats.rx += cl_rx_buf[node].count;
diff --git a/examples/vhost/main.c b/examples/vhost/main.c
index ac888348d2..79561d6de0 100644
--- a/examples/vhost/main.c
+++ b/examples/vhost/main.c
@@ -1006,8 +1006,7 @@ unlink_vmdq(struct vhost_dev *vdev)
 					(uint16_t)vdev->vmdq_rx_q, pkts_burst, MAX_PKT_BURST);
 
 		while (rx_count) {
-			for (i = 0; i < rx_count; i++)
-				rte_pktmbuf_free(pkts_burst[i]);
+			rte_pktmbuf_free_bulk(pkts_burst, rx_count);
 
 			rx_count = rte_eth_rx_burst(ports[0],
 					(uint16_t)vdev->vmdq_rx_q, pkts_burst, MAX_PKT_BURST);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* RE: [PATCH 13/20] mbuf: allow NULL array in rte_pktmbuf_free_bulk
  2026-05-08 20:33 ` [PATCH 13/20] mbuf: allow NULL array in rte_pktmbuf_free_bulk Stephen Hemminger
@ 2026-05-09  8:47   ` Morten Brørup
  2026-05-09 15:46     ` Stephen Hemminger
  0 siblings, 1 reply; 26+ messages in thread
From: Morten Brørup @ 2026-05-09  8:47 UTC (permalink / raw)
  To: Stephen Hemminger, dev

> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Friday, 8 May 2026 22.34
> 
> This allows callers to avoid NULL checks and just call
> rte_pktmbuf_free_bulk, similar to rte_pktmbuf_free.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>

I disagree with this patch.

The parameter is an array of (pointers to) mbufs.
We already accept that the array can contain NULL pointers (no mbuf present).
This is extremely forgiving, considering that other fast path functions don't allow NULL pointers in arrays;
e.g. rte_eth_tx_burst(), rte_mempool_put_bulk().
But since it's a "free()" class of function, I don't object to it.

However, this patch changes the parameter type from "array" to "array or NULL (no array present)".
And I don't think we should change the parameter type; it should remain "array" only.

If there are any scenarios where a non-present array (NULL) is passed to the function, the count should be zero too.
And when the count is zero, the function does not dereference the array, so explicitly checking for NULL is superfluous.

We have a convention of not checking parameter validity in fast path functions.
And I consider it invalid parameters passing NULL with a non-zero count.

You might argue that this is a "free()" class of function, which warrants checking for NULL; but since it already accepts NULL with zero count, it is already covered.

We could change the function declaration for clarity:

void rte_pktmbuf_free_bulk(
		unsigned int count;
		struct rte_mbuf *mbufs[count], unsigned int count);

Or add a debug assertion at the start of the function:
RTE_ASSERT(mbufs != NULL || count == 0);


> ---
>  devtools/cocci/nullfree.cocci          | 5 ++++-
>  doc/guides/rel_notes/release_26_07.rst | 5 +++++
>  lib/mbuf/rte_mbuf.c                    | 3 +++
>  lib/mbuf/rte_mbuf.h                    | 1 +
>  4 files changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/devtools/cocci/nullfree.cocci
> b/devtools/cocci/nullfree.cocci
> index e7417b69ff..78e30f730a 100644
> --- a/devtools/cocci/nullfree.cocci
> +++ b/devtools/cocci/nullfree.cocci
> @@ -4,7 +4,7 @@
>  // free(NULL) as a no-op.
>  //
>  @@
> -expression E;
> +expression E, N;
>  @@
>  (
>  - if (E != NULL) cmdline_free(E);
> @@ -79,6 +79,9 @@ expression E;
>  - if (E != NULL) rte_pktmbuf_free(E);
>  + rte_pktmbuf_free(E);
>  |
> +- if (E != NULL) rte_pktmbuf_free_bulk(E, N);
> ++ rte_pktmbuf_free_bulk(E, N);
> +|
>  - if (E != NULL) rte_rib_free(E);
>  + rte_rib_free(E);
>  |
> diff --git a/doc/guides/rel_notes/release_26_07.rst
> b/doc/guides/rel_notes/release_26_07.rst
> index f012d47a4b..6f2f7f849f 100644
> --- a/doc/guides/rel_notes/release_26_07.rst
> +++ b/doc/guides/rel_notes/release_26_07.rst
> @@ -63,6 +63,11 @@ New Features
>      ``rte_eal_init`` and the application is responsible for probing
> each device,
>    * ``--auto-probing`` enables the initial bus probing, which is the
> current default behavior.
> 
> +* **mbuf: rte_pktmbuf_free_bulk now accepts NULL array pointer.**
> +
> +  Calling ``rte_pktmbuf_free_bulk`` with a NULL ``mbufs`` argument  is
> a no-op,
> +  matching the behavior of ``rte_pktmbuf_free()`` and ``rte_free()``.
> +
> 
>  Removed Items
>  -------------
> diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
> index c2476e7704..8ec3bb53bb 100644
> --- a/lib/mbuf/rte_mbuf.c
> +++ b/lib/mbuf/rte_mbuf.c
> @@ -562,6 +562,9 @@ void rte_pktmbuf_free_bulk(struct rte_mbuf **mbufs,
> unsigned int count)
>  	struct rte_mbuf *m, *m_next,
> *pending[RTE_PKTMBUF_FREE_PENDING_SZ];
>  	unsigned int idx, nb_pending = 0;
> 
> +	if (mbufs == NULL)
> +		return;
> +
>  	rte_mbuf_history_mark_bulk(mbufs, count,
> RTE_MBUF_HISTORY_OP_LIB_FREE);
> 
>  	for (idx = 0; idx < count; idx++) {
> diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
> index e7c3bbadd4..e9f8932e80 100644
> --- a/lib/mbuf/rte_mbuf.h
> +++ b/lib/mbuf/rte_mbuf.h
> @@ -1534,6 +1534,7 @@ static inline void rte_pktmbuf_free(struct
> rte_mbuf *m)
>   *  @param mbufs
>   *    Array of pointers to packet mbufs.
>   *    The array may contain NULL pointers.
> + *    The array pointer is NULL function does nothing.
>   *  @param count
>   *    Array size.
>   */
> --
> 2.53.0


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 13/20] mbuf: allow NULL array in rte_pktmbuf_free_bulk
  2026-05-09  8:47   ` Morten Brørup
@ 2026-05-09 15:46     ` Stephen Hemminger
  2026-05-10 12:31       ` Morten Brørup
  0 siblings, 1 reply; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-09 15:46 UTC (permalink / raw)
  To: Morten Brørup; +Cc: dev

On Sat, 9 May 2026 10:47:53 +0200
Morten Brørup <mb@smartsharesystems.com> wrote:

> > From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> > Sent: Friday, 8 May 2026 22.34
> > 
> > This allows callers to avoid NULL checks and just call
> > rte_pktmbuf_free_bulk, similar to rte_pktmbuf_free.
> > 
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>  
> 
> I disagree with this patch.
> 
> The parameter is an array of (pointers to) mbufs.
> We already accept that the array can contain NULL pointers (no mbuf present).
> This is extremely forgiving, considering that other fast path functions don't allow NULL pointers in arrays;
> e.g. rte_eth_tx_burst(), rte_mempool_put_bulk().
> But since it's a "free()" class of function, I don't object to it.
> 
> However, this patch changes the parameter type from "array" to "array or NULL (no array present)".
> And I don't think we should change the parameter type; it should remain "array" only.
> 
> If there are any scenarios where a non-present array (NULL) is passed to the function, the count should be zero too.
> And when the count is zero, the function does not dereference the array, so explicitly checking for NULL is superfluous.
> 
> We have a convention of not checking parameter validity in fast path functions.
> And I consider it invalid parameters passing NULL with a non-zero count.
> 
> You might argue that this is a "free()" class of function, which warrants checking for NULL; but since it already accepts NULL with zero count, it is already covered.
> 
> We could change the function declaration for clarity:
> 
> void rte_pktmbuf_free_bulk(
> 		unsigned int count;
> 		struct rte_mbuf *mbufs[count], unsigned int count);
> 
> Or add a debug assertion at the start of the function:
> RTE_ASSERT(mbufs != NULL || count == 0);

Ok, it was more motivated by common pattern in driver cleanup paths like:

--- a/app/test-compress-perf/comp_perf_test_common.c
+++ b/app/test-compress-perf/comp_perf_test_common.c
@@ -83,11 +83,9 @@ comp_perf_free_memory(struct comp_test_data *test_data,
 {
 	uint32_t i;
 
-	if (mem->decomp_bufs != NULL)
-		rte_pktmbuf_free_bulk(mem->decomp_bufs, mem->total_bufs);
+	rte_pktmbuf_free_bulk(mem->decomp_bufs, mem->total_bufs);
 
-	if (mem->comp_bufs != NULL)
-		rte_pktmbuf_free_bulk(mem->comp_bufs, mem->total_bufs);
+	rte_pktmbuf_free_bulk(mem->comp_bufs, mem->total_bufs);
 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH 13/20] mbuf: allow NULL array in rte_pktmbuf_free_bulk
  2026-05-09 15:46     ` Stephen Hemminger
@ 2026-05-10 12:31       ` Morten Brørup
  2026-05-10 15:21         ` Stephen Hemminger
  0 siblings, 1 reply; 26+ messages in thread
From: Morten Brørup @ 2026-05-10 12:31 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Saturday, 9 May 2026 17.47
> 
> On Sat, 9 May 2026 10:47:53 +0200
> Morten Brørup <mb@smartsharesystems.com> wrote:
> 
> > > From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> > > Sent: Friday, 8 May 2026 22.34
> > >
> > > This allows callers to avoid NULL checks and just call
> > > rte_pktmbuf_free_bulk, similar to rte_pktmbuf_free.
> > >
> > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> >
> > I disagree with this patch.
> >
> > The parameter is an array of (pointers to) mbufs.
> > We already accept that the array can contain NULL pointers (no mbuf
> present).
> > This is extremely forgiving, considering that other fast path
> functions don't allow NULL pointers in arrays;
> > e.g. rte_eth_tx_burst(), rte_mempool_put_bulk().
> > But since it's a "free()" class of function, I don't object to it.
> >
> > However, this patch changes the parameter type from "array" to "array
> or NULL (no array present)".
> > And I don't think we should change the parameter type; it should
> remain "array" only.
> >
> > If there are any scenarios where a non-present array (NULL) is passed
> to the function, the count should be zero too.
> > And when the count is zero, the function does not dereference the
> array, so explicitly checking for NULL is superfluous.
> >
> > We have a convention of not checking parameter validity in fast path
> functions.
> > And I consider it invalid parameters passing NULL with a non-zero
> count.
> >
> > You might argue that this is a "free()" class of function, which
> warrants checking for NULL; but since it already accepts NULL with zero
> count, it is already covered.
> >
> > We could change the function declaration for clarity:
> >
> > void rte_pktmbuf_free_bulk(
> > 		unsigned int count;
> > 		struct rte_mbuf *mbufs[count], unsigned int count);
> >
> > Or add a debug assertion at the start of the function:
> > RTE_ASSERT(mbufs != NULL || count == 0);
> 
> Ok, it was more motivated by common pattern in driver cleanup paths
> like:
> 
> --- a/app/test-compress-perf/comp_perf_test_common.c
> +++ b/app/test-compress-perf/comp_perf_test_common.c
> @@ -83,11 +83,9 @@ comp_perf_free_memory(struct comp_test_data
> *test_data,
>  {
>  	uint32_t i;
> 
> -	if (mem->decomp_bufs != NULL)
> -		rte_pktmbuf_free_bulk(mem->decomp_bufs, mem->total_bufs);
> +	rte_pktmbuf_free_bulk(mem->decomp_bufs, mem->total_bufs);
> 
> -	if (mem->comp_bufs != NULL)
> -		rte_pktmbuf_free_bulk(mem->comp_bufs, mem->total_bufs);
> +	rte_pktmbuf_free_bulk(mem->comp_bufs, mem->total_bufs);
> 

Skimming comp_perf_test_common.c, it looks like mem->total_bufs is initialized to the number of wanted buffers, and then mem->decomp_bufs is set up afterwards. In other words, total_bufs can be non-zero while comp_bufs is NULL.

IMO, removing the NULL comparison here would pass invalid parameters to rte_pktmbuf_free_bulk().

Train of thoughts...

On the other hand, it does provide a good example where considering rte_pktmbuf_free_bulk() a "free()" class function accepting a NULL pointer would be helpful.
And the added performance cost of checking for a NULL pointer is per burst, not per packet.
I'm not as strongly opposed as I was initially.

However, looking at it in a broader scope gets me be back to being opposed:
This patch is for freeing mbufs.
If we consider freeing mempool objects, the cleanup function would call rte_mempool_put_bulk() to free the objects, which is the function for freeing previously allocated mempool objects. It just happens to not have "free" as part of its name.

The mempool single object "free()" function, rte_mempool_put(), doesn't accept a NULL pointer.
Similarly, the mempool bulk free function, rte_mempool_put_bulk(), doesn't accept holes (NULL pointers) in the array.
I certainly do not want to introduce holes into mempool object arrays.

Maybe it was a bad decision to allow holes in mbuf arrays being passed to rte_pktmbuf_free_bulk(). Such holes are not accepted in any other DPDK APIs.

At this point, I'm still not in favor of this patch.
It's defensive coding (with a performance cost, however small) in a fast path function.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 13/20] mbuf: allow NULL array in rte_pktmbuf_free_bulk
  2026-05-10 12:31       ` Morten Brørup
@ 2026-05-10 15:21         ` Stephen Hemminger
  0 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2026-05-10 15:21 UTC (permalink / raw)
  To: Morten Brørup; +Cc: dev

On Sun, 10 May 2026 14:31:57 +0200
Morten Brørup <mb@smartsharesystems.com> wrote:

> > From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> > Sent: Saturday, 9 May 2026 17.47
> > 
> > On Sat, 9 May 2026 10:47:53 +0200
> > Morten Brørup <mb@smartsharesystems.com> wrote:
> >   
> > > > From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> > > > Sent: Friday, 8 May 2026 22.34
> > > >
> > > > This allows callers to avoid NULL checks and just call
> > > > rte_pktmbuf_free_bulk, similar to rte_pktmbuf_free.
> > > >
> > > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>  
> > >
> > > I disagree with this patch.
> > >
> > > The parameter is an array of (pointers to) mbufs.
> > > We already accept that the array can contain NULL pointers (no mbuf  
> > present).  
> > > This is extremely forgiving, considering that other fast path  
> > functions don't allow NULL pointers in arrays;  
> > > e.g. rte_eth_tx_burst(), rte_mempool_put_bulk().
> > > But since it's a "free()" class of function, I don't object to it.
> > >
> > > However, this patch changes the parameter type from "array" to "array  
> > or NULL (no array present)".  
> > > And I don't think we should change the parameter type; it should  
> > remain "array" only.  
> > >
> > > If there are any scenarios where a non-present array (NULL) is passed  
> > to the function, the count should be zero too.  
> > > And when the count is zero, the function does not dereference the  
> > array, so explicitly checking for NULL is superfluous.  
> > >
> > > We have a convention of not checking parameter validity in fast path  
> > functions.  
> > > And I consider it invalid parameters passing NULL with a non-zero  
> > count.  
> > >
> > > You might argue that this is a "free()" class of function, which  
> > warrants checking for NULL; but since it already accepts NULL with zero
> > count, it is already covered.  
> > >
> > > We could change the function declaration for clarity:
> > >
> > > void rte_pktmbuf_free_bulk(
> > > 		unsigned int count;
> > > 		struct rte_mbuf *mbufs[count], unsigned int count);
> > >
> > > Or add a debug assertion at the start of the function:
> > > RTE_ASSERT(mbufs != NULL || count == 0);  
> > 
> > Ok, it was more motivated by common pattern in driver cleanup paths
> > like:
> > 
> > --- a/app/test-compress-perf/comp_perf_test_common.c
> > +++ b/app/test-compress-perf/comp_perf_test_common.c
> > @@ -83,11 +83,9 @@ comp_perf_free_memory(struct comp_test_data
> > *test_data,
> >  {
> >  	uint32_t i;
> > 
> > -	if (mem->decomp_bufs != NULL)
> > -		rte_pktmbuf_free_bulk(mem->decomp_bufs, mem->total_bufs);
> > +	rte_pktmbuf_free_bulk(mem->decomp_bufs, mem->total_bufs);
> > 
> > -	if (mem->comp_bufs != NULL)
> > -		rte_pktmbuf_free_bulk(mem->comp_bufs, mem->total_bufs);
> > +	rte_pktmbuf_free_bulk(mem->comp_bufs, mem->total_bufs);
> >   
> 
> Skimming comp_perf_test_common.c, it looks like mem->total_bufs is initialized to the number of wanted buffers, and then mem->decomp_bufs is set up afterwards. In other words, total_bufs can be non-zero while comp_bufs is NULL.
> 
> IMO, removing the NULL comparison here would pass invalid parameters to rte_pktmbuf_free_bulk().
> 
> Train of thoughts...
> 
> On the other hand, it does provide a good example where considering rte_pktmbuf_free_bulk() a "free()" class function accepting a NULL pointer would be helpful.
> And the added performance cost of checking for a NULL pointer is per burst, not per packet.
> I'm not as strongly opposed as I was initially.
> 
> However, looking at it in a broader scope gets me be back to being opposed:
> This patch is for freeing mbufs.
> If we consider freeing mempool objects, the cleanup function would call rte_mempool_put_bulk() to free the objects, which is the function for freeing previously allocated mempool objects. It just happens to not have "free" as part of its name.
> 
> The mempool single object "free()" function, rte_mempool_put(), doesn't accept a NULL pointer.
> Similarly, the mempool bulk free function, rte_mempool_put_bulk(), doesn't accept holes (NULL pointers) in the array.
> I certainly do not want to introduce holes into mempool object arrays.
> 
> Maybe it was a bad decision to allow holes in mbuf arrays being passed to rte_pktmbuf_free_bulk(). Such holes are not accepted in any other DPDK APIs.
> 
> At this point, I'm still not in favor of this patch.
> It's defensive coding (with a performance cost, however small) in a fast path function.
> 

More thoughts.
- allowing NULL array is not worth it; not a big win, and only one place mattered

- allowing holes in array seems odd, and not that useful. Probably can't change now.
  Not sure why callers would need it.

- Probably should add RTE_ASSERT() into free bulk. Should allow rte_pktmbuf_free_bulk(NULL, 0)
  for consistency with some other API's that take array and count. But assert should trigger
  on rte_pktmbuf_free_bulk(NULL, 1)

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 18/20] app/test-dma-perf: remove unnecessary null check
  2026-05-08 20:33 ` [PATCH 18/20] app/test-dma-perf: remove unnecessary null check Stephen Hemminger
@ 2026-05-11  1:16   ` fengchengwen
  0 siblings, 0 replies; 26+ messages in thread
From: fengchengwen @ 2026-05-11  1:16 UTC (permalink / raw)
  To: Stephen Hemminger, dev; +Cc: Cheng Jiang

NACK
The srcs / dsts may be NULL if setup_memory_env() failed.

On 5/9/2026 4:33 AM, Stephen Hemminger wrote:
> Remove unnecessary if check before calling rte_pktmbuf_free_bulk.
> 
> Generated by devtools/cocci/null_free.cocci
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
>  app/test-dma-perf/benchmark.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/app/test-dma-perf/benchmark.c b/app/test-dma-perf/benchmark.c
> index c0ffc859bd..576c59faff 100644
> --- a/app/test-dma-perf/benchmark.c
> +++ b/app/test-dma-perf/benchmark.c
> @@ -690,10 +690,8 @@ teardown_memory_env(uint32_t nr_buf, struct rte_mbuf **srcs, struct rte_mbuf **d
>  		    struct rte_dma_op **dma_ops)
>  {
>  	/* free mbufs used in the test */
> -	if (srcs != NULL)
> -		rte_pktmbuf_free_bulk(srcs, nr_buf);
> -	if (dsts != NULL)
> -		rte_pktmbuf_free_bulk(dsts, nr_buf);
> +	rte_pktmbuf_free_bulk(srcs, nr_buf);
> +	rte_pktmbuf_free_bulk(dsts, nr_buf);
>  
>  	/* free the points for the mbufs */
>  	rte_free(srcs);


^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2026-05-11  1:16 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-08 20:33 [PATCH 00/20] pktmbuf free bulk cleanups Stephen Hemminger
2026-05-08 20:33 ` [PATCH 01/20] devtools/cocci: add transform for rte_pktmbuf_free_bulk Stephen Hemminger
2026-05-08 20:33 ` [PATCH 02/20] eventdev: use rte_pktmbuf_free_bulk Stephen Hemminger
2026-05-08 20:33 ` [PATCH 03/20] gso: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 04/20] ip_frag: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 05/20] pipeline: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 06/20] port: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 07/20] net/af_xdp: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 08/20] net/cnxk: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 09/20] net/pfe: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 10/20] net/virtio: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 11/20] net/zxdh: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 12/20] app/compress-perf: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 13/20] mbuf: allow NULL array in rte_pktmbuf_free_bulk Stephen Hemminger
2026-05-09  8:47   ` Morten Brørup
2026-05-09 15:46     ` Stephen Hemminger
2026-05-10 12:31       ` Morten Brørup
2026-05-10 15:21         ` Stephen Hemminger
2026-05-08 20:33 ` [PATCH 14/20] net/zxdh: remove unnecessary null check Stephen Hemminger
2026-05-08 20:33 ` [PATCH 15/20] net/ice: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 16/20] net/bnxt: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 17/20] test: use rte_pktmbuf_free_bulk Stephen Hemminger
2026-05-08 20:33 ` [PATCH 18/20] app/test-dma-perf: remove unnecessary null check Stephen Hemminger
2026-05-11  1:16   ` fengchengwen
2026-05-08 20:33 ` [PATCH 19/20] app/test-compress-perf: " Stephen Hemminger
2026-05-08 20:33 ` [PATCH 20/20] examples: use rte_pktmbuf_free_bulk Stephen Hemminger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox