aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-06-08 22:09:23 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-11 21:37:08 -0400
commitc7de2cf053420d63bac85133469c965d4b1083e1 (patch)
treeb56f7c96d01e25f79fe1f9b7e5305265e92214d9 /net
parentcbd6890c5987cd7115147e1dd2c10d729afabb08 (diff)
pkt_sched: gen_kill_estimator() rcu fixes
gen_kill_estimator() API is incomplete or not well documented, since caller should make sure an RCU grace period is respected before freeing stats_lock. This was partially addressed in commit 5d944c640b4 (gen_estimator: deadlock fix), but same problem exist for all gen_kill_estimator() users, if lock they use is not already RCU protected. A code review shows xt_RATEEST.c, act_api.c, act_police.c have this problem. Other are ok because they use qdisc lock, already RCU protected. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/gen_estimator.c1
-rw-r--r--net/netfilter/xt_RATEEST.c12
-rw-r--r--net/sched/act_api.c11
-rw-r--r--net/sched/act_police.c12
4 files changed, 33 insertions, 3 deletions
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index 785e5276a300..9fbe7f7429b0 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -263,6 +263,7 @@ static void __gen_kill_estimator(struct rcu_head *head)
263 * 263 *
264 * Removes the rate estimator specified by &bstats and &rate_est. 264 * Removes the rate estimator specified by &bstats and &rate_est.
265 * 265 *
266 * Note : Caller should respect an RCU grace period before freeing stats_lock
266 */ 267 */
267void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, 268void gen_kill_estimator(struct gnet_stats_basic_packed *bstats,
268 struct gnet_stats_rate_est *rate_est) 269 struct gnet_stats_rate_est *rate_est)
diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c
index 69c01e10f8af..de079abd5bc8 100644
--- a/net/netfilter/xt_RATEEST.c
+++ b/net/netfilter/xt_RATEEST.c
@@ -60,13 +60,22 @@ struct xt_rateest *xt_rateest_lookup(const char *name)
60} 60}
61EXPORT_SYMBOL_GPL(xt_rateest_lookup); 61EXPORT_SYMBOL_GPL(xt_rateest_lookup);
62 62
63static void xt_rateest_free_rcu(struct rcu_head *head)
64{
65 kfree(container_of(head, struct xt_rateest, rcu));
66}
67
63void xt_rateest_put(struct xt_rateest *est) 68void xt_rateest_put(struct xt_rateest *est)
64{ 69{
65 mutex_lock(&xt_rateest_mutex); 70 mutex_lock(&xt_rateest_mutex);
66 if (--est->refcnt == 0) { 71 if (--est->refcnt == 0) {
67 hlist_del(&est->list); 72 hlist_del(&est->list);
68 gen_kill_estimator(&est->bstats, &est->rstats); 73 gen_kill_estimator(&est->bstats, &est->rstats);
69 kfree(est); 74 /*
75 * gen_estimator est_timer() might access est->lock or bstats,
76 * wait a RCU grace period before freeing 'est'
77 */
78 call_rcu(&est->rcu, xt_rateest_free_rcu);
70 } 79 }
71 mutex_unlock(&xt_rateest_mutex); 80 mutex_unlock(&xt_rateest_mutex);
72} 81}
@@ -179,6 +188,7 @@ static int __init xt_rateest_tg_init(void)
179static void __exit xt_rateest_tg_fini(void) 188static void __exit xt_rateest_tg_fini(void)
180{ 189{
181 xt_unregister_target(&xt_rateest_tg_reg); 190 xt_unregister_target(&xt_rateest_tg_reg);
191 rcu_barrier(); /* Wait for completion of call_rcu()'s (xt_rateest_free_rcu) */
182} 192}
183 193
184 194
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 972378f47f3c..23b25f89e7e0 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -26,6 +26,11 @@
26#include <net/act_api.h> 26#include <net/act_api.h>
27#include <net/netlink.h> 27#include <net/netlink.h>
28 28
29static void tcf_common_free_rcu(struct rcu_head *head)
30{
31 kfree(container_of(head, struct tcf_common, tcfc_rcu));
32}
33
29void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) 34void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
30{ 35{
31 unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); 36 unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);
@@ -38,7 +43,11 @@ void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
38 write_unlock_bh(hinfo->lock); 43 write_unlock_bh(hinfo->lock);
39 gen_kill_estimator(&p->tcfc_bstats, 44 gen_kill_estimator(&p->tcfc_bstats,
40 &p->tcfc_rate_est); 45 &p->tcfc_rate_est);
41 kfree(p); 46 /*
47 * gen_estimator est_timer() might access p->tcfc_lock
48 * or bstats, wait a RCU grace period before freeing p
49 */
50 call_rcu(&p->tcfc_rcu, tcf_common_free_rcu);
42 return; 51 return;
43 } 52 }
44 } 53 }
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 654f73dff7c1..537a48732e9e 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 }
@@ -397,6 +406,7 @@ static void __exit
397police_cleanup_module(void) 406police_cleanup_module(void)
398{ 407{
399 tcf_unregister_action(&act_police_ops); 408 tcf_unregister_action(&act_police_ops);
409 rcu_barrier(); /* Wait for completion of call_rcu()'s (tcf_police_free_rcu) */
400} 410}
401 411
402module_init(police_init_module); 412module_init(police_init_module);