net: sched: flower: don't check for rtnl on head dereference
Flower classifier only changes root pointer during init and destroy. Cls API implements reference counting for tcf_proto, so there is no danger of concurrent access to tp when it is being destroyed, even without protection provided by rtnl lock. Implement new function fl_head_dereference() to dereference tp->root without checking for rtnl lock. Use it in all flower function that obtain head pointer instead of rtnl_dereference(). Signed-off-by: Vlad Buslov <vladbu@mellanox.com> Reviewed-by: Stefano Brivio <sbrivio@redhat.com> Acked-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
31f1a0e37c
commit
e474619a24
|
@ -437,10 +437,20 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
|
|||
cls_flower.stats.lastused);
|
||||
}
|
||||
|
||||
static struct cls_fl_head *fl_head_dereference(struct tcf_proto *tp)
|
||||
{
|
||||
/* Flower classifier only changes root pointer during init and destroy.
|
||||
* Users must obtain reference to tcf_proto instance before calling its
|
||||
* API, so tp->root pointer is protected from concurrent call to
|
||||
* fl_destroy() by reference counting.
|
||||
*/
|
||||
return rcu_dereference_raw(tp->root);
|
||||
}
|
||||
|
||||
static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct cls_fl_head *head = rtnl_dereference(tp->root);
|
||||
struct cls_fl_head *head = fl_head_dereference(tp);
|
||||
bool async = tcf_exts_get_net(&f->exts);
|
||||
bool last;
|
||||
|
||||
|
@ -472,7 +482,7 @@ static void fl_destroy_sleepable(struct work_struct *work)
|
|||
static void fl_destroy(struct tcf_proto *tp, bool rtnl_held,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct cls_fl_head *head = rtnl_dereference(tp->root);
|
||||
struct cls_fl_head *head = fl_head_dereference(tp);
|
||||
struct fl_flow_mask *mask, *next_mask;
|
||||
struct cls_fl_filter *f, *next;
|
||||
|
||||
|
@ -490,7 +500,7 @@ static void fl_destroy(struct tcf_proto *tp, bool rtnl_held,
|
|||
|
||||
static void *fl_get(struct tcf_proto *tp, u32 handle)
|
||||
{
|
||||
struct cls_fl_head *head = rtnl_dereference(tp->root);
|
||||
struct cls_fl_head *head = fl_head_dereference(tp);
|
||||
|
||||
return idr_find(&head->handle_idr, handle);
|
||||
}
|
||||
|
@ -1308,7 +1318,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
|
|||
void **arg, bool ovr, bool rtnl_held,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct cls_fl_head *head = rtnl_dereference(tp->root);
|
||||
struct cls_fl_head *head = fl_head_dereference(tp);
|
||||
struct cls_fl_filter *fold = *arg;
|
||||
struct cls_fl_filter *fnew;
|
||||
struct fl_flow_mask *mask;
|
||||
|
@ -1446,7 +1456,7 @@ errout_mask_alloc:
|
|||
static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
|
||||
bool rtnl_held, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct cls_fl_head *head = rtnl_dereference(tp->root);
|
||||
struct cls_fl_head *head = fl_head_dereference(tp);
|
||||
struct cls_fl_filter *f = arg;
|
||||
|
||||
rhashtable_remove_fast(&f->mask->ht, &f->ht_node,
|
||||
|
@ -1459,7 +1469,7 @@ static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
|
|||
static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg,
|
||||
bool rtnl_held)
|
||||
{
|
||||
struct cls_fl_head *head = rtnl_dereference(tp->root);
|
||||
struct cls_fl_head *head = fl_head_dereference(tp);
|
||||
struct cls_fl_filter *f;
|
||||
|
||||
arg->count = arg->skip;
|
||||
|
@ -1478,7 +1488,7 @@ static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg,
|
|||
static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
|
||||
void *cb_priv, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct cls_fl_head *head = rtnl_dereference(tp->root);
|
||||
struct cls_fl_head *head = fl_head_dereference(tp);
|
||||
struct tc_cls_flower_offload cls_flower = {};
|
||||
struct tcf_block *block = tp->chain->block;
|
||||
struct fl_flow_mask *mask;
|
||||
|
|
Loading…
Reference in New Issue