diff options
Diffstat (limited to 'net/sched/cls_flower.c')
-rw-r--r-- | net/sched/cls_flower.c | 42 |
1 files changed, 33 insertions, 9 deletions
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 1cacfa5c95f3..c5cea78491dc 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/rhashtable.h> | 15 | #include <linux/rhashtable.h> |
16 | #include <linux/workqueue.h> | ||
16 | 17 | ||
17 | #include <linux/if_ether.h> | 18 | #include <linux/if_ether.h> |
18 | #include <linux/in6.h> | 19 | #include <linux/in6.h> |
@@ -65,7 +66,10 @@ struct cls_fl_head { | |||
65 | bool mask_assigned; | 66 | bool mask_assigned; |
66 | struct list_head filters; | 67 | struct list_head filters; |
67 | struct rhashtable_params ht_params; | 68 | struct rhashtable_params ht_params; |
68 | struct rcu_head rcu; | 69 | union { |
70 | struct work_struct work; | ||
71 | struct rcu_head rcu; | ||
72 | }; | ||
69 | }; | 73 | }; |
70 | 74 | ||
71 | struct cls_fl_filter { | 75 | struct cls_fl_filter { |
@@ -286,6 +290,24 @@ static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f) | |||
286 | call_rcu(&f->rcu, fl_destroy_filter); | 290 | call_rcu(&f->rcu, fl_destroy_filter); |
287 | } | 291 | } |
288 | 292 | ||
293 | static void fl_destroy_sleepable(struct work_struct *work) | ||
294 | { | ||
295 | struct cls_fl_head *head = container_of(work, struct cls_fl_head, | ||
296 | work); | ||
297 | if (head->mask_assigned) | ||
298 | rhashtable_destroy(&head->ht); | ||
299 | kfree(head); | ||
300 | module_put(THIS_MODULE); | ||
301 | } | ||
302 | |||
303 | static void fl_destroy_rcu(struct rcu_head *rcu) | ||
304 | { | ||
305 | struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu); | ||
306 | |||
307 | INIT_WORK(&head->work, fl_destroy_sleepable); | ||
308 | schedule_work(&head->work); | ||
309 | } | ||
310 | |||
289 | static bool fl_destroy(struct tcf_proto *tp, bool force) | 311 | static bool fl_destroy(struct tcf_proto *tp, bool force) |
290 | { | 312 | { |
291 | struct cls_fl_head *head = rtnl_dereference(tp->root); | 313 | struct cls_fl_head *head = rtnl_dereference(tp->root); |
@@ -296,10 +318,10 @@ static bool fl_destroy(struct tcf_proto *tp, bool force) | |||
296 | 318 | ||
297 | list_for_each_entry_safe(f, next, &head->filters, list) | 319 | list_for_each_entry_safe(f, next, &head->filters, list) |
298 | __fl_delete(tp, f); | 320 | __fl_delete(tp, f); |
299 | RCU_INIT_POINTER(tp->root, NULL); | 321 | |
300 | if (head->mask_assigned) | 322 | __module_get(THIS_MODULE); |
301 | rhashtable_destroy(&head->ht); | 323 | call_rcu(&head->rcu, fl_destroy_rcu); |
302 | kfree_rcu(head, rcu); | 324 | |
303 | return true; | 325 | return true; |
304 | } | 326 | } |
305 | 327 | ||
@@ -759,8 +781,9 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, | |||
759 | } | 781 | } |
760 | 782 | ||
761 | if (fold) { | 783 | if (fold) { |
762 | rhashtable_remove_fast(&head->ht, &fold->ht_node, | 784 | if (!tc_skip_sw(fold->flags)) |
763 | head->ht_params); | 785 | rhashtable_remove_fast(&head->ht, &fold->ht_node, |
786 | head->ht_params); | ||
764 | if (!tc_skip_hw(fold->flags)) | 787 | if (!tc_skip_hw(fold->flags)) |
765 | fl_hw_destroy_filter(tp, fold); | 788 | fl_hw_destroy_filter(tp, fold); |
766 | } | 789 | } |
@@ -788,8 +811,9 @@ static int fl_delete(struct tcf_proto *tp, unsigned long arg) | |||
788 | struct cls_fl_head *head = rtnl_dereference(tp->root); | 811 | struct cls_fl_head *head = rtnl_dereference(tp->root); |
789 | struct cls_fl_filter *f = (struct cls_fl_filter *) arg; | 812 | struct cls_fl_filter *f = (struct cls_fl_filter *) arg; |
790 | 813 | ||
791 | rhashtable_remove_fast(&head->ht, &f->ht_node, | 814 | if (!tc_skip_sw(f->flags)) |
792 | head->ht_params); | 815 | rhashtable_remove_fast(&head->ht, &f->ht_node, |
816 | head->ht_params); | ||
793 | __fl_delete(tp, f); | 817 | __fl_delete(tp, f); |
794 | return 0; | 818 | return 0; |
795 | } | 819 | } |