diff options
-rw-r--r-- | include/net/pkt_cls.h | 2 | ||||
-rw-r--r-- | net/sched/cls_api.c | 5 | ||||
-rw-r--r-- | net/sched/cls_basic.c | 24 | ||||
-rw-r--r-- | net/sched/cls_bpf.c | 22 | ||||
-rw-r--r-- | net/sched/cls_cgroup.c | 23 | ||||
-rw-r--r-- | net/sched/cls_flow.c | 24 | ||||
-rw-r--r-- | net/sched/cls_flower.c | 40 | ||||
-rw-r--r-- | net/sched/cls_fw.c | 24 | ||||
-rw-r--r-- | net/sched/cls_matchall.c | 21 | ||||
-rw-r--r-- | net/sched/cls_route.c | 23 | ||||
-rw-r--r-- | net/sched/cls_rsvp.h | 20 | ||||
-rw-r--r-- | net/sched/cls_tcindex.c | 41 | ||||
-rw-r--r-- | net/sched/cls_u32.c | 37 |
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 | ||
35 | struct tcf_block_cb; | 35 | struct tcf_block_cb; |
36 | bool tcf_queue_work(struct work_struct *work); | 36 | bool tcf_queue_work(struct rcu_work *rwork, work_func_t func); |
37 | 37 | ||
38 | #ifdef CONFIG_NET_CLS | 38 | #ifdef CONFIG_NET_CLS |
39 | struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, | 39 | struct 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 | } |
104 | EXPORT_SYMBOL(unregister_tcf_proto_ops); | 104 | EXPORT_SYMBOL(unregister_tcf_proto_ops); |
105 | 105 | ||
106 | bool tcf_queue_work(struct work_struct *work) | 106 | bool 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 | } |
110 | EXPORT_SYMBOL(tcf_queue_work); | 111 | EXPORT_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 | ||
44 | static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 41 | static 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 | ||
98 | static void basic_delete_filter_work(struct work_struct *work) | 95 | static 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 | ||
107 | static 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 | |||
115 | static void basic_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) | 105 | static 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 | ||
58 | static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = { | 55 | static 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 | ||
276 | static void cls_bpf_delete_prog_work(struct work_struct *work) | 273 | static 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 | ||
285 | static 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 | |||
293 | static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog, | 283 | static 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 | ||
32 | static int cls_cgroup_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 29 | static 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 | ||
71 | static void cls_cgroup_destroy_work(struct work_struct *work) | 68 | static 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 | ||
81 | static 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 | |||
91 | static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, | 78 | static 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; |
140 | errout: | 127 | errout: |
@@ -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 | ||
66 | static inline u32 addr_fold(void *addr) | 63 | static inline u32 addr_fold(void *addr) |
@@ -383,21 +380,14 @@ static void __flow_destroy_filter(struct flow_filter *f) | |||
383 | 380 | ||
384 | static void flow_destroy_filter_work(struct work_struct *work) | 381 | static 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 | ||
393 | static 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 | |||
401 | static int flow_change(struct net *net, struct sk_buff *in_skb, | 391 | static 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 { | |||
73 | struct cls_fl_head { | 73 | struct 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 | ||
236 | static void fl_destroy_filter_work(struct work_struct *work) | 230 | static 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 | ||
245 | static 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 | |||
253 | static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f, | 240 | static 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 | ||
337 | static void fl_destroy_sleepable(struct work_struct *work) | 324 | static 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 | ||
345 | static 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 | |||
353 | static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) | 333 | static 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 | ||
371 | static void *fl_get(struct tcf_proto *tp, u32 handle) | 351 | static 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 | ||
56 | static u32 fw_hash(u32 handle) | 53 | static u32 fw_hash(u32 handle) |
@@ -134,21 +131,14 @@ static void __fw_delete_filter(struct fw_filter *f) | |||
134 | 131 | ||
135 | static void fw_delete_filter_work(struct work_struct *work) | 132 | static 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 | ||
144 | static 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 | |||
152 | static void fw_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) | 142 | static 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 | ||
30 | static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 27 | static 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 | ||
54 | static void mall_destroy_work(struct work_struct *work) | 51 | static 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 | ||
63 | static 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 | |||
72 | static void mall_destroy_hw_filter(struct tcf_proto *tp, | 61 | static 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 | ||
267 | static void route4_delete_filter_work(struct work_struct *work) | 264 | static 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 | ||
276 | static void route4_delete_filter(struct rcu_head *head) | 274 | static 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 | ||
284 | static void route4_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) | 279 | static 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 | ||
106 | static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid) | 103 | static 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 | ||
295 | static void rsvp_delete_filter_work(struct work_struct *work) | 292 | static 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 | ||
304 | static 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 | |||
312 | static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f) | 302 | static 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 @@ | |||
28 | struct tcindex_filter_result { | 28 | struct 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 | ||
37 | struct tcindex_filter { | 34 | struct 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 | ||
161 | static 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 | |||
170 | static void __tcindex_destroy_fexts(struct tcindex_filter *f) | 157 | static 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 | ||
177 | static void tcindex_destroy_fexts_work(struct work_struct *work) | 164 | static 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 | ||
187 | static 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 | |||
196 | static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last, | 175 | static 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 | */ |
437 | static void u32_delete_key_work(struct work_struct *work) | 434 | static 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 | ||
446 | static 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 | */ |
461 | static void u32_delete_key_freepf_work(struct work_struct *work) | 451 | static 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 | ||
470 | static 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 | |||
478 | static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) | 461 | static 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 | ||