From: Jun Yang <[email protected]>

A BPID allocated by dpaa_mbuf_create_pool() is only returned to the
kernel allocator from dpaa_mbuf_free_pool(). An application that exits
without calling rte_mempool_free() therefore leaks the BPID, and the ID
stays reserved until the board is rebooted.

Track the allocated BPIDs and the flags they were created with in a
static per-BPID table, and add a driver destructor that releases any
BPID still marked in use at process exit. The destructor cannot touch
the bman_pool object because it lives in EAL memory that may already be
gone, so bman_free_bpid() is added to release the ID from the flags
alone.

The rte_dpaa_bpid_info array is shared hugepage memory referenced by
every Rx queue through fq->bp_array, including in secondary processes,
so it must not be freed when the last local mempool is released. Free it
from the destructor instead, once, at process teardown, and only clear
the per-BPID mp and bp pointers in dpaa_mbuf_free_pool(). Free the
correct pointer there as well: bp_info rather than mp->pool_data, which
is the same allocation but was being dereferenced after the free.

Allocate bp_info with rte_zmalloc() so no uninitialised field is left
behind, and use FSL_BM_BURST_MAX instead of the open-coded 8 for the
hardware bulk acquire size.

Signed-off-by: Jun Yang <[email protected]>
---
 drivers/bus/dpaa/base/qbman/bman.c       |  8 +++
 drivers/bus/dpaa/dpaa_bus_base_symbols.c |  1 +
 drivers/bus/dpaa/include/fsl_bman.h      |  3 ++
 drivers/mempool/dpaa/dpaa_mempool.c      | 68 +++++++++++++++++++++---
 drivers/mempool/dpaa/dpaa_mempool.h      |  2 +-
 5 files changed, 74 insertions(+), 8 deletions(-)

diff --git a/drivers/bus/dpaa/base/qbman/bman.c 
b/drivers/bus/dpaa/base/qbman/bman.c
index ee4232d0a0..0ae1160973 100644
--- a/drivers/bus/dpaa/base/qbman/bman.c
+++ b/drivers/bus/dpaa/base/qbman/bman.c
@@ -251,6 +251,14 @@ void bman_free_pool(struct bman_pool *pool)
        kfree(pool);
 }
 
