net/mlx5: DR, Fix potential race in dr_rule_create_rule_nic
authorYevgeny Kliteynik <kliteyn@nvidia.com>
Tue, 17 Jan 2023 15:34:20 +0000 (17:34 +0200)
committerSaeed Mahameed <saeedm@nvidia.com>
Wed, 8 Feb 2023 03:01:04 +0000 (19:01 -0800)
Selecting builder should be protected by the lock to prevent the case
where a new rule sets a builder in the nic_matcher while the previous
rule is still using the nic_matcher.

Fixing this issue and cleaning the error flow.

Fixes: b9b81e1e9382 ("net/mlx5: DR, For short chains of STEs, avoid allocating ste_arr dynamically")
Signed-off-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Alex Vesker <valex@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c

index b851141e03de3c67e1f422460d1d5cc571356066..042ca0349124332ab875d11b9c8112b9b1173de4 100644 (file)
@@ -1138,12 +1138,14 @@ dr_rule_create_rule_nic(struct mlx5dr_rule *rule,
                         rule->flow_source))
                return 0;
 
+       mlx5dr_domain_nic_lock(nic_dmn);
+
        ret = mlx5dr_matcher_select_builders(matcher,
                                             nic_matcher,
                                             dr_rule_get_ipv(&param->outer),
                                             dr_rule_get_ipv(&param->inner));
        if (ret)
-               return ret;
+               goto err_unlock;
 
        hw_ste_arr_is_opt = nic_matcher->num_of_builders <= DR_RULE_MAX_STES_OPTIMIZED;
        if (likely(hw_ste_arr_is_opt)) {
@@ -1152,12 +1154,12 @@ dr_rule_create_rule_nic(struct mlx5dr_rule *rule,
                hw_ste_arr = kzalloc((nic_matcher->num_of_builders + DR_ACTION_MAX_STES) *
                                     DR_STE_SIZE, GFP_KERNEL);
 
-               if (!hw_ste_arr)
-                       return -ENOMEM;
+               if (!hw_ste_arr) {
+                       ret = -ENOMEM;
+                       goto err_unlock;
+               }
        }
 
-       mlx5dr_domain_nic_lock(nic_dmn);
-
        ret = mlx5dr_matcher_add_to_tbl_nic(dmn, nic_matcher);
        if (ret)
                goto free_hw_ste;
@@ -1223,7 +1225,10 @@ dr_rule_create_rule_nic(struct mlx5dr_rule *rule,
 
        mlx5dr_domain_nic_unlock(nic_dmn);
 
-       goto out;
+       if (unlikely(!hw_ste_arr_is_opt))
+               kfree(hw_ste_arr);
+
+       return 0;
 
 free_rule:
        dr_rule_clean_rule_members(rule, nic_rule);
@@ -1238,12 +1243,12 @@ remove_from_nic_tbl:
                mlx5dr_matcher_remove_from_tbl_nic(dmn, nic_matcher);
 
 free_hw_ste:
-       mlx5dr_domain_nic_unlock(nic_dmn);
-
-out:
-       if (unlikely(!hw_ste_arr_is_opt))
+       if (!hw_ste_arr_is_opt)
                kfree(hw_ste_arr);
 
+err_unlock:
+       mlx5dr_domain_nic_unlock(nic_dmn);
+
        return ret;
 }