Commit e474619a authored by Vlad Buslov's avatar Vlad Buslov Committed by David S. Miller

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: default avatarVlad Buslov <vladbu@mellanox.com>
Reviewed-by: default avatarStefano Brivio <sbrivio@redhat.com>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 31f1a0e3
...@@ -437,10 +437,20 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f) ...@@ -437,10 +437,20 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
cls_flower.stats.lastused); 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, static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
struct netlink_ext_ack *extack) 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 async = tcf_exts_get_net(&f->exts);
bool last; bool last;
...@@ -472,7 +482,7 @@ static void fl_destroy_sleepable(struct work_struct *work) ...@@ -472,7 +482,7 @@ static void fl_destroy_sleepable(struct work_struct *work)
static void fl_destroy(struct tcf_proto *tp, bool rtnl_held, static void fl_destroy(struct tcf_proto *tp, bool rtnl_held,
struct netlink_ext_ack *extack) 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 fl_flow_mask *mask, *next_mask;
struct cls_fl_filter *f, *next; struct cls_fl_filter *f, *next;
...@@ -490,7 +500,7 @@ static void fl_destroy(struct tcf_proto *tp, bool rtnl_held, ...@@ -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) 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); return idr_find(&head->handle_idr, handle);
} }
...@@ -1308,7 +1318,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, ...@@ -1308,7 +1318,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
void **arg, bool ovr, bool rtnl_held, void **arg, bool ovr, bool rtnl_held,
struct netlink_ext_ack *extack) 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 *fold = *arg;
struct cls_fl_filter *fnew; struct cls_fl_filter *fnew;
struct fl_flow_mask *mask; struct fl_flow_mask *mask;
...@@ -1446,7 +1456,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, ...@@ -1446,7 +1456,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
static int fl_delete(struct tcf_proto *tp, void *arg, bool *last, static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
bool rtnl_held, struct netlink_ext_ack *extack) 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; struct cls_fl_filter *f = arg;
rhashtable_remove_fast(&f->mask->ht, &f->ht_node, 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, ...@@ -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, static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg,
bool rtnl_held) 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; struct cls_fl_filter *f;
arg->count = arg->skip; arg->count = arg->skip;
...@@ -1478,7 +1488,7 @@ static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg, ...@@ -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, static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
void *cb_priv, struct netlink_ext_ack *extack) 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 tc_cls_flower_offload cls_flower = {};
struct tcf_block *block = tp->chain->block; struct tcf_block *block = tp->chain->block;
struct fl_flow_mask *mask; struct fl_flow_mask *mask;
......
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