[23/25] net/mlx5: make meter action thread safe
diff mbox series

Message ID 1601984948-313027-24-git-send-email-suanmingm@nvidia.com
State Superseded, archived
Delegated to: Raslan Darawsheh
Headers show
Series
  • net/mlx5: support multiple-thread flow operations
Related show

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Suanming Mou Oct. 6, 2020, 11:49 a.m. UTC
This commits add the spinlock for the meter action to make it be thread
safe. Atomic reference count is not engough as the meter action should
be created synchronized with reference count increase. With only atomic
reference count, even the count is increased, the action may still not
be created.

Signed-off-by: Suanming Mou <suanmingm@nvidia.com>
---
 drivers/net/mlx5/mlx5_flow.h       |  2 ++
 drivers/net/mlx5/mlx5_flow_meter.c | 72 ++++++++++++++++++++------------------
 2 files changed, 39 insertions(+), 35 deletions(-)

Patch
diff mbox series

diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 2e060e6..e6890a4 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -748,6 +748,8 @@  struct mlx5_flow_meter {
 	struct mlx5_flow_meter_profile *profile;
 	/**< Meter profile parameters. */
 
+	rte_spinlock_t sl; /**< Meter action spinlock. */
+
 	/** Policer actions (per meter output color). */
 	enum rte_mtr_policer_action action[RTE_COLORS];
 
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index b36bc7b..cba8389 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -679,6 +679,7 @@ 
 	fm->shared = !!shared;
 	fm->policer_stats.stats_mask = params->stats_mask;
 	fm->profile->ref_cnt++;
+	rte_spinlock_init(&fm->sl);
 	return 0;
 error:
 	mlx5_flow_destroy_policer_rules(dev, fm, &attr);
@@ -1167,49 +1168,49 @@  struct mlx5_flow_meter *
 		       struct rte_flow_error *error)
 {
 	struct mlx5_flow_meter *fm;
+	int ret = 0;
 
 	fm = mlx5_flow_meter_find(priv, meter_id);
 	if (fm == NULL) {
 		rte_flow_error_set(error, ENOENT,
 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 				   "Meter object id not valid");
-		goto error;
-	}
-	if (!fm->shared && fm->ref_cnt) {
-		DRV_LOG(ERR, "Cannot share a non-shared meter.");
-		rte_flow_error_set(error, EINVAL,
-				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				  "Meter can't be shared");
-		goto error;
+		return fm;
 	}
-	if (!fm->ref_cnt++) {
-		MLX5_ASSERT(!fm->mfts->meter_action);
+	rte_spinlock_lock(&fm->sl);
+	if (fm->mfts->meter_action) {
+		if (fm->shared &&
+		    attr->transfer == fm->transfer &&
+		    attr->ingress == fm->ingress &&
+		    attr->egress == fm->egress)
+			fm->ref_cnt++;
+		else
+			ret = -1;
+	} else {
 		fm->ingress = attr->ingress;
 		fm->egress = attr->egress;
 		fm->transfer = attr->transfer;
+		 fm->ref_cnt = 1;
 		/* This also creates the meter object. */
 		fm->mfts->meter_action = mlx5_flow_meter_action_create(priv,
 								       fm);
-		if (!fm->mfts->meter_action)
-			goto error_detach;
-	} else {
-		MLX5_ASSERT(fm->mfts->meter_action);
-		if (attr->transfer != fm->transfer ||
-		    attr->ingress != fm->ingress ||
-		    attr->egress != fm->egress) {
-			DRV_LOG(ERR, "meter I/O attributes do not "
-				"match flow I/O attributes.");
-			goto error_detach;
+		if (!fm->mfts->meter_action) {
+			fm->ref_cnt = 0;
+			fm->ingress = 0;
+			fm->egress = 0;
+			fm->transfer = 0;
+			ret = -1;
+			DRV_LOG(ERR, "meter action create failed.");
 		}
 	}
-	return fm;
-error_detach:
-	mlx5_flow_meter_detach(fm);
-	rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-			  fm->mfts->meter_action ? "Meter attr not match" :
-			  "Meter action create failed");
-error:
-	return NULL;
+	rte_spinlock_unlock(&fm->sl);
+	if (ret)
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   fm->mfts->meter_action ?
+				   "Meter attr not match" :
+				   "Meter action create failed");
+	return ret ? NULL : fm;
 }
 
 /**
@@ -1222,15 +1223,16 @@  struct mlx5_flow_meter *
 mlx5_flow_meter_detach(struct mlx5_flow_meter *fm)
 {
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
+	rte_spinlock_lock(&fm->sl);
 	MLX5_ASSERT(fm->ref_cnt);
-	if (--fm->ref_cnt)
-		return;
-	if (fm->mfts->meter_action)
+	if (--fm->ref_cnt == 0) {
 		mlx5_glue->destroy_flow_action(fm->mfts->meter_action);
-	fm->mfts->meter_action = NULL;
-	fm->ingress = 0;
-	fm->egress = 0;
-	fm->transfer = 0;
+		fm->mfts->meter_action = NULL;
+		fm->ingress = 0;
+		fm->egress = 0;
+		fm->transfer = 0;
+	}
+	rte_spinlock_unlock(&fm->sl);
 #else
 	(void)fm;
 #endif