]> git.droids-corp.org - dpdk.git/commitdiff
net/mlx5: fix meter action pool protection
authorJiawei Wang <jiaweiw@nvidia.com>
Mon, 1 Nov 2021 06:30:40 +0000 (08:30 +0200)
committerRaslan Darawsheh <rasland@nvidia.com>
Mon, 1 Nov 2021 13:53:36 +0000 (14:53 +0100)
The ASO meter action with flows creation could be supported on
multiple threads. The meter pools were created to manage the meter
object resources, if there is no room in the current meter pool then
resize the meter pool to the new pool size and free the old one.

There's a race condition while one thread resizes the meter pool and
the old pool resource be freed, and another thread query the meter
object by index on the old pool, the return value is invalid.

This patch adds a read-write lock to protect the pool resource while
resizing and query.

Fixes: a5835d530f00 ("net/mlx5: optimize Rx queue match")
Cc: stable@dpdk.org
Signed-off-by: Jiawei Wang <jiaweiw@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
drivers/net/mlx5/mlx5.c
drivers/net/mlx5/mlx5.h
drivers/net/mlx5/mlx5_flow.h
drivers/net/mlx5/mlx5_flow_dv.c
drivers/net/mlx5/mlx5_flow_meter.c

index b90752c56df759073260904cc38a3ec74ea45551..4ba850af263cee86d206af62827d7447c2f9bd9b 100644 (file)
@@ -632,6 +632,7 @@ mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh)
                }
                if (sh->meter_aso_en) {
                        rte_spinlock_init(&sh->mtrmng->pools_mng.mtrsl);
+                       rte_rwlock_init(&sh->mtrmng->pools_mng.resize_mtrwl);
                        LIST_INIT(&sh->mtrmng->pools_mng.meters);
                }
                sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
index 5e88dfcfea1623ab5f5eadab7c8c850d856e6f57..39c001aa1bf7fab2ca2944681860dba70fdb3344 100644 (file)
@@ -895,6 +895,7 @@ struct mlx5_aso_mtr_pools_mng {
        volatile uint16_t n_valid; /* Number of valid pools. */
        uint16_t n; /* Number of pools. */
        rte_spinlock_t mtrsl; /* The ASO flow meter free list lock. */
+       rte_rwlock_t resize_mtrwl; /* Lock for resize objects. */
        struct aso_meter_list meters; /* Free ASO flow meter list. */
        struct mlx5_aso_sq sq; /*SQ using by ASO flow meter. */
        struct mlx5_aso_mtr_pool **pools; /* ASO flow meter pool array. */
index 01ecfab9f4d70996bf7946303daf5e963de73345..5509c28f01c4985a0c037a1706ff463dda52b2c0 100644 (file)
@@ -1337,7 +1337,9 @@ mlx5_aso_meter_by_idx(struct mlx5_priv *priv, uint32_t idx)
        /* Decrease to original index. */
        idx--;
        MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < pools_mng->n);
+       rte_rwlock_read_lock(&pools_mng->resize_mtrwl);
        pool = pools_mng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
+       rte_rwlock_read_unlock(&pools_mng->resize_mtrwl);
        return &pool->mtrs[idx % MLX5_ASO_MTRS_PER_POOL];
 }
 
index 22081dddd31d397990b017633471aadebc57c421..8962d26c75d7093c7710da6c5408c8d99da8d6f3 100644 (file)
@@ -6398,14 +6398,17 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev, struct mlx5_aso_mtr **mtr_free)
                return NULL;
        }
        pool->devx_obj = dcs;
+       rte_rwlock_write_lock(&pools_mng->resize_mtrwl);
        pool->index = pools_mng->n_valid;
        if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) {
                mlx5_free(pool);
                claim_zero(mlx5_devx_cmd_destroy(dcs));
+               rte_rwlock_write_unlock(&pools_mng->resize_mtrwl);
                return NULL;
        }
        pools_mng->pools[pool->index] = pool;
        pools_mng->n_valid++;
+       rte_rwlock_write_unlock(&pools_mng->resize_mtrwl);
        for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
                pool->mtrs[i].offset = i;
                LIST_INSERT_HEAD(&pools_mng->meters, &pool->mtrs[i], next);
index ba4e9fca1723cb90e4ca1c7db3aa3bc92a89b95e..f4a7b697e63f1a940bf8cf43916cca347346e2c8 100644 (file)
@@ -1789,24 +1789,21 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
        struct mlx5_aso_mtr_pools_mng *pools_mng =
                                &priv->sh->mtrmng->pools_mng;
        union mlx5_l3t_data data;
+       uint16_t n_valid;
 
        if (priv->sh->meter_aso_en) {
-               rte_spinlock_lock(&pools_mng->mtrsl);
-               if (!pools_mng->n_valid || !priv->mtr_idx_tbl) {
-                       rte_spinlock_unlock(&pools_mng->mtrsl);
+               rte_rwlock_read_lock(&pools_mng->resize_mtrwl);
+               n_valid = pools_mng->n_valid;
+               rte_rwlock_read_unlock(&pools_mng->resize_mtrwl);
+               if (!n_valid || !priv->mtr_idx_tbl ||
+                   (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
+                   !data.dword))
                        return NULL;
-               }
-               if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
-                       !data.dword) {
-                       rte_spinlock_unlock(&pools_mng->mtrsl);
-                       return NULL;
-               }
                if (mtr_idx)
                        *mtr_idx = data.dword;
                aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
                /* Remove reference taken by the mlx5_l3t_get_entry. */
                mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
-               rte_spinlock_unlock(&pools_mng->mtrsl);
                if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
                        return NULL;
                return &aso_mtr->fm;