diff options
Diffstat (limited to 'net/sched/act_police.c')
-rw-r--r-- | net/sched/act_police.c | 33 |
1 files changed, 20 insertions, 13 deletions
diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 654f73dff7c1..7ebf7439b478 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c | |||
@@ -97,6 +97,11 @@ nla_put_failure: | |||
97 | goto done; | 97 | goto done; |
98 | } | 98 | } |
99 | 99 | ||
100 | static void tcf_police_free_rcu(struct rcu_head *head) | ||
101 | { | ||
102 | kfree(container_of(head, struct tcf_police, tcf_rcu)); | ||
103 | } | ||
104 | |||
100 | static void tcf_police_destroy(struct tcf_police *p) | 105 | static void tcf_police_destroy(struct tcf_police *p) |
101 | { | 106 | { |
102 | unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); | 107 | unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); |
@@ -113,7 +118,11 @@ static void tcf_police_destroy(struct tcf_police *p) | |||
113 | qdisc_put_rtab(p->tcfp_R_tab); | 118 | qdisc_put_rtab(p->tcfp_R_tab); |
114 | if (p->tcfp_P_tab) | 119 | if (p->tcfp_P_tab) |
115 | qdisc_put_rtab(p->tcfp_P_tab); | 120 | qdisc_put_rtab(p->tcfp_P_tab); |
116 | kfree(p); | 121 | /* |
122 | * gen_estimator est_timer() might access p->tcf_lock | ||
123 | * or bstats, wait a RCU grace period before freeing p | ||
124 | */ | ||
125 | call_rcu(&p->tcf_rcu, tcf_police_free_rcu); | ||
117 | return; | 126 | return; |
118 | } | 127 | } |
119 | } | 128 | } |
@@ -341,22 +350,19 @@ tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | |||
341 | { | 350 | { |
342 | unsigned char *b = skb_tail_pointer(skb); | 351 | unsigned char *b = skb_tail_pointer(skb); |
343 | struct tcf_police *police = a->priv; | 352 | struct tcf_police *police = a->priv; |
344 | struct tc_police opt; | 353 | struct tc_police opt = { |
345 | 354 | .index = police->tcf_index, | |
346 | opt.index = police->tcf_index; | 355 | .action = police->tcf_action, |
347 | opt.action = police->tcf_action; | 356 | .mtu = police->tcfp_mtu, |
348 | opt.mtu = police->tcfp_mtu; | 357 | .burst = police->tcfp_burst, |
349 | opt.burst = police->tcfp_burst; | 358 | .refcnt = police->tcf_refcnt - ref, |
350 | opt.refcnt = police->tcf_refcnt - ref; | 359 | .bindcnt = police->tcf_bindcnt - bind, |
351 | opt.bindcnt = police->tcf_bindcnt - bind; | 360 | }; |
361 | |||
352 | if (police->tcfp_R_tab) | 362 | if (police->tcfp_R_tab) |
353 | opt.rate = police->tcfp_R_tab->rate; | 363 | opt.rate = police->tcfp_R_tab->rate; |
354 | else | ||
355 | memset(&opt.rate, 0, sizeof(opt.rate)); | ||
356 | if (police->tcfp_P_tab) | 364 | if (police->tcfp_P_tab) |
357 | opt.peakrate = police->tcfp_P_tab->rate; | 365 | opt.peakrate = police->tcfp_P_tab->rate; |
358 | else | ||
359 | memset(&opt.peakrate, 0, sizeof(opt.peakrate)); | ||
360 | NLA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); | 366 | NLA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); |
361 | if (police->tcfp_result) | 367 | if (police->tcfp_result) |
362 | NLA_PUT_U32(skb, TCA_POLICE_RESULT, police->tcfp_result); | 368 | NLA_PUT_U32(skb, TCA_POLICE_RESULT, police->tcfp_result); |
@@ -397,6 +403,7 @@ static void __exit | |||
397 | police_cleanup_module(void) | 403 | police_cleanup_module(void) |
398 | { | 404 | { |
399 | tcf_unregister_action(&act_police_ops); | 405 | tcf_unregister_action(&act_police_ops); |
406 | rcu_barrier(); /* Wait for completion of call_rcu()'s (tcf_police_free_rcu) */ | ||
400 | } | 407 | } |
401 | 408 | ||
402 | module_init(police_init_module); | 409 | module_init(police_init_module); |