diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/sched/cls_flower.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index b480d7c792ba..5b5722c8b32c 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c | |||
@@ -87,7 +87,10 @@ struct cls_fl_filter { | |||
87 | struct list_head list; | 87 | struct list_head list; |
88 | u32 handle; | 88 | u32 handle; |
89 | u32 flags; | 89 | u32 flags; |
90 | struct rcu_head rcu; | 90 | union { |
91 | struct work_struct work; | ||
92 | struct rcu_head rcu; | ||
93 | }; | ||
91 | struct net_device *hw_dev; | 94 | struct net_device *hw_dev; |
92 | }; | 95 | }; |
93 | 96 | ||
@@ -215,12 +218,22 @@ static int fl_init(struct tcf_proto *tp) | |||
215 | return 0; | 218 | return 0; |
216 | } | 219 | } |
217 | 220 | ||
218 | static void fl_destroy_filter(struct rcu_head *head) | 221 | static void fl_destroy_filter_work(struct work_struct *work) |
219 | { | 222 | { |
220 | struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu); | 223 | struct cls_fl_filter *f = container_of(work, struct cls_fl_filter, work); |
221 | 224 | ||
225 | rtnl_lock(); | ||
222 | tcf_exts_destroy(&f->exts); | 226 | tcf_exts_destroy(&f->exts); |
223 | kfree(f); | 227 | kfree(f); |
228 | rtnl_unlock(); | ||
229 | } | ||
230 | |||
231 | static void fl_destroy_filter(struct rcu_head *head) | ||
232 | { | ||
233 | struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu); | ||
234 | |||
235 | INIT_WORK(&f->work, fl_destroy_filter_work); | ||
236 | tcf_queue_work(&f->work); | ||
224 | } | 237 | } |
225 | 238 | ||
226 | static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f) | 239 | static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f) |