aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/pkt_cls.h2
-rw-r--r--net/sched/cls_api.c5
-rw-r--r--net/sched/cls_basic.c24
-rw-r--r--net/sched/cls_bpf.c22
-rw-r--r--net/sched/cls_cgroup.c23
-rw-r--r--net/sched/cls_flow.c24
-rw-r--r--net/sched/cls_flower.c40
-rw-r--r--net/sched/cls_fw.c24
-rw-r--r--net/sched/cls_matchall.c21
-rw-r--r--net/sched/cls_route.c23
-rw-r--r--net/sched/cls_rsvp.h20
-rw-r--r--net/sched/cls_tcindex.c41
-rw-r--r--net/sched/cls_u32.c37
13 files changed, 85 insertions, 221 deletions
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 0005f0b40fe9..f3ec43725724 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -33,7 +33,7 @@ struct tcf_block_ext_info {
33}; 33};
34 34
35struct tcf_block_cb; 35struct tcf_block_cb;
36bool tcf_queue_work(struct work_struct *work); 36bool tcf_queue_work(struct rcu_work *rwork, work_func_t func);
37 37
38#ifdef CONFIG_NET_CLS 38#ifdef CONFIG_NET_CLS
39struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, 39struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 963e4bf0aab8..a4a5ace834c3 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -103,9 +103,10 @@ int unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
103} 103}
104EXPORT_SYMBOL(unregister_tcf_proto_ops); 104EXPORT_SYMBOL(unregister_tcf_proto_ops);
105 105
106bool tcf_queue_work(struct work_struct *work) 106bool tcf_queue_work(struct rcu_work *rwork, work_func_t func)
107{ 107{
108 return queue_work(tc_filter_wq, work); 108 INIT_RCU_WORK(rwork, func);
109 return queue_rcu_work(tc_filter_wq, rwork);
109} 110}
110EXPORT_SYMBOL(tcf_queue_work); 111EXPORT_SYMBOL(tcf_queue_work);
111 112
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index 6b7ab3512f5b..95367f37098d 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -35,10 +35,7 @@ struct basic_filter {
35 struct tcf_result res; 35 struct tcf_result res;
36 struct tcf_proto *tp; 36 struct tcf_proto *tp;
37 struct list_head link; 37 struct list_head link;
38 union { 38 struct rcu_work rwork;
39 struct work_struct work;
40 struct rcu_head rcu;
41 };
42}; 39};
43 40
44static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp, 41static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp,
@@ -97,21 +94,14 @@ static void __basic_delete_filter(struct basic_filter *f)
97 94
98static void basic_delete_filter_work(struct work_struct *work) 95static void basic_delete_filter_work(struct work_struct *work)
99{ 96{
100 struct basic_filter *f = container_of(work, struct basic_filter, work); 97 struct basic_filter *f = container_of(to_rcu_work(work),
101 98 struct basic_filter,
99 rwork);
102 rtnl_lock(); 100 rtnl_lock();
103 __basic_delete_filter(f); 101 __basic_delete_filter(f);
104 rtnl_unlock(); 102 rtnl_unlock();
105} 103}
106 104
107static void basic_delete_filter(struct rcu_head *head)
108{
109 struct basic_filter *f = container_of(head, struct basic_filter, rcu);
110
111 INIT_WORK(&f->work, basic_delete_filter_work);
112 tcf_queue_work(&f->work);
113}
114
115static void basic_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) 105static void basic_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
116{ 106{
117 struct basic_head *head = rtnl_dereference(tp->root); 107 struct basic_head *head = rtnl_dereference(tp->root);
@@ -122,7 +112,7 @@ static void basic_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
122 tcf_unbind_filter(tp, &f->res); 112 tcf_unbind_filter(tp, &f->res);
123 idr_remove(&head->handle_idr, f->handle); 113 idr_remove(&head->handle_idr, f->handle);
124 if (tcf_exts_get_net(&f->exts)) 114 if (tcf_exts_get_net(&f->exts))
125 call_rcu(&f->rcu, basic_delete_filter); 115 tcf_queue_work(&f->rwork, basic_delete_filter_work);
126 else 116 else
127 __basic_delete_filter(f); 117 __basic_delete_filter(f);
128 } 118 }
@@ -140,7 +130,7 @@ static int basic_delete(struct tcf_proto *tp, void *arg, bool *last,
140 tcf_unbind_filter(tp, &f->res); 130 tcf_unbind_filter(tp, &f->res);
141 idr_remove(&head->handle_idr, f->handle); 131 idr_remove(&head->handle_idr, f->handle);
142 tcf_exts_get_net(&f->exts); 132 tcf_exts_get_net(&f->exts);
143 call_rcu(&f->rcu, basic_delete_filter); 133 tcf_queue_work(&f->rwork, basic_delete_filter_work);
144 *last = list_empty(&head->flist); 134 *last = list_empty(&head->flist);
145 return 0; 135 return 0;
146} 136}
@@ -234,7 +224,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
234 list_replace_rcu(&fold->link, &fnew->link); 224 list_replace_rcu(&fold->link, &fnew->link);
235 tcf_unbind_filter(tp, &fold->res); 225 tcf_unbind_filter(tp, &fold->res);
236 tcf_exts_get_net(&fold->exts); 226 tcf_exts_get_net(&fold->exts);
237 call_rcu(&fold->rcu, basic_delete_filter); 227 tcf_queue_work(&fold->rwork, basic_delete_filter_work);
238 } else { 228 } else {
239 list_add_rcu(&fnew->link, &head->flist); 229 list_add_rcu(&fnew->link, &head->flist);
240 } 230 }
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index b07c1fa8bc0d..1aa7f6511065 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -49,10 +49,7 @@ struct cls_bpf_prog {
49 struct sock_filter *bpf_ops; 49 struct sock_filter *bpf_ops;
50 const char *bpf_name; 50 const char *bpf_name;
51 struct tcf_proto *tp; 51 struct tcf_proto *tp;
52 union { 52 struct rcu_work rwork;
53 struct work_struct work;
54 struct rcu_head rcu;
55 };
56}; 53};
57 54
58static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = { 55static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = {
@@ -275,21 +272,14 @@ static void __cls_bpf_delete_prog(struct cls_bpf_prog *prog)
275 272
276static void cls_bpf_delete_prog_work(struct work_struct *work) 273static void cls_bpf_delete_prog_work(struct work_struct *work)
277{ 274{
278 struct cls_bpf_prog *prog = container_of(work, struct cls_bpf_prog, work); 275 struct cls_bpf_prog *prog = container_of(to_rcu_work(work),
279 276 struct cls_bpf_prog,
277 rwork);
280 rtnl_lock(); 278 rtnl_lock();
281 __cls_bpf_delete_prog(prog); 279 __cls_bpf_delete_prog(prog);
282 rtnl_unlock(); 280 rtnl_unlock();
283} 281}
284 282
285static void cls_bpf_delete_prog_rcu(struct rcu_head *rcu)
286{
287 struct cls_bpf_prog *prog = container_of(rcu, struct cls_bpf_prog, rcu);
288
289 INIT_WORK(&prog->work, cls_bpf_delete_prog_work);
290 tcf_queue_work(&prog->work);
291}
292
293static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog, 283static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog,
294 struct netlink_ext_ack *extack) 284 struct netlink_ext_ack *extack)
295{ 285{
@@ -300,7 +290,7 @@ static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog,
300 list_del_rcu(&prog->link); 290 list_del_rcu(&prog->link);
301 tcf_unbind_filter(tp, &prog->res); 291 tcf_unbind_filter(tp, &prog->res);
302 if (tcf_exts_get_net(&prog->exts)) 292 if (tcf_exts_get_net(&prog->exts))
303 call_rcu(&prog->rcu, cls_bpf_delete_prog_rcu); 293 tcf_queue_work(&prog->rwork, cls_bpf_delete_prog_work);
304 else 294 else
305 __cls_bpf_delete_prog(prog); 295 __cls_bpf_delete_prog(prog);
306} 296}
@@ -526,7 +516,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
526 list_replace_rcu(&oldprog->link, &prog->link); 516 list_replace_rcu(&oldprog->link, &prog->link);
527 tcf_unbind_filter(tp, &oldprog->res); 517 tcf_unbind_filter(tp, &oldprog->res);
528 tcf_exts_get_net(&oldprog->exts); 518 tcf_exts_get_net(&oldprog->exts);
529 call_rcu(&oldprog->rcu, cls_bpf_delete_prog_rcu); 519 tcf_queue_work(&oldprog->rwork, cls_bpf_delete_prog_work);
530 } else { 520 } else {
531 list_add_rcu(&prog->link, &head->plist); 521 list_add_rcu(&prog->link, &head->plist);
532 } 522 }
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
index 762da5c0cf5e..3bc01bdde165 100644
--- a/net/sched/cls_cgroup.c
+++ b/net/sched/cls_cgroup.c
@@ -23,10 +23,7 @@ struct cls_cgroup_head {
23 struct tcf_exts exts; 23 struct tcf_exts exts;
24 struct tcf_ematch_tree ematches; 24 struct tcf_ematch_tree ematches;
25 struct tcf_proto *tp; 25 struct tcf_proto *tp;
26 union { 26 struct rcu_work rwork;
27 struct work_struct work;
28 struct rcu_head rcu;
29 };
30}; 27};
31 28
32static int cls_cgroup_classify(struct sk_buff *skb, const struct tcf_proto *tp, 29static int cls_cgroup_classify(struct sk_buff *skb, const struct tcf_proto *tp,
@@ -70,24 +67,14 @@ static void __cls_cgroup_destroy(struct cls_cgroup_head *head)
70 67
71static void cls_cgroup_destroy_work(struct work_struct *work) 68static void cls_cgroup_destroy_work(struct work_struct *work)
72{ 69{
73 struct cls_cgroup_head *head = container_of(work, 70 struct cls_cgroup_head *head = container_of(to_rcu_work(work),
74 struct cls_cgroup_head, 71 struct cls_cgroup_head,
75 work); 72 rwork);
76 rtnl_lock(); 73 rtnl_lock();
77 __cls_cgroup_destroy(head); 74 __cls_cgroup_destroy(head);
78 rtnl_unlock(); 75 rtnl_unlock();
79} 76}
80 77
81static void cls_cgroup_destroy_rcu(struct rcu_head *root)
82{
83 struct cls_cgroup_head *head = container_of(root,
84 struct cls_cgroup_head,
85 rcu);
86
87 INIT_WORK(&head->work, cls_cgroup_destroy_work);
88 tcf_queue_work(&head->work);
89}
90
91static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, 78static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
92 struct tcf_proto *tp, unsigned long base, 79 struct tcf_proto *tp, unsigned long base,
93 u32 handle, struct nlattr **tca, 80 u32 handle, struct nlattr **tca,
@@ -134,7 +121,7 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
134 rcu_assign_pointer(tp->root, new); 121 rcu_assign_pointer(tp->root, new);
135 if (head) { 122 if (head) {
136 tcf_exts_get_net(&head->exts); 123 tcf_exts_get_net(&head->exts);
137 call_rcu(&head->rcu, cls_cgroup_destroy_rcu); 124 tcf_queue_work(&head->rwork, cls_cgroup_destroy_work);
138 } 125 }
139 return 0; 126 return 0;
140errout: 127errout:
@@ -151,7 +138,7 @@ static void cls_cgroup_destroy(struct tcf_proto *tp,
151 /* Head can still be NULL due to cls_cgroup_init(). */ 138 /* Head can still be NULL due to cls_cgroup_init(). */
152 if (head) { 139 if (head) {
153 if (tcf_exts_get_net(&head->exts)) 140 if (tcf_exts_get_net(&head->exts))
154 call_rcu(&head->rcu, cls_cgroup_destroy_rcu); 141 tcf_queue_work(&head->rwork, cls_cgroup_destroy_work);
155 else 142 else
156 __cls_cgroup_destroy(head); 143 __cls_cgroup_destroy(head);
157 } 144 }
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index cd5fe383afdd..2bb043cd436b 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -57,10 +57,7 @@ struct flow_filter {
57 u32 divisor; 57 u32 divisor;
58 u32 baseclass; 58 u32 baseclass;
59 u32 hashrnd; 59 u32 hashrnd;
60 union { 60 struct rcu_work rwork;
61 struct work_struct work;
62 struct rcu_head rcu;
63 };
64}; 61};
65 62
66static inline u32 addr_fold(void *addr) 63static inline u32 addr_fold(void *addr)
@@ -383,21 +380,14 @@ static void __flow_destroy_filter(struct flow_filter *f)
383 380
384static void flow_destroy_filter_work(struct work_struct *work) 381static void flow_destroy_filter_work(struct work_struct *work)
385{ 382{
386 struct flow_filter *f = container_of(work, struct flow_filter, work); 383 struct flow_filter *f = container_of(to_rcu_work(work),
387 384 struct flow_filter,
385 rwork);
388 rtnl_lock(); 386 rtnl_lock();
389 __flow_destroy_filter(f); 387 __flow_destroy_filter(f);
390 rtnl_unlock(); 388 rtnl_unlock();
391} 389}
392 390
393static void flow_destroy_filter(struct rcu_head *head)
394{
395 struct flow_filter *f = container_of(head, struct flow_filter, rcu);
396
397 INIT_WORK(&f->work, flow_destroy_filter_work);
398 tcf_queue_work(&f->work);
399}
400
401static int flow_change(struct net *net, struct sk_buff *in_skb, 391static int flow_change(struct net *net, struct sk_buff *in_skb,
402 struct tcf_proto *tp, unsigned long base, 392 struct tcf_proto *tp, unsigned long base,
403 u32 handle, struct nlattr **tca, 393 u32 handle, struct nlattr **tca,
@@ -563,7 +553,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
563 553
564 if (fold) { 554 if (fold) {
565 tcf_exts_get_net(&fold->exts); 555 tcf_exts_get_net(&fold->exts);
566 call_rcu(&fold->rcu, flow_destroy_filter); 556 tcf_queue_work(&fold->rwork, flow_destroy_filter_work);
567 } 557 }
568 return 0; 558 return 0;
569 559
@@ -583,7 +573,7 @@ static int flow_delete(struct tcf_proto *tp, void *arg, bool *last,
583 573
584 list_del_rcu(&f->list); 574 list_del_rcu(&f->list);
585 tcf_exts_get_net(&f->exts); 575 tcf_exts_get_net(&f->exts);
586 call_rcu(&f->rcu, flow_destroy_filter); 576 tcf_queue_work(&f->rwork, flow_destroy_filter_work);
587 *last = list_empty(&head->filters); 577 *last = list_empty(&head->filters);
588 return 0; 578 return 0;
589} 579}
@@ -608,7 +598,7 @@ static void flow_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
608 list_for_each_entry_safe(f, next, &head->filters, list) { 598 list_for_each_entry_safe(f, next, &head->filters, list) {
609 list_del_rcu(&f->list); 599 list_del_rcu(&f->list);
610 if (tcf_exts_get_net(&f->exts)) 600 if (tcf_exts_get_net(&f->exts))
611 call_rcu(&f->rcu, flow_destroy_filter); 601 tcf_queue_work(&f->rwork, flow_destroy_filter_work);
612 else 602 else
613 __flow_destroy_filter(f); 603 __flow_destroy_filter(f);
614 } 604 }
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index eacaaf803914..4e74508515f4 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -73,10 +73,7 @@ struct fl_flow_mask {
73struct cls_fl_head { 73struct cls_fl_head {
74 struct rhashtable ht; 74 struct rhashtable ht;
75 struct list_head masks; 75 struct list_head masks;
76 union { 76 struct rcu_work rwork;
77 struct work_struct work;
78 struct rcu_head rcu;
79 };
80 struct idr handle_idr; 77 struct idr handle_idr;
81}; 78};
82 79
@@ -90,10 +87,7 @@ struct cls_fl_filter {
90 struct list_head list; 87 struct list_head list;
91 u32 handle; 88 u32 handle;
92 u32 flags; 89 u32 flags;
93 union { 90 struct rcu_work rwork;
94 struct work_struct work;
95 struct rcu_head rcu;
96 };
97 struct net_device *hw_dev; 91 struct net_device *hw_dev;
98}; 92};
99 93
@@ -235,21 +229,14 @@ static void __fl_destroy_filter(struct cls_fl_filter *f)
235 229
236static void fl_destroy_filter_work(struct work_struct *work) 230static void fl_destroy_filter_work(struct work_struct *work)
237{ 231{
238 struct cls_fl_filter *f = container_of(work, struct cls_fl_filter, work); 232 struct cls_fl_filter *f = container_of(to_rcu_work(work),
233 struct cls_fl_filter, rwork);
239 234
240 rtnl_lock(); 235 rtnl_lock();
241 __fl_destroy_filter(f); 236 __fl_destroy_filter(f);
242 rtnl_unlock(); 237 rtnl_unlock();
243} 238}
244 239
245static void fl_destroy_filter(struct rcu_head *head)
246{
247 struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu);
248
249 INIT_WORK(&f->work, fl_destroy_filter_work);
250 tcf_queue_work(&f->work);
251}
252
253static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f, 240static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
254 struct netlink_ext_ack *extack) 241 struct netlink_ext_ack *extack)
255{ 242{
@@ -327,7 +314,7 @@ static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
327 fl_hw_destroy_filter(tp, f, extack); 314 fl_hw_destroy_filter(tp, f, extack);
328 tcf_unbind_filter(tp, &f->res); 315 tcf_unbind_filter(tp, &f->res);
329 if (async) 316 if (async)
330 call_rcu(&f->rcu, fl_destroy_filter); 317 tcf_queue_work(&f->rwork, fl_destroy_filter_work);
331 else 318 else
332 __fl_destroy_filter(f); 319 __fl_destroy_filter(f);
333 320
@@ -336,20 +323,13 @@ static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
336 323
337static void fl_destroy_sleepable(struct work_struct *work) 324static void fl_destroy_sleepable(struct work_struct *work)
338{ 325{
339 struct cls_fl_head *head = container_of(work, struct cls_fl_head, 326 struct cls_fl_head *head = container_of(to_rcu_work(work),
340 work); 327 struct cls_fl_head,
328 rwork);
341 kfree(head); 329 kfree(head);
342 module_put(THIS_MODULE); 330 module_put(THIS_MODULE);
343} 331}
344 332
345static void fl_destroy_rcu(struct rcu_head *rcu)
346{
347 struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu);
348
349 INIT_WORK(&head->work, fl_destroy_sleepable);
350 schedule_work(&head->work);
351}
352
353static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) 333static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
354{ 334{
355 struct cls_fl_head *head = rtnl_dereference(tp->root); 335 struct cls_fl_head *head = rtnl_dereference(tp->root);
@@ -365,7 +345,7 @@ static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
365 idr_destroy(&head->handle_idr); 345 idr_destroy(&head->handle_idr);
366 346
367 __module_get(THIS_MODULE); 347 __module_get(THIS_MODULE);
368 call_rcu(&head->rcu, fl_destroy_rcu); 348 tcf_queue_work(&head->rwork, fl_destroy_sleepable);
369} 349}
370 350
371static void *fl_get(struct tcf_proto *tp, u32 handle) 351static void *fl_get(struct tcf_proto *tp, u32 handle)
@@ -1036,7 +1016,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
1036 list_replace_rcu(&fold->list, &fnew->list); 1016 list_replace_rcu(&fold->list, &fnew->list);
1037 tcf_unbind_filter(tp, &fold->res); 1017 tcf_unbind_filter(tp, &fold->res);
1038 tcf_exts_get_net(&fold->exts); 1018 tcf_exts_get_net(&fold->exts);
1039 call_rcu(&fold->rcu, fl_destroy_filter); 1019 tcf_queue_work(&fold->rwork, fl_destroy_filter_work);
1040 } else { 1020 } else {
1041 list_add_tail_rcu(&fnew->list, &fnew->mask->filters); 1021 list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
1042 } 1022 }
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index 8b207723fbc2..29eeeaf3ea44 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -47,10 +47,7 @@ struct fw_filter {
47#endif /* CONFIG_NET_CLS_IND */ 47#endif /* CONFIG_NET_CLS_IND */
48 struct tcf_exts exts; 48 struct tcf_exts exts;
49 struct tcf_proto *tp; 49 struct tcf_proto *tp;
50 union { 50 struct rcu_work rwork;
51 struct work_struct work;
52 struct rcu_head rcu;
53 };
54}; 51};
55 52
56static u32 fw_hash(u32 handle) 53static u32 fw_hash(u32 handle)
@@ -134,21 +131,14 @@ static void __fw_delete_filter(struct fw_filter *f)
134 131
135static void fw_delete_filter_work(struct work_struct *work) 132static void fw_delete_filter_work(struct work_struct *work)
136{ 133{
137 struct fw_filter *f = container_of(work, struct fw_filter, work); 134 struct fw_filter *f = container_of(to_rcu_work(work),
138 135 struct fw_filter,
136 rwork);
139 rtnl_lock(); 137 rtnl_lock();
140 __fw_delete_filter(f); 138 __fw_delete_filter(f);
141 rtnl_unlock(); 139 rtnl_unlock();
142} 140}
143 141
144static void fw_delete_filter(struct rcu_head *head)
145{
146 struct fw_filter *f = container_of(head, struct fw_filter, rcu);
147
148 INIT_WORK(&f->work, fw_delete_filter_work);
149 tcf_queue_work(&f->work);
150}
151
152static void fw_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) 142static void fw_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
153{ 143{
154 struct fw_head *head = rtnl_dereference(tp->root); 144 struct fw_head *head = rtnl_dereference(tp->root);
@@ -164,7 +154,7 @@ static void fw_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
164 rtnl_dereference(f->next)); 154 rtnl_dereference(f->next));
165 tcf_unbind_filter(tp, &f->res); 155 tcf_unbind_filter(tp, &f->res);
166 if (tcf_exts_get_net(&f->exts)) 156 if (tcf_exts_get_net(&f->exts))
167 call_rcu(&f->rcu, fw_delete_filter); 157 tcf_queue_work(&f->rwork, fw_delete_filter_work);
168 else 158 else
169 __fw_delete_filter(f); 159 __fw_delete_filter(f);
170 } 160 }
@@ -193,7 +183,7 @@ static int fw_delete(struct tcf_proto *tp, void *arg, bool *last,
193 RCU_INIT_POINTER(*fp, rtnl_dereference(f->next)); 183 RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
194 tcf_unbind_filter(tp, &f->res); 184 tcf_unbind_filter(tp, &f->res);
195 tcf_exts_get_net(&f->exts); 185 tcf_exts_get_net(&f->exts);
196 call_rcu(&f->rcu, fw_delete_filter); 186 tcf_queue_work(&f->rwork, fw_delete_filter_work);
197 ret = 0; 187 ret = 0;
198 break; 188 break;
199 } 189 }
@@ -316,7 +306,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
316 rcu_assign_pointer(*fp, fnew); 306 rcu_assign_pointer(*fp, fnew);
317 tcf_unbind_filter(tp, &f->res); 307 tcf_unbind_filter(tp, &f->res);
318 tcf_exts_get_net(&f->exts); 308 tcf_exts_get_net(&f->exts);
319 call_rcu(&f->rcu, fw_delete_filter); 309 tcf_queue_work(&f->rwork, fw_delete_filter_work);
320 310
321 *arg = fnew; 311 *arg = fnew;
322 return err; 312 return err;
diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c
index 2ba721a590a7..47b207ef7762 100644
--- a/net/sched/cls_matchall.c
+++ b/net/sched/cls_matchall.c
@@ -21,10 +21,7 @@ struct cls_mall_head {
21 struct tcf_result res; 21 struct tcf_result res;
22 u32 handle; 22 u32 handle;
23 u32 flags; 23 u32 flags;
24 union { 24 struct rcu_work rwork;
25 struct work_struct work;
26 struct rcu_head rcu;
27 };
28}; 25};
29 26
30static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp, 27static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp,
@@ -53,22 +50,14 @@ static void __mall_destroy(struct cls_mall_head *head)
53 50
54static void mall_destroy_work(struct work_struct *work) 51static void mall_destroy_work(struct work_struct *work)
55{ 52{
56 struct cls_mall_head *head = container_of(work, struct cls_mall_head, 53 struct cls_mall_head *head = container_of(to_rcu_work(work),
57 work); 54 struct cls_mall_head,
55 rwork);
58 rtnl_lock(); 56 rtnl_lock();
59 __mall_destroy(head); 57 __mall_destroy(head);
60 rtnl_unlock(); 58 rtnl_unlock();
61} 59}
62 60
63static void mall_destroy_rcu(struct rcu_head *rcu)
64{
65 struct cls_mall_head *head = container_of(rcu, struct cls_mall_head,
66 rcu);
67
68 INIT_WORK(&head->work, mall_destroy_work);
69 tcf_queue_work(&head->work);
70}
71
72static void mall_destroy_hw_filter(struct tcf_proto *tp, 61static void mall_destroy_hw_filter(struct tcf_proto *tp,
73 struct cls_mall_head *head, 62 struct cls_mall_head *head,
74 unsigned long cookie, 63 unsigned long cookie,
@@ -126,7 +115,7 @@ static void mall_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
126 mall_destroy_hw_filter(tp, head, (unsigned long) head, extack); 115 mall_destroy_hw_filter(tp, head, (unsigned long) head, extack);
127 116
128 if (tcf_exts_get_net(&head->exts)) 117 if (tcf_exts_get_net(&head->exts))
129 call_rcu(&head->rcu, mall_destroy_rcu); 118 tcf_queue_work(&head->rwork, mall_destroy_work);
130 else 119 else
131 __mall_destroy(head); 120 __mall_destroy(head);
132} 121}
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index 21a03a8ee029..0404aa5fa7cb 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -57,10 +57,7 @@ struct route4_filter {
57 u32 handle; 57 u32 handle;
58 struct route4_bucket *bkt; 58 struct route4_bucket *bkt;
59 struct tcf_proto *tp; 59 struct tcf_proto *tp;
60 union { 60 struct rcu_work rwork;
61 struct work_struct work;
62 struct rcu_head rcu;
63 };
64}; 61};
65 62
66#define ROUTE4_FAILURE ((struct route4_filter *)(-1L)) 63#define ROUTE4_FAILURE ((struct route4_filter *)(-1L))
@@ -266,19 +263,17 @@ static void __route4_delete_filter(struct route4_filter *f)
266 263
267static void route4_delete_filter_work(struct work_struct *work) 264static void route4_delete_filter_work(struct work_struct *work)
268{ 265{
269 struct route4_filter *f = container_of(work, struct route4_filter, work); 266 struct route4_filter *f = container_of(to_rcu_work(work),
270 267 struct route4_filter,
268 rwork);
271 rtnl_lock(); 269 rtnl_lock();
272 __route4_delete_filter(f); 270 __route4_delete_filter(f);
273 rtnl_unlock(); 271 rtnl_unlock();
274} 272}
275 273
276static void route4_delete_filter(struct rcu_head *head) 274static void route4_queue_work(struct route4_filter *f)
277{ 275{
278 struct route4_filter *f = container_of(head, struct route4_filter, rcu); 276 tcf_queue_work(&f->rwork, route4_delete_filter_work);
279
280 INIT_WORK(&f->work, route4_delete_filter_work);
281 tcf_queue_work(&f->work);
282} 277}
283 278
284static void route4_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) 279static void route4_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
@@ -304,7 +299,7 @@ static void route4_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
304 RCU_INIT_POINTER(b->ht[h2], next); 299 RCU_INIT_POINTER(b->ht[h2], next);
305 tcf_unbind_filter(tp, &f->res); 300 tcf_unbind_filter(tp, &f->res);
306 if (tcf_exts_get_net(&f->exts)) 301 if (tcf_exts_get_net(&f->exts))
307 call_rcu(&f->rcu, route4_delete_filter); 302 route4_queue_work(f);
308 else 303 else
309 __route4_delete_filter(f); 304 __route4_delete_filter(f);
310 } 305 }
@@ -349,7 +344,7 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,
349 /* Delete it */ 344 /* Delete it */
350 tcf_unbind_filter(tp, &f->res); 345 tcf_unbind_filter(tp, &f->res);
351 tcf_exts_get_net(&f->exts); 346 tcf_exts_get_net(&f->exts);
352 call_rcu(&f->rcu, route4_delete_filter); 347 tcf_queue_work(&f->rwork, route4_delete_filter_work);
353 348
354 /* Strip RTNL protected tree */ 349 /* Strip RTNL protected tree */
355 for (i = 0; i <= 32; i++) { 350 for (i = 0; i <= 32; i++) {
@@ -554,7 +549,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
554 if (fold) { 549 if (fold) {
555 tcf_unbind_filter(tp, &fold->res); 550 tcf_unbind_filter(tp, &fold->res);
556 tcf_exts_get_net(&fold->exts); 551 tcf_exts_get_net(&fold->exts);
557 call_rcu(&fold->rcu, route4_delete_filter); 552 tcf_queue_work(&fold->rwork, route4_delete_filter_work);
558 } 553 }
559 return 0; 554 return 0;
560 555
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h
index 4f1297657c27..e9ccf7daea7d 100644
--- a/net/sched/cls_rsvp.h
+++ b/net/sched/cls_rsvp.h
@@ -97,10 +97,7 @@ struct rsvp_filter {
97 97
98 u32 handle; 98 u32 handle;
99 struct rsvp_session *sess; 99 struct rsvp_session *sess;
100 union { 100 struct rcu_work rwork;
101 struct work_struct work;
102 struct rcu_head rcu;
103 };
104}; 101};
105 102
106static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid) 103static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid)
@@ -294,21 +291,14 @@ static void __rsvp_delete_filter(struct rsvp_filter *f)
294 291
295static void rsvp_delete_filter_work(struct work_struct *work) 292static void rsvp_delete_filter_work(struct work_struct *work)
296{ 293{
297 struct rsvp_filter *f = container_of(work, struct rsvp_filter, work); 294 struct rsvp_filter *f = container_of(to_rcu_work(work),
298 295 struct rsvp_filter,
296 rwork);
299 rtnl_lock(); 297 rtnl_lock();
300 __rsvp_delete_filter(f); 298 __rsvp_delete_filter(f);
301 rtnl_unlock(); 299 rtnl_unlock();
302} 300}
303 301
304static void rsvp_delete_filter_rcu(struct rcu_head *head)
305{
306 struct rsvp_filter *f = container_of(head, struct rsvp_filter, rcu);
307
308 INIT_WORK(&f->work, rsvp_delete_filter_work);
309 tcf_queue_work(&f->work);
310}
311
312static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f) 302static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
313{ 303{
314 tcf_unbind_filter(tp, &f->res); 304 tcf_unbind_filter(tp, &f->res);
@@ -317,7 +307,7 @@ static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
317 * in cleanup() callback 307 * in cleanup() callback
318 */ 308 */
319 if (tcf_exts_get_net(&f->exts)) 309 if (tcf_exts_get_net(&f->exts))
320 call_rcu(&f->rcu, rsvp_delete_filter_rcu); 310 tcf_queue_work(&f->rwork, rsvp_delete_filter_work);
321 else 311 else
322 __rsvp_delete_filter(f); 312 __rsvp_delete_filter(f);
323} 313}
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
index b49cc990a000..32f4bbd82f35 100644
--- a/net/sched/cls_tcindex.c
+++ b/net/sched/cls_tcindex.c
@@ -28,20 +28,14 @@
28struct tcindex_filter_result { 28struct tcindex_filter_result {
29 struct tcf_exts exts; 29 struct tcf_exts exts;
30 struct tcf_result res; 30 struct tcf_result res;
31 union { 31 struct rcu_work rwork;
32 struct work_struct work;
33 struct rcu_head rcu;
34 };
35}; 32};
36 33
37struct tcindex_filter { 34struct tcindex_filter {
38 u16 key; 35 u16 key;
39 struct tcindex_filter_result result; 36 struct tcindex_filter_result result;
40 struct tcindex_filter __rcu *next; 37 struct tcindex_filter __rcu *next;
41 union { 38 struct rcu_work rwork;
42 struct work_struct work;
43 struct rcu_head rcu;
44 };
45}; 39};
46 40
47 41
@@ -152,21 +146,14 @@ static void tcindex_destroy_rexts_work(struct work_struct *work)
152{ 146{
153 struct tcindex_filter_result *r; 147 struct tcindex_filter_result *r;
154 148
155 r = container_of(work, struct tcindex_filter_result, work); 149 r = container_of(to_rcu_work(work),
150 struct tcindex_filter_result,
151 rwork);
156 rtnl_lock(); 152 rtnl_lock();
157 __tcindex_destroy_rexts(r); 153 __tcindex_destroy_rexts(r);
158 rtnl_unlock(); 154 rtnl_unlock();
159} 155}
160 156
161static void tcindex_destroy_rexts(struct rcu_head *head)
162{
163 struct tcindex_filter_result *r;
164
165 r = container_of(head, struct tcindex_filter_result, rcu);
166 INIT_WORK(&r->work, tcindex_destroy_rexts_work);
167 tcf_queue_work(&r->work);
168}
169
170static void __tcindex_destroy_fexts(struct tcindex_filter *f) 157static void __tcindex_destroy_fexts(struct tcindex_filter *f)
171{ 158{
172 tcf_exts_destroy(&f->result.exts); 159 tcf_exts_destroy(&f->result.exts);
@@ -176,23 +163,15 @@ static void __tcindex_destroy_fexts(struct tcindex_filter *f)
176 163
177static void tcindex_destroy_fexts_work(struct work_struct *work) 164static void tcindex_destroy_fexts_work(struct work_struct *work)
178{ 165{
179 struct tcindex_filter *f = container_of(work, struct tcindex_filter, 166 struct tcindex_filter *f = container_of(to_rcu_work(work),
180 work); 167 struct tcindex_filter,
168 rwork);
181 169
182 rtnl_lock(); 170 rtnl_lock();
183 __tcindex_destroy_fexts(f); 171 __tcindex_destroy_fexts(f);
184 rtnl_unlock(); 172 rtnl_unlock();
185} 173}
186 174
187static void tcindex_destroy_fexts(struct rcu_head *head)
188{
189 struct tcindex_filter *f = container_of(head, struct tcindex_filter,
190 rcu);
191
192 INIT_WORK(&f->work, tcindex_destroy_fexts_work);
193 tcf_queue_work(&f->work);
194}
195
196static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last, 175static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last,
197 struct netlink_ext_ack *extack) 176 struct netlink_ext_ack *extack)
198{ 177{
@@ -228,12 +207,12 @@ found:
228 */ 207 */
229 if (f) { 208 if (f) {
230 if (tcf_exts_get_net(&f->result.exts)) 209 if (tcf_exts_get_net(&f->result.exts))
231 call_rcu(&f->rcu, tcindex_destroy_fexts); 210 tcf_queue_work(&f->rwork, tcindex_destroy_fexts_work);
232 else 211 else
233 __tcindex_destroy_fexts(f); 212 __tcindex_destroy_fexts(f);
234 } else { 213 } else {
235 if (tcf_exts_get_net(&r->exts)) 214 if (tcf_exts_get_net(&r->exts))
236 call_rcu(&r->rcu, tcindex_destroy_rexts); 215 tcf_queue_work(&r->rwork, tcindex_destroy_rexts_work);
237 else 216 else
238 __tcindex_destroy_rexts(r); 217 __tcindex_destroy_rexts(r);
239 } 218 }
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index bac47b5d18fd..fb861f90fde6 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -68,10 +68,7 @@ struct tc_u_knode {
68 u32 __percpu *pcpu_success; 68 u32 __percpu *pcpu_success;
69#endif 69#endif
70 struct tcf_proto *tp; 70 struct tcf_proto *tp;
71 union { 71 struct rcu_work rwork;
72 struct work_struct work;
73 struct rcu_head rcu;
74 };
75 /* The 'sel' field MUST be the last field in structure to allow for 72 /* The 'sel' field MUST be the last field in structure to allow for
76 * tc_u32_keys allocated at end of structure. 73 * tc_u32_keys allocated at end of structure.
77 */ 74 */
@@ -436,21 +433,14 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n,
436 */ 433 */
437static void u32_delete_key_work(struct work_struct *work) 434static void u32_delete_key_work(struct work_struct *work)
438{ 435{
439 struct tc_u_knode *key = container_of(work, struct tc_u_knode, work); 436 struct tc_u_knode *key = container_of(to_rcu_work(work),
440 437 struct tc_u_knode,
438 rwork);
441 rtnl_lock(); 439 rtnl_lock();
442 u32_destroy_key(key->tp, key, false); 440 u32_destroy_key(key->tp, key, false);
443 rtnl_unlock(); 441 rtnl_unlock();
444} 442}
445 443
446static void u32_delete_key_rcu(struct rcu_head *rcu)
447{
448 struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu);
449
450 INIT_WORK(&key->work, u32_delete_key_work);
451 tcf_queue_work(&key->work);
452}
453
454/* u32_delete_key_freepf_rcu is the rcu callback variant 444/* u32_delete_key_freepf_rcu is the rcu callback variant
455 * that free's the entire structure including the statistics 445 * that free's the entire structure including the statistics
456 * percpu variables. Only use this if the key is not a copy 446 * percpu variables. Only use this if the key is not a copy
@@ -460,21 +450,14 @@ static void u32_delete_key_rcu(struct rcu_head *rcu)
460 */ 450 */
461static void u32_delete_key_freepf_work(struct work_struct *work) 451static void u32_delete_key_freepf_work(struct work_struct *work)
462{ 452{
463 struct tc_u_knode *key = container_of(work, struct tc_u_knode, work); 453 struct tc_u_knode *key = container_of(to_rcu_work(work),
464 454 struct tc_u_knode,
455 rwork);
465 rtnl_lock(); 456 rtnl_lock();
466 u32_destroy_key(key->tp, key, true); 457 u32_destroy_key(key->tp, key, true);
467 rtnl_unlock(); 458 rtnl_unlock();
468} 459}
469 460
470static void u32_delete_key_freepf_rcu(struct rcu_head *rcu)
471{
472 struct tc_u_knode *key = container_of(rcu, struct tc_u_knode, rcu);
473
474 INIT_WORK(&key->work, u32_delete_key_freepf_work);
475 tcf_queue_work(&key->work);
476}
477
478static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) 461static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key)
479{ 462{
480 struct tc_u_knode __rcu **kp; 463 struct tc_u_knode __rcu **kp;
@@ -491,7 +474,7 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key)
491 tcf_unbind_filter(tp, &key->res); 474 tcf_unbind_filter(tp, &key->res);
492 idr_remove(&ht->handle_idr, key->handle); 475 idr_remove(&ht->handle_idr, key->handle);
493 tcf_exts_get_net(&key->exts); 476 tcf_exts_get_net(&key->exts);
494 call_rcu(&key->rcu, u32_delete_key_freepf_rcu); 477 tcf_queue_work(&key->rwork, u32_delete_key_freepf_work);
495 return 0; 478 return 0;
496 } 479 }
497 } 480 }
@@ -611,7 +594,7 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht,
611 u32_remove_hw_knode(tp, n, extack); 594 u32_remove_hw_knode(tp, n, extack);
612 idr_remove(&ht->handle_idr, n->handle); 595 idr_remove(&ht->handle_idr, n->handle);
613 if (tcf_exts_get_net(&n->exts)) 596 if (tcf_exts_get_net(&n->exts))
614 call_rcu(&n->rcu, u32_delete_key_freepf_rcu); 597 tcf_queue_work(&n->rwork, u32_delete_key_freepf_work);
615 else 598 else
616 u32_destroy_key(n->tp, n, true); 599 u32_destroy_key(n->tp, n, true);
617 } 600 }
@@ -995,7 +978,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
995 u32_replace_knode(tp, tp_c, new); 978 u32_replace_knode(tp, tp_c, new);
996 tcf_unbind_filter(tp, &n->res); 979 tcf_unbind_filter(tp, &n->res);
997 tcf_exts_get_net(&n->exts); 980 tcf_exts_get_net(&n->exts);
998 call_rcu(&n->rcu, u32_delete_key_rcu); 981 tcf_queue_work(&n->rwork, u32_delete_key_work);
999 return 0; 982 return 0;
1000 } 983 }
1001 984