aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_flow.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/cls_flow.c')
-rw-r--r--net/sched/cls_flow.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 2a3a60ec5b86..67f3a2af6aab 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -57,7 +57,10 @@ struct flow_filter {
57 u32 divisor; 57 u32 divisor;
58 u32 baseclass; 58 u32 baseclass;
59 u32 hashrnd; 59 u32 hashrnd;
60 struct rcu_head rcu; 60 union {
61 struct work_struct work;
62 struct rcu_head rcu;
63 };
61}; 64};
62 65
63static inline u32 addr_fold(void *addr) 66static inline u32 addr_fold(void *addr)
@@ -369,14 +372,24 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
369 [TCA_FLOW_PERTURB] = { .type = NLA_U32 }, 372 [TCA_FLOW_PERTURB] = { .type = NLA_U32 },
370}; 373};
371 374
372static void flow_destroy_filter(struct rcu_head *head) 375static void flow_destroy_filter_work(struct work_struct *work)
373{ 376{
374 struct flow_filter *f = container_of(head, struct flow_filter, rcu); 377 struct flow_filter *f = container_of(work, struct flow_filter, work);
375 378
379 rtnl_lock();
376 del_timer_sync(&f->perturb_timer); 380 del_timer_sync(&f->perturb_timer);
377 tcf_exts_destroy(&f->exts); 381 tcf_exts_destroy(&f->exts);
378 tcf_em_tree_destroy(&f->ematches); 382 tcf_em_tree_destroy(&f->ematches);
379 kfree(f); 383 kfree(f);
384 rtnl_unlock();
385}
386
387static void flow_destroy_filter(struct rcu_head *head)
388{
389 struct flow_filter *f = container_of(head, struct flow_filter, rcu);
390
391 INIT_WORK(&f->work, flow_destroy_filter_work);
392 tcf_queue_work(&f->work);
380} 393}
381 394
382static int flow_change(struct net *net, struct sk_buff *in_skb, 395static int flow_change(struct net *net, struct sk_buff *in_skb,