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.c20
1 files changed, 14 insertions, 6 deletions
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 7d97f612c9b9..b9d63d2246e6 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -23,7 +23,6 @@
23#include <linux/skbuff.h> 23#include <linux/skbuff.h>
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/kmod.h> 25#include <linux/kmod.h>
26#include <linux/err.h>
27#include <linux/slab.h> 26#include <linux/slab.h>
28#include <net/net_namespace.h> 27#include <net/net_namespace.h>
29#include <net/sock.h> 28#include <net/sock.h>
@@ -336,7 +335,8 @@ static void tcf_block_put_final(struct work_struct *work)
336 struct tcf_chain *chain, *tmp; 335 struct tcf_chain *chain, *tmp;
337 336
338 rtnl_lock(); 337 rtnl_lock();
339 /* Only chain 0 should be still here. */ 338
339 /* At this point, all the chains should have refcnt == 1. */
340 list_for_each_entry_safe(chain, tmp, &block->chain_list, list) 340 list_for_each_entry_safe(chain, tmp, &block->chain_list, list)
341 tcf_chain_put(chain); 341 tcf_chain_put(chain);
342 rtnl_unlock(); 342 rtnl_unlock();
@@ -344,15 +344,23 @@ static void tcf_block_put_final(struct work_struct *work)
344} 344}
345 345
346/* XXX: Standalone actions are not allowed to jump to any chain, and bound 346/* 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 347 * actions should be all removed after flushing.
348 * destroyed in tc filter workqueue with RTNL lock, they can not race here.
349 */ 348 */
350void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q, 349void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
351 struct tcf_block_ext_info *ei) 350 struct tcf_block_ext_info *ei)
352{ 351{
353 struct tcf_chain *chain, *tmp; 352 struct tcf_chain *chain;
354 353
355 list_for_each_entry_safe(chain, tmp, &block->chain_list, list) 354 if (!block)
355 return;
356 /* Hold a refcnt for all chains, except 0, so that they don't disappear
357 * while we are iterating.
358 */
359 list_for_each_entry(chain, &block->chain_list, list)
360 if (chain->index)
361 tcf_chain_hold(chain);
362
363 list_for_each_entry(chain, &block->chain_list, list)
356 tcf_chain_flush(chain); 364 tcf_chain_flush(chain);
357 365
358 tcf_block_offload_unbind(block, q, ei); 366 tcf_block_offload_unbind(block, q, ei);