aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/cls_api.c')
-rw-r--r--net/sched/cls_api.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 7d97f612c9b9..ddcf04b4ab43 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -336,7 +336,8 @@ static void tcf_block_put_final(struct work_struct *work)
336 struct tcf_chain *chain, *tmp; 336 struct tcf_chain *chain, *tmp;
337 337
338 rtnl_lock(); 338 rtnl_lock();
339 /* Only chain 0 should be still here. */ 339
340 /* At this point, all the chains should have refcnt == 1. */
340 list_for_each_entry_safe(chain, tmp, &block->chain_list, list) 341 list_for_each_entry_safe(chain, tmp, &block->chain_list, list)
341 tcf_chain_put(chain); 342 tcf_chain_put(chain);
342 rtnl_unlock(); 343 rtnl_unlock();
@@ -344,15 +345,21 @@ static void tcf_block_put_final(struct work_struct *work)
344} 345}
345 346
346/* XXX: Standalone actions are not allowed to jump to any chain, and bound 347/* XXX: Standalone actions are not allowed to jump to any chain, and bound
347 * actions should be all removed after flushing. However, filters are now 348 * actions should be all removed after flushing.
348 * destroyed in tc filter workqueue with RTNL lock, they can not race here.
349 */ 349 */
350void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q, 350void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
351 struct tcf_block_ext_info *ei) 351 struct tcf_block_ext_info *ei)
352{ 352{
353 struct tcf_chain *chain, *tmp; 353 struct tcf_chain *chain;
354 354
355 list_for_each_entry_safe(chain, tmp, &block->chain_list, list) 355 /* Hold a refcnt for all chains, except 0, so that they don't disappear
356 * while we are iterating.
357 */
358 list_for_each_entry(chain, &block->chain_list, list)
359 if (chain->index)
360 tcf_chain_hold(chain);
361
362 list_for_each_entry(chain, &block->chain_list, list)
356 tcf_chain_flush(chain); 363 tcf_chain_flush(chain);
357 364
358 tcf_block_offload_unbind(block, q, ei); 365 tcf_block_offload_unbind(block, q, ei);