From d2faae25c3050a87c8ff965a7939e999e3154b62 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Fri, 9 Aug 2019 13:20:48 +0300 Subject: [PATCH] net/mlx5e: Protect mod_hdr hash table with mutex To remove dependency on rtnl lock, protect mod_hdr hash table from concurrent modifications with new mutex. Implement helper function to get flow namespace to prevent code duplication. Signed-off-by: Vlad Buslov Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_tc.c | 35 +++++++++++++------ .../net/ethernet/mellanox/mlx5/core/eswitch.c | 2 ++ include/linux/mlx5/fs.h | 1 + 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 09d5cc700297..0600b7878600 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -315,22 +315,31 @@ mlx5e_mod_hdr_get(struct mod_hdr_tbl *tbl, struct mod_hdr_key *key, u32 hash_key } static void mlx5e_mod_hdr_put(struct mlx5e_priv *priv, - struct mlx5e_mod_hdr_entry *mh) + struct mlx5e_mod_hdr_entry *mh, + int namespace) { - if (!refcount_dec_and_test(&mh->refcnt)) + struct mod_hdr_tbl *tbl = get_mod_hdr_table(priv, namespace); + + if (!refcount_dec_and_mutex_lock(&mh->refcnt, &tbl->lock)) return; + hash_del(&mh->mod_hdr_hlist); + mutex_unlock(&tbl->lock); WARN_ON(!list_empty(&mh->flows)); mlx5_modify_header_dealloc(priv->mdev, mh->mod_hdr_id); - hash_del(&mh->mod_hdr_hlist); + kfree(mh); } +static int get_flow_name_space(struct mlx5e_tc_flow *flow) +{ + return mlx5e_is_eswitch_flow(flow) ? + MLX5_FLOW_NAMESPACE_FDB : MLX5_FLOW_NAMESPACE_KERNEL; +} static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow, struct mlx5e_tc_flow_parse_attr *parse_attr) { - bool is_eswitch_flow = mlx5e_is_eswitch_flow(flow); int num_actions, actions_size, namespace, err; struct mlx5e_mod_hdr_entry *mh; struct mod_hdr_tbl *tbl; @@ -345,17 +354,19 @@ static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv, hash_key = hash_mod_hdr_info(&key); - namespace = is_eswitch_flow ? - MLX5_FLOW_NAMESPACE_FDB : MLX5_FLOW_NAMESPACE_KERNEL; + namespace = get_flow_name_space(flow); tbl = get_mod_hdr_table(priv, namespace); + mutex_lock(&tbl->lock); mh = mlx5e_mod_hdr_get(tbl, &key, hash_key); if (mh) goto attach_flow; mh = kzalloc(sizeof(*mh) + actions_size, GFP_KERNEL); - if (!mh) - return -ENOMEM; + if (!mh) { + err = -ENOMEM; + goto out_err; + } mh->key.actions = (void *)mh + sizeof(*mh); memcpy(mh->key.actions, key.actions, actions_size); @@ -374,11 +385,12 @@ static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv, hash_add(tbl->hlist, &mh->mod_hdr_hlist, hash_key); attach_flow: + mutex_unlock(&tbl->lock); flow->mh = mh; spin_lock(&mh->flows_lock); list_add(&flow->mod_hdr, &mh->flows); spin_unlock(&mh->flows_lock); - if (is_eswitch_flow) + if (mlx5e_is_eswitch_flow(flow)) flow->esw_attr->mod_hdr_id = mh->mod_hdr_id; else flow->nic_attr->mod_hdr_id = mh->mod_hdr_id; @@ -386,6 +398,7 @@ attach_flow: return 0; out_err: + mutex_unlock(&tbl->lock); kfree(mh); return err; } @@ -401,7 +414,7 @@ static void mlx5e_detach_mod_hdr(struct mlx5e_priv *priv, list_del(&flow->mod_hdr); spin_unlock(&flow->mh->flows_lock); - mlx5e_mod_hdr_put(priv, flow->mh); + mlx5e_mod_hdr_put(priv, flow->mh, get_flow_name_space(flow)); flow->mh = NULL; } @@ -3865,6 +3878,7 @@ int mlx5e_tc_nic_init(struct mlx5e_priv *priv) int err; mutex_init(&tc->t_lock); + mutex_init(&tc->mod_hdr.lock); hash_init(tc->mod_hdr.hlist); mutex_init(&tc->hairpin_tbl_lock); hash_init(tc->hairpin_tbl); @@ -3898,6 +3912,7 @@ void mlx5e_tc_nic_cleanup(struct mlx5e_priv *priv) if (tc->netdevice_nb.notifier_call) unregister_netdevice_notifier(&tc->netdevice_nb); + mutex_destroy(&tc->mod_hdr.lock); mutex_destroy(&tc->hairpin_tbl_lock); rhashtable_destroy(&tc->ht); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 5ce3c81e3083..2d734ecae719 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -2000,6 +2000,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) goto abort; hash_init(esw->offloads.encap_tbl); + mutex_init(&esw->offloads.mod_hdr.lock); hash_init(esw->offloads.mod_hdr.hlist); atomic64_set(&esw->offloads.num_flows, 0); mutex_init(&esw->state_lock); @@ -2037,6 +2038,7 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) esw->dev->priv.eswitch = NULL; destroy_workqueue(esw->work_queue); esw_offloads_cleanup_reps(esw); + mutex_destroy(&esw->offloads.mod_hdr.lock); kfree(esw->vports); kfree(esw); } diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index 96650a33aa91..1cb1045ce313 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -127,6 +127,7 @@ struct mlx5_flow_destination { }; struct mod_hdr_tbl { + struct mutex lock; /* protects hlist */ DECLARE_HASHTABLE(hlist, 8); }; -- 2.30.2