aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/act_police.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/act_police.c')
-rw-r--r--net/sched/act_police.c33
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
100static void tcf_police_free_rcu(struct rcu_head *head)
101{
102 kfree(container_of(head, struct tcf_police, tcf_rcu));
103}
104
100static void tcf_police_destroy(struct tcf_police *p) 105static 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
397police_cleanup_module(void) 403police_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
402module_init(police_init_module); 409module_init(police_init_module);