diff options
Diffstat (limited to 'net/sched/cls_api.c')
-rw-r--r-- | net/sched/cls_api.c | 20 |
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 | */ |
350 | void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q, | 349 | void 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); |