Commit 61086f39 authored by Vlad Buslov's avatar Vlad Buslov Committed by Saeed Mahameed

net/mlx5e: Protect encap hash table with mutex

To remove dependency on rtnl lock, protect encap hash table from concurrent
modifications with new "encap_tbl_lock" mutex. Use the mutex to protect
internal encap entry state from concurrent modification. This is necessary
because a flow can be attached to multiple encap entries simultaneously,
which significantly complicates using finer grained per-entry lock.
Signed-off-by: default avatarVlad Buslov <vladbu@mellanox.com>
Reviewed-by: default avatarRoi Dayan <roid@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent 948993f2
...@@ -1478,33 +1478,51 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe) ...@@ -1478,33 +1478,51 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
} }
} }
void mlx5e_encap_put(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e) static void mlx5e_encap_dealloc(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e)
{ {
if (!refcount_dec_and_test(&e->refcnt))
return;
WARN_ON(!list_empty(&e->flows)); WARN_ON(!list_empty(&e->flows));
mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e);
if (e->flags & MLX5_ENCAP_ENTRY_VALID) if (e->flags & MLX5_ENCAP_ENTRY_VALID)
mlx5_packet_reformat_dealloc(priv->mdev, e->encap_id); mlx5_packet_reformat_dealloc(priv->mdev, e->encap_id);
hash_del_rcu(&e->encap_hlist);
kfree(e->encap_header); kfree(e->encap_header);
kfree(e); kfree(e);
} }
void mlx5e_encap_put(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
if (!refcount_dec_and_mutex_lock(&e->refcnt, &esw->offloads.encap_tbl_lock))
return;
hash_del_rcu(&e->encap_hlist);
mutex_unlock(&esw->offloads.encap_tbl_lock);
mlx5e_encap_dealloc(priv, e);
}
static void mlx5e_detach_encap(struct mlx5e_priv *priv, static void mlx5e_detach_encap(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow, int out_index) struct mlx5e_tc_flow *flow, int out_index)
{ {
struct mlx5e_encap_entry *e = flow->encaps[out_index].e;
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
/* flow wasn't fully initialized */ /* flow wasn't fully initialized */
if (!flow->encaps[out_index].e) if (!e)
return; return;
mutex_lock(&esw->offloads.encap_tbl_lock);
list_del(&flow->encaps[out_index].list); list_del(&flow->encaps[out_index].list);
mlx5e_encap_put(priv, flow->encaps[out_index].e);
flow->encaps[out_index].e = NULL; flow->encaps[out_index].e = NULL;
if (!refcount_dec_and_test(&e->refcnt)) {
mutex_unlock(&esw->offloads.encap_tbl_lock);
return;
}
hash_del_rcu(&e->encap_hlist);
mutex_unlock(&esw->offloads.encap_tbl_lock);
mlx5e_encap_dealloc(priv, e);
} }
static void __mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow) static void __mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow)
...@@ -2882,6 +2900,7 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv, ...@@ -2882,6 +2900,7 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
hash_key = hash_encap_info(&key); hash_key = hash_encap_info(&key);
mutex_lock(&esw->offloads.encap_tbl_lock);
e = mlx5e_encap_get(priv, &key, hash_key); e = mlx5e_encap_get(priv, &key, hash_key);
/* must verify if encap is valid or not */ /* must verify if encap is valid or not */
...@@ -2889,8 +2908,10 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv, ...@@ -2889,8 +2908,10 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
goto attach_flow; goto attach_flow;
e = kzalloc(sizeof(*e), GFP_KERNEL); e = kzalloc(sizeof(*e), GFP_KERNEL);
if (!e) if (!e) {
return -ENOMEM; err = -ENOMEM;
goto out_err;
}
refcount_set(&e->refcnt, 1); refcount_set(&e->refcnt, 1);
e->tun_info = tun_info; e->tun_info = tun_info;
...@@ -2922,10 +2943,12 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv, ...@@ -2922,10 +2943,12 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
} else { } else {
*encap_valid = false; *encap_valid = false;
} }
mutex_unlock(&esw->offloads.encap_tbl_lock);
return err; return err;
out_err: out_err:
mutex_unlock(&esw->offloads.encap_tbl_lock);
kfree(e); kfree(e);
return err; return err;
} }
......
...@@ -1999,6 +1999,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) ...@@ -1999,6 +1999,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
if (err) if (err)
goto abort; goto abort;
mutex_init(&esw->offloads.encap_tbl_lock);
hash_init(esw->offloads.encap_tbl); hash_init(esw->offloads.encap_tbl);
mutex_init(&esw->offloads.mod_hdr.lock); mutex_init(&esw->offloads.mod_hdr.lock);
hash_init(esw->offloads.mod_hdr.hlist); hash_init(esw->offloads.mod_hdr.hlist);
...@@ -2039,6 +2040,7 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) ...@@ -2039,6 +2040,7 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
destroy_workqueue(esw->work_queue); destroy_workqueue(esw->work_queue);
esw_offloads_cleanup_reps(esw); esw_offloads_cleanup_reps(esw);
mutex_destroy(&esw->offloads.mod_hdr.lock); mutex_destroy(&esw->offloads.mod_hdr.lock);
mutex_destroy(&esw->offloads.encap_tbl_lock);
kfree(esw->vports); kfree(esw->vports);
kfree(esw); kfree(esw);
} }
......
...@@ -181,6 +181,7 @@ struct mlx5_esw_offload { ...@@ -181,6 +181,7 @@ struct mlx5_esw_offload {
struct mlx5_eswitch_rep *vport_reps; struct mlx5_eswitch_rep *vport_reps;
struct list_head peer_flows; struct list_head peer_flows;
struct mutex peer_mutex; struct mutex peer_mutex;
struct mutex encap_tbl_lock; /* protects encap_tbl */
DECLARE_HASHTABLE(encap_tbl, 8); DECLARE_HASHTABLE(encap_tbl, 8);
struct mod_hdr_tbl mod_hdr; struct mod_hdr_tbl mod_hdr;
DECLARE_HASHTABLE(termtbl_tbl, 8); DECLARE_HASHTABLE(termtbl_tbl, 8);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment