diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/gen_estimator.c | 9 |
1 files changed, 4 insertions, 5 deletions
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index a89f32fa94f6..57abe8266be1 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c | |||
@@ -99,7 +99,7 @@ struct gen_estimator_head | |||
99 | 99 | ||
100 | static struct gen_estimator_head elist[EST_MAX_INTERVAL+1]; | 100 | static struct gen_estimator_head elist[EST_MAX_INTERVAL+1]; |
101 | 101 | ||
102 | /* Protects against NULL dereference and RCU write-side */ | 102 | /* Protects against NULL dereference */ |
103 | static DEFINE_RWLOCK(est_lock); | 103 | static DEFINE_RWLOCK(est_lock); |
104 | 104 | ||
105 | static void est_timer(unsigned long arg) | 105 | static void est_timer(unsigned long arg) |
@@ -185,7 +185,6 @@ int gen_new_estimator(struct gnet_stats_basic *bstats, | |||
185 | est->last_packets = bstats->packets; | 185 | est->last_packets = bstats->packets; |
186 | est->avpps = rate_est->pps<<10; | 186 | est->avpps = rate_est->pps<<10; |
187 | 187 | ||
188 | write_lock_bh(&est_lock); | ||
189 | if (!elist[idx].timer.function) { | 188 | if (!elist[idx].timer.function) { |
190 | INIT_LIST_HEAD(&elist[idx].list); | 189 | INIT_LIST_HEAD(&elist[idx].list); |
191 | setup_timer(&elist[idx].timer, est_timer, idx); | 190 | setup_timer(&elist[idx].timer, est_timer, idx); |
@@ -195,7 +194,6 @@ int gen_new_estimator(struct gnet_stats_basic *bstats, | |||
195 | mod_timer(&elist[idx].timer, jiffies + ((HZ/4) << idx)); | 194 | mod_timer(&elist[idx].timer, jiffies + ((HZ/4) << idx)); |
196 | 195 | ||
197 | list_add_rcu(&est->list, &elist[idx].list); | 196 | list_add_rcu(&est->list, &elist[idx].list); |
198 | write_unlock_bh(&est_lock); | ||
199 | return 0; | 197 | return 0; |
200 | } | 198 | } |
201 | 199 | ||
@@ -214,6 +212,7 @@ static void __gen_kill_estimator(struct rcu_head *head) | |||
214 | * Removes the rate estimator specified by &bstats and &rate_est | 212 | * Removes the rate estimator specified by &bstats and &rate_est |
215 | * and deletes the timer. | 213 | * and deletes the timer. |
216 | * | 214 | * |
215 | * NOTE: Called under rtnl_mutex | ||
217 | */ | 216 | */ |
218 | void gen_kill_estimator(struct gnet_stats_basic *bstats, | 217 | void gen_kill_estimator(struct gnet_stats_basic *bstats, |
219 | struct gnet_stats_rate_est *rate_est) | 218 | struct gnet_stats_rate_est *rate_est) |
@@ -227,17 +226,17 @@ void gen_kill_estimator(struct gnet_stats_basic *bstats, | |||
227 | if (!elist[idx].timer.function) | 226 | if (!elist[idx].timer.function) |
228 | continue; | 227 | continue; |
229 | 228 | ||
230 | write_lock_bh(&est_lock); | ||
231 | list_for_each_entry_safe(e, n, &elist[idx].list, list) { | 229 | list_for_each_entry_safe(e, n, &elist[idx].list, list) { |
232 | if (e->rate_est != rate_est || e->bstats != bstats) | 230 | if (e->rate_est != rate_est || e->bstats != bstats) |
233 | continue; | 231 | continue; |
234 | 232 | ||
233 | write_lock_bh(&est_lock); | ||
235 | e->bstats = NULL; | 234 | e->bstats = NULL; |
235 | write_unlock_bh(&est_lock); | ||
236 | 236 | ||
237 | list_del_rcu(&e->list); | 237 | list_del_rcu(&e->list); |
238 | call_rcu(&e->e_rcu, __gen_kill_estimator); | 238 | call_rcu(&e->e_rcu, __gen_kill_estimator); |
239 | } | 239 | } |
240 | write_unlock_bh(&est_lock); | ||
241 | } | 240 | } |
242 | } | 241 | } |
243 | 242 | ||