On Tue, Jul 30, 2019 at 12:16 PM Willem de Bruijn <willemdebruijn.ker...@gmail.com> wrote: > > On Mon, Jul 29, 2019 at 7:50 PM Saeed Mahameed <sae...@mellanox.com> wrote: > > > > From: Vlad Buslov <vla...@mellanox.com> > > > > In order to remove dependency on rtnl lock, access to tc flows hashtable > > must be explicitly protected from concurrent flows removal. > > > > Extend tc flow structure with rcu to allow concurrent parallel access. Use > > rcu read lock to safely lookup flow in tc flows hash table, and take > > reference to it. Use rcu free for flow deletion to accommodate concurrent > > stats requests. > > > > Add new DELETED flow flag. Imlement new flow_flag_test_and_set() helper > > that is used to set a flag and return its previous value. Use it to > > atomically set the flag in mlx5e_delete_flower() to guarantee that flow can > > only be deleted once, even when same flow is deleted concurrently by > > multiple tasks. > > > > Signed-off-by: Vlad Buslov <vla...@mellanox.com> > > Reviewed-by: Jianbo Liu <jian...@mellanox.com> > > Reviewed-by: Roi Dayan <r...@mellanox.com> > > Signed-off-by: Saeed Mahameed <sae...@mellanox.com> > > --- > > > @@ -3492,16 +3507,32 @@ int mlx5e_delete_flower(struct net_device *dev, > > struct mlx5e_priv *priv, > > { > > struct rhashtable *tc_ht = get_tc_ht(priv, flags); > > struct mlx5e_tc_flow *flow; > > + int err; > > > > + rcu_read_lock(); > > flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params); > > - if (!flow || !same_flow_direction(flow, flags)) > > - return -EINVAL; > > + if (!flow || !same_flow_direction(flow, flags)) { > > + err = -EINVAL; > > + goto errout; > > + } > > > > + /* Only delete the flow if it doesn't have MLX5E_TC_FLOW_DELETED > > flag > > + * set. > > + */ > > + if (flow_flag_test_and_set(flow, DELETED)) { > > + err = -EINVAL; > > + goto errout; > > + } > > rhashtable_remove_fast(tc_ht, &flow->node, tc_ht_params); > > + rcu_read_unlock(); > > > > mlx5e_flow_put(priv, flow); > > Dereferencing flow outside rcu readside critical section? Does a build > with lockdep not complain?
Eh no, it won't. The surprising part to me was to use a readside critical section when performing a write action on an RCU ptr. The DELETED flag ensures that multiple writers will not compete to call rhashtable_remove_fast. rcu_read_lock is a common pattern to do rhashtable lookup + delete. > > > > > return 0; > > + > > +errout: > > + rcu_read_unlock(); > > + return err; > > } > > > > int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv, > > @@ -3517,8 +3548,10 @@ int mlx5e_stats_flower(struct net_device *dev, > > struct mlx5e_priv *priv, > > u64 bytes = 0; > > int err = 0; > > > > - flow = mlx5e_flow_get(rhashtable_lookup_fast(tc_ht, &f->cookie, > > - tc_ht_params)); > > + rcu_read_lock(); > > + flow = mlx5e_flow_get(rhashtable_lookup(tc_ht, &f->cookie, > > + tc_ht_params)); > > + rcu_read_unlock(); > > if (IS_ERR(flow)) > > return PTR_ERR(flow); > > Same, in code below this check? Never mind, sorry. I missed that this took a reference on the ptr returned from rhashtable_lookup.