+void bman_free_bpid(u8 bpid, u32 flags)
+{
+       if (flags & BMAN_POOL_FLAG_THRESH)
+               bm_pool_set(bpid, zero_thresholds);
+       if (flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
+               bman_release_bpid(bpid);
+}
+
 const struct bman_pool_params *bman_get_params(const struct bman_pool *pool)
 {
        return &pool->params;
diff --git a/drivers/bus/dpaa/dpaa_bus_base_symbols.c 
b/drivers/bus/dpaa/dpaa_bus_base_symbols.c
index b806b44d29..7a9b08e68c 100644
--- a/drivers/bus/dpaa/dpaa_bus_base_symbols.c
+++ b/drivers/bus/dpaa/dpaa_bus_base_symbols.c
@@ -44,6 +44,7 @@ RTE_EXPORT_INTERNAL_SYMBOL(fman_if_receive_rx_errors)
 RTE_EXPORT_INTERNAL_SYMBOL(netcfg_acquire)
 RTE_EXPORT_INTERNAL_SYMBOL(netcfg_release)
 RTE_EXPORT_INTERNAL_SYMBOL(bman_new_pool)
+RTE_EXPORT_INTERNAL_SYMBOL(bman_free_bpid)
 RTE_EXPORT_INTERNAL_SYMBOL(bman_free_pool)
 RTE_EXPORT_INTERNAL_SYMBOL(bman_get_params)
 RTE_EXPORT_INTERNAL_SYMBOL(bman_release)
diff --git a/drivers/bus/dpaa/include/fsl_bman.h 
b/drivers/bus/dpaa/include/fsl_bman.h
index 639e0edc96..88e4df503f 100644
--- a/drivers/bus/dpaa/include/fsl_bman.h
+++ b/drivers/bus/dpaa/include/fsl_bman.h
@@ -292,6 +292,9 @@ struct bman_pool *bman_new_pool(const struct 
bman_pool_params *params);
 __rte_internal
 void bman_free_pool(struct bman_pool *pool);
 
+__rte_internal
+void bman_free_bpid(u8 bpid, u32 flags);
+
 /**
  * bman_get_params - Returns a pool object's parameters.
  * @pool: the pool object
diff --git a/drivers/mempool/dpaa/dpaa_mempool.c 
b/drivers/mempool/dpaa/dpaa_mempool.c
index 2f8555a026..2e9453a873 100644
--- a/drivers/mempool/dpaa/dpaa_mempool.c
+++ b/drivers/mempool/dpaa/dpaa_mempool.c
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  *
- *   Copyright 2017,2019,2023-2025 NXP
+ *   Copyright 2017,2019,2023-2026 NXP
  *
  */
 
@@ -25,10 +25,24 @@
 #include <rte_eal.h>
 #include <rte_malloc.h>
 #include <rte_ring.h>
+#include <rte_common.h>
 
 #include <dpaa_mempool.h>
 #include <dpaax_iova_table.h>
 
+struct dpaa_bpid_flag {
+       uint32_t flags;
+       bool used;
+};
+
+/* Referenced from the destructor to release the BPIDs allocated by this
+ * process. The destructor cannot touch the bman_pool object because it lives
+ * in EAL memory that rte_eal_cleanup() may already have detached, so the ID
+ * is released from the recorded flags alone. This table is process-local
+ * static storage and therefore still valid at that point.
+ */
+static struct dpaa_bpid_flag s_dpaa_bpid_allocated_flag[DPAA_MAX_BPOOLS];
+
 #define FMAN_ERRATA_BOUNDARY ((uint64_t)4096)
 #define FMAN_ERRATA_BOUNDARY_MASK (~(FMAN_ERRATA_BOUNDARY - 1))
 
@@ -50,7 +64,7 @@ static int
 dpaa_mbuf_create_pool(struct rte_mempool *mp)
 {
        struct bman_pool *bp;
-       struct bm_buffer bufs[8];
+       struct bm_buffer bufs[FSL_BM_BURST_MAX];
        struct dpaa_bp_info *bp_info;
        uint8_t bpid;
        int num_bufs = 0, ret = 0;
@@ -83,8 +97,8 @@ dpaa_mbuf_create_pool(struct rte_mempool *mp)
                 * then in 1s for the remainder.
                 */
                if (ret != 1)
-                       ret = bman_acquire(bp, bufs, 8, 0);
-               if (ret < 8)
+                       ret = bman_acquire(bp, bufs, FSL_BM_BURST_MAX, 0);
+               if (ret < FSL_BM_BURST_MAX)
                        ret = bman_acquire(bp, bufs, 1, 0);
                if (ret > 0)
                        num_bufs += ret;
@@ -115,7 +129,7 @@ dpaa_mbuf_create_pool(struct rte_mempool *mp)
        rte_dpaa_bpid_info[bpid].ptov_off = 0;
        rte_dpaa_bpid_info[bpid].flags = 0;
 
-       bp_info = rte_malloc(NULL,
+       bp_info = rte_zmalloc(NULL,
                             sizeof(struct dpaa_bp_info),
                             RTE_CACHE_LINE_SIZE);
        if (!bp_info) {
@@ -127,6 +141,8 @@ dpaa_mbuf_create_pool(struct rte_mempool *mp)
        rte_memcpy(bp_info, (void *)&rte_dpaa_bpid_info[bpid],
                   sizeof(struct dpaa_bp_info));
        mp->pool_data = (void *)bp_info;
+       s_dpaa_bpid_allocated_flag[bpid].flags = params.flags;
+       s_dpaa_bpid_allocated_flag[bpid].used = true;
 
        DPAA_MEMPOOL_INFO("BMAN pool created for bpid =%d", bpid);
        return 0;
@@ -143,10 +159,26 @@ dpaa_mbuf_free_pool(struct rte_mempool *mp)
                bman_free_pool(bp_info->bp);
                DPAA_MEMPOOL_INFO("BMAN pool freed for bpid =%d",
                                  bp_info->bpid);
-               rte_free(mp->pool_data);
-               bp_info->bp = NULL;
+               if (rte_dpaa_bpid_info != NULL) {
+                       rte_dpaa_bpid_info[bp_info->bpid].mp = NULL;
+                       rte_dpaa_bpid_info[bp_info->bpid].bp = NULL;
+               }
+               s_dpaa_bpid_allocated_flag[bp_info->bpid].used = false;
+               rte_free(bp_info);
                mp->pool_data = NULL;
        }
+
+       /* rte_dpaa_bpid_info is not freed here, and not from the driver
+        * destructor either. It is shared (hugepage) memory referenced by
+        * every Rx queue via fq->bp_array, including in secondary processes:
+        * in a secondary the pointer is not even a local allocation, the Rx
+        * path installs the primary's array (see dpaa_rxtx.c). Releasing it
+        * when the last local mempool goes away would leave those references
+        * dangling, and a destructor cannot release it either because
+        * rte_eal_cleanup() detaches EAL memory before the destructors run.
+        * The array is a fixed-size per-process table, so it is simply left
+        * to the process teardown.
+        */
 }
 
 static int
@@ -481,4 +513,26 @@ static const struct rte_mempool_ops dpaa_mpool_ops = {
        .populate = dpaa_populate,
 };
 
+#define RTE_PRIORITY_104 104
+
+RTE_FINI_PRIO(dpaa_mpool_finish, RTE_PRIORITY_104)
+{
+       uint16_t bpid;
+
+       for (bpid = 0; bpid < DPAA_MAX_BPOOLS; bpid++) {
+               if (s_dpaa_bpid_allocated_flag[bpid].used) {
+                       bman_free_bpid(bpid, 
s_dpaa_bpid_allocated_flag[bpid].flags);
+                       s_dpaa_bpid_allocated_flag[bpid].used = false;
+               }
+       }
+
+       /* rte_dpaa_bpid_info is deliberately not freed here. It is EAL memory,
+        * and rte_eal_cleanup() has already called rte_eal_memory_detach() by
+        * the time the destructors run, so rte_free() would operate on an
+        * unmapped mapping. In a secondary it is not even a local allocation:
+        * the Rx path installs the primary's array (see dpaa_rxtx.c), so
+        * freeing it would release the primary's live BPID table.
+        */
+}
+
 RTE_MEMPOOL_REGISTER_OPS(dpaa_mpool_ops);
diff --git a/drivers/mempool/dpaa/dpaa_mempool.h 
b/drivers/mempool/dpaa/dpaa_mempool.h
index 865b533b8f..ca34747711 100644
--- a/drivers/mempool/dpaa/dpaa_mempool.h
+++ b/drivers/mempool/dpaa/dpaa_mempool.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  *
- *   Copyright 2017,2019,2024 -2025 NXP
+ *   Copyright 2017,2019,2024 -2026 NXP
  *
  */
 #ifndef __DPAA_MEMPOOL_H__
-- 
2.25.1

Reply via email to