diff options
author | Cong Wang <xiyou.wangcong@gmail.com> | 2017-11-06 16:47:30 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-11-08 20:03:10 -0500 |
commit | 35c55fc156d85a396a975fc17636f560fc02fd65 (patch) | |
tree | 4600cfecab2372a77cfb9143e4b24b059d24433a | |
parent | f2b751053ee9314e82c178f6ca0fee7e160fac95 (diff) |
cls_u32: use tcf_exts_get_net() before call_rcu()
Hold netns refcnt before call_rcu() and release it after
the tcf_exts_destroy() is done.
Note, on ->destroy() path we have to respect the return value
of tcf_exts_get_net(), on other paths it should always return
true, so we don't need to care.
Cc: Lucas Bates <lucasb@mojatatu.com>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/sched/cls_u32.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index dadd1b344497..b58eccb21f03 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c | |||
@@ -399,6 +399,7 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n, | |||
399 | bool free_pf) | 399 | bool free_pf) |
400 | { | 400 | { |
401 | tcf_exts_destroy(&n->exts); | 401 | tcf_exts_destroy(&n->exts); |
402 | tcf_exts_put_net(&n->exts); | ||
402 | if (n->ht_down) | 403 | if (n->ht_down) |
403 | n->ht_down->refcnt--; | 404 | n->ht_down->refcnt--; |
404 | #ifdef CONFIG_CLS_U32_PERF | 405 | #ifdef CONFIG_CLS_U32_PERF |
@@ -476,6 +477,7 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) | |||
476 | RCU_INIT_POINTER(*kp, key->next); | 477 | RCU_INIT_POINTER(*kp, key->next); |
477 | 478 | ||
478 | tcf_unbind_filter(tp, &key->res); | 479 | tcf_unbind_filter(tp, &key->res); |
480 | tcf_exts_get_net(&key->exts); | ||
479 | call_rcu(&key->rcu, u32_delete_key_freepf_rcu); | 481 | call_rcu(&key->rcu, u32_delete_key_freepf_rcu); |
480 | return 0; | 482 | return 0; |
481 | } | 483 | } |
@@ -588,7 +590,10 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht) | |||
588 | rtnl_dereference(n->next)); | 590 | rtnl_dereference(n->next)); |
589 | tcf_unbind_filter(tp, &n->res); | 591 | tcf_unbind_filter(tp, &n->res); |
590 | u32_remove_hw_knode(tp, n->handle); | 592 | u32_remove_hw_knode(tp, n->handle); |
591 | call_rcu(&n->rcu, u32_delete_key_freepf_rcu); | 593 | if (tcf_exts_get_net(&n->exts)) |
594 | call_rcu(&n->rcu, u32_delete_key_freepf_rcu); | ||
595 | else | ||
596 | u32_destroy_key(n->tp, n, true); | ||
592 | } | 597 | } |
593 | } | 598 | } |
594 | } | 599 | } |
@@ -949,6 +954,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, | |||
949 | 954 | ||
950 | u32_replace_knode(tp, tp_c, new); | 955 | u32_replace_knode(tp, tp_c, new); |
951 | tcf_unbind_filter(tp, &n->res); | 956 | tcf_unbind_filter(tp, &n->res); |
957 | tcf_exts_get_net(&n->exts); | ||
952 | call_rcu(&n->rcu, u32_delete_key_rcu); | 958 | call_rcu(&n->rcu, u32_delete_key_rcu); |
953 | return 0; | 959 | return 0; |
954 | } | 960 | } |