diff options
author | Cong Wang <xiyou.wangcong@gmail.com> | 2017-10-26 21:24:34 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-10-29 09:49:31 -0400 |
commit | e071dff2a6beeccb6f9744f9a0251ab773ca2ab8 (patch) | |
tree | 28ddec66cf18004c8c8ce9bff76e78e70c3a6600 /net | |
parent | 0552c8afa077889b4704ef5ee88b03063ad45023 (diff) |
net_sched: use tcf_queue_work() in fw filter
Defer the tcf_exts_destroy() in RCU callback to
tc filter workqueue and get RTNL lock.
Reported-by: Chris Mi <chrism@mellanox.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Jiri Pirko <jiri@resnulli.us>
Cc: John Fastabend <john.fastabend@gmail.com>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/sched/cls_fw.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 941245ad07fd..99183b8621ec 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c | |||
@@ -46,7 +46,10 @@ struct fw_filter { | |||
46 | #endif /* CONFIG_NET_CLS_IND */ | 46 | #endif /* CONFIG_NET_CLS_IND */ |
47 | struct tcf_exts exts; | 47 | struct tcf_exts exts; |
48 | struct tcf_proto *tp; | 48 | struct tcf_proto *tp; |
49 | struct rcu_head rcu; | 49 | union { |
50 | struct work_struct work; | ||
51 | struct rcu_head rcu; | ||
52 | }; | ||
50 | }; | 53 | }; |
51 | 54 | ||
52 | static u32 fw_hash(u32 handle) | 55 | static u32 fw_hash(u32 handle) |
@@ -119,12 +122,22 @@ static int fw_init(struct tcf_proto *tp) | |||
119 | return 0; | 122 | return 0; |
120 | } | 123 | } |
121 | 124 | ||
122 | static void fw_delete_filter(struct rcu_head *head) | 125 | static void fw_delete_filter_work(struct work_struct *work) |
123 | { | 126 | { |
124 | struct fw_filter *f = container_of(head, struct fw_filter, rcu); | 127 | struct fw_filter *f = container_of(work, struct fw_filter, work); |
125 | 128 | ||
129 | rtnl_lock(); | ||
126 | tcf_exts_destroy(&f->exts); | 130 | tcf_exts_destroy(&f->exts); |
127 | kfree(f); | 131 | kfree(f); |
132 | rtnl_unlock(); | ||
133 | } | ||
134 | |||
135 | static void fw_delete_filter(struct rcu_head *head) | ||
136 | { | ||
137 | struct fw_filter *f = container_of(head, struct fw_filter, rcu); | ||
138 | |||
139 | INIT_WORK(&f->work, fw_delete_filter_work); | ||
140 | tcf_queue_work(&f->work); | ||
128 | } | 141 | } |
129 | 142 | ||
130 | static void fw_destroy(struct tcf_proto *tp) | 143 | static void fw_destroy(struct tcf_proto *tp) |