aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_flower.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/cls_flower.c')
-rw-r--r--net/sched/cls_flower.c42
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
71struct cls_fl_filter { 75struct 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
293static 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
303static 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
289static bool fl_destroy(struct tcf_proto *tp, bool force) 311static 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}