Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad9421e3 authored by Roi Dayan's avatar Roi Dayan Committed by Saeed Mahameed
Browse files

net/mlx5: Fix possible deadlock from lockdep when adding fte to fg



This is a false positive report due to incorrect nested lock
annotations as we lock multiple fgs with the same subclass.
Instead of locking all fgs only lock the one being used as was
done before.

Fixes: bd71b08e ("net/mlx5: Support multiple updates of steering rules in parallel")
Signed-off-by: default avatarRoi Dayan <roid@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent fc433829
Loading
Loading
Loading
Loading
+37 −37
Original line number Diff line number Diff line
@@ -1578,6 +1578,33 @@ static u64 matched_fgs_get_version(struct list_head *match_head)
	return version;
}

static struct fs_fte *
lookup_fte_locked(struct mlx5_flow_group *g,
		  u32 *match_value,
		  bool take_write)
{
	struct fs_fte *fte_tmp;

	if (take_write)
		nested_down_write_ref_node(&g->node, FS_LOCK_PARENT);
	else
		nested_down_read_ref_node(&g->node, FS_LOCK_PARENT);
	fte_tmp = rhashtable_lookup_fast(&g->ftes_hash, match_value,
					 rhash_fte);
	if (!fte_tmp || !tree_get_node(&fte_tmp->node)) {
		fte_tmp = NULL;
		goto out;
	}

	nested_down_write_ref_node(&fte_tmp->node, FS_LOCK_CHILD);
out:
	if (take_write)
		up_write_ref_node(&g->node);
	else
		up_read_ref_node(&g->node);
	return fte_tmp;
}

static struct mlx5_flow_handle *
try_add_to_existing_fg(struct mlx5_flow_table *ft,
		       struct list_head *match_head,
@@ -1600,10 +1627,6 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft,
	if (IS_ERR(fte))
		return  ERR_PTR(-ENOMEM);

	list_for_each_entry(iter, match_head, list) {
		nested_down_read_ref_node(&iter->g->node, FS_LOCK_PARENT);
	}

search_again_locked:
	version = matched_fgs_get_version(match_head);
	/* Try to find a fg that already contains a matching fte */
@@ -1611,20 +1634,9 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft,
		struct fs_fte *fte_tmp;

		g = iter->g;
		fte_tmp = rhashtable_lookup_fast(&g->ftes_hash, spec->match_value,
						 rhash_fte);
		if (!fte_tmp || !tree_get_node(&fte_tmp->node))
		fte_tmp = lookup_fte_locked(g, spec->match_value, take_write);
		if (!fte_tmp)
			continue;

		nested_down_write_ref_node(&fte_tmp->node, FS_LOCK_CHILD);
		if (!take_write) {
			list_for_each_entry(iter, match_head, list)
				up_read_ref_node(&iter->g->node);
		} else {
			list_for_each_entry(iter, match_head, list)
				up_write_ref_node(&iter->g->node);
		}

		rule = add_rule_fg(g, spec->match_value,
				   flow_act, dest, dest_num, fte_tmp);
		up_write_ref_node(&fte_tmp->node);
@@ -1633,19 +1645,6 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft,
		return rule;
	}

	/* No group with matching fte found. Try to add a new fte to any
	 * matching fg.
	 */

	if (!take_write) {
		list_for_each_entry(iter, match_head, list)
			up_read_ref_node(&iter->g->node);
		list_for_each_entry(iter, match_head, list)
			nested_down_write_ref_node(&iter->g->node,
						   FS_LOCK_PARENT);
		take_write = true;
	}

	/* Check the ft version, for case that new flow group
	 * was added while the fgs weren't locked
	 */
@@ -1657,27 +1656,30 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft,
	/* Check the fgs version, for case the new FTE with the
	 * same values was added while the fgs weren't locked
	 */
	if (version != matched_fgs_get_version(match_head))
	if (version != matched_fgs_get_version(match_head)) {
		take_write = true;
		goto search_again_locked;
	}

	list_for_each_entry(iter, match_head, list) {
		g = iter->g;

		if (!g->node.active)
			continue;

		nested_down_write_ref_node(&g->node, FS_LOCK_PARENT);

		err = insert_fte(g, fte);
		if (err) {
			up_write_ref_node(&g->node);
			if (err == -ENOSPC)
				continue;
			list_for_each_entry(iter, match_head, list)
				up_write_ref_node(&iter->g->node);
			kmem_cache_free(steering->ftes_cache, fte);
			return ERR_PTR(err);
		}

		nested_down_write_ref_node(&fte->node, FS_LOCK_CHILD);
		list_for_each_entry(iter, match_head, list)
			up_write_ref_node(&iter->g->node);
		up_write_ref_node(&g->node);
		rule = add_rule_fg(g, spec->match_value,
				   flow_act, dest, dest_num, fte);
		up_write_ref_node(&fte->node);
@@ -1686,8 +1688,6 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft,
	}
	rule = ERR_PTR(-ENOENT);
out:
	list_for_each_entry(iter, match_head, list)
		up_write_ref_node(&iter->g->node);
	kmem_cache_free(steering->ftes_cache, fte);
	return rule;
}