net/mlx5e: Protect mod_hdr hash table with mutex
authorVlad Buslov <vladbu@mellanox.com>
Fri, 9 Aug 2019 10:20:48 +0000 (13:20 +0300)
committerSaeed Mahameed <saeedm@mellanox.com>
Fri, 9 Aug 2019 21:54:09 +0000 (14:54 -0700)
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 <vladbu@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
include/linux/mlx5/fs.h

index 09d5cc7002975b50dd06078ddccc742c9cb73a14..0600b787860091680054539ce5f4e36af6d08a03 100644 (file)
@@ -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);
index 5ce3c81e308341b076922da93aec0f3d8906d75c..2d734ecae71967cc7f5f22c095e7eca900218880 100644 (file)
@@ -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);
 }
index 96650a33aa919392c5ae48ce7d2b1cd9f0ba256a..1cb1045ce313dd2192a91b841bfd559a12aae4e2 100644 (file)
@@ -127,6 +127,7 @@ struct mlx5_flow_destination {
 };
 
 struct mod_hdr_tbl {
+       struct mutex lock; /* protects hlist */
        DECLARE_HASHTABLE(hlist, 8);
 };