From 7797b0fe64463d46b0c91f61bacc01a48e23f8e8 Mon Sep 17 00:00:00 2001 From: Jiawei Wang Date: Mon, 1 Nov 2021 08:30:40 +0200 Subject: [PATCH] net/mlx5: fix meter action pool protection 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 Acked-by: Matan Azrad --- drivers/net/mlx5/mlx5.c | 1 + drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_flow.h | 2 ++ drivers/net/mlx5/mlx5_flow_dv.c | 3 +++ drivers/net/mlx5/mlx5_flow_meter.c | 17 +++++++---------- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index b90752c56d..4ba850af26 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -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; diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 5e88dfcfea..39c001aa1b 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -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. */ diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 01ecfab9f4..5509c28f01 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -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]; } diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 22081dddd3..8962d26c75 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -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); diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c index ba4e9fca17..f4a7b697e6 100644 --- a/drivers/net/mlx5/mlx5_flow_meter.c +++ b/drivers/net/mlx5/mlx5_flow_meter.c @@ -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; -- 2.20.1