aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCong Wang <xiyou.wangcong@gmail.com>2017-11-06 16:47:30 -0500
committerDavid S. Miller <davem@davemloft.net>2017-11-08 20:03:10 -0500
commit35c55fc156d85a396a975fc17636f560fc02fd65 (patch)
tree4600cfecab2372a77cfb9143e4b24b059d24433a
parentf2b751053ee9314e82c178f6ca0fee7e160fac95 (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.c8
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 }