aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_basic.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/cls_basic.c')
-rw-r--r--net/sched/cls_basic.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index d89ebafd2239..f177649a2419 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -34,7 +34,10 @@ struct basic_filter {
34 struct tcf_result res; 34 struct tcf_result res;
35 struct tcf_proto *tp; 35 struct tcf_proto *tp;
36 struct list_head link; 36 struct list_head link;
37 struct rcu_head rcu; 37 union {
38 struct work_struct work;
39 struct rcu_head rcu;
40 };
38}; 41};
39 42
40static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp, 43static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp,
@@ -82,15 +85,26 @@ static int basic_init(struct tcf_proto *tp)
82 return 0; 85 return 0;
83} 86}
84 87
85static void basic_delete_filter(struct rcu_head *head) 88static void basic_delete_filter_work(struct work_struct *work)
86{ 89{
87 struct basic_filter *f = container_of(head, struct basic_filter, rcu); 90 struct basic_filter *f = container_of(work, struct basic_filter, work);
88 91
92 rtnl_lock();
89 tcf_exts_destroy(&f->exts); 93 tcf_exts_destroy(&f->exts);
90 tcf_em_tree_destroy(&f->ematches); 94 tcf_em_tree_destroy(&f->ematches);
95 rtnl_unlock();
96
91 kfree(f); 97 kfree(f);
92} 98}
93 99
100static void basic_delete_filter(struct rcu_head *head)
101{
102 struct basic_filter *f = container_of(head, struct basic_filter, rcu);
103
104 INIT_WORK(&f->work, basic_delete_filter_work);
105 tcf_queue_work(&f->work);
106}
107
94static void basic_destroy(struct tcf_proto *tp) 108static void basic_destroy(struct tcf_proto *tp)
95{ 109{
96 struct basic_head *head = rtnl_dereference(tp->root); 110 struct basic_head *head = rtnl_dereference(tp->root);