diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2016-11-28 06:22:12 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-29 19:48:38 -0500 |
commit | 707693c8a498697aa8db240b93eb76ec62e30892 (patch) | |
tree | a9ee8933c07cfc86afc74436d39a26c8beaff683 /net | |
parent | 95c2027bfeda21a28eb245121e6a249f38d0788e (diff) |
netlink: Call cb->done from a worker thread
The cb->done interface expects to be called in process context.
This was broken by the netlink RCU conversion. This patch fixes
it by adding a worker struct to make the cb->done call where
necessary.
Fixes: 21e4902aea80 ("netlink: Lockless lookup with RCU grace...")
Reported-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Acked-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/netlink/af_netlink.c | 27 | ||||
-rw-r--r-- | net/netlink/af_netlink.h | 2 |
2 files changed, 25 insertions, 4 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 62bea4591054..602e5ebe9db3 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -322,14 +322,11 @@ static void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) | |||
322 | sk_mem_charge(sk, skb->truesize); | 322 | sk_mem_charge(sk, skb->truesize); |
323 | } | 323 | } |
324 | 324 | ||
325 | static void netlink_sock_destruct(struct sock *sk) | 325 | static void __netlink_sock_destruct(struct sock *sk) |
326 | { | 326 | { |
327 | struct netlink_sock *nlk = nlk_sk(sk); | 327 | struct netlink_sock *nlk = nlk_sk(sk); |
328 | 328 | ||
329 | if (nlk->cb_running) { | 329 | if (nlk->cb_running) { |
330 | if (nlk->cb.done) | ||
331 | nlk->cb.done(&nlk->cb); | ||
332 | |||
333 | module_put(nlk->cb.module); | 330 | module_put(nlk->cb.module); |
334 | kfree_skb(nlk->cb.skb); | 331 | kfree_skb(nlk->cb.skb); |
335 | } | 332 | } |
@@ -346,6 +343,28 @@ static void netlink_sock_destruct(struct sock *sk) | |||
346 | WARN_ON(nlk_sk(sk)->groups); | 343 | WARN_ON(nlk_sk(sk)->groups); |
347 | } | 344 | } |
348 | 345 | ||
346 | static void netlink_sock_destruct_work(struct work_struct *work) | ||
347 | { | ||
348 | struct netlink_sock *nlk = container_of(work, struct netlink_sock, | ||
349 | work); | ||
350 | |||
351 | nlk->cb.done(&nlk->cb); | ||
352 | __netlink_sock_destruct(&nlk->sk); | ||
353 | } | ||
354 | |||
355 | static void netlink_sock_destruct(struct sock *sk) | ||
356 | { | ||
357 | struct netlink_sock *nlk = nlk_sk(sk); | ||
358 | |||
359 | if (nlk->cb_running && nlk->cb.done) { | ||
360 | INIT_WORK(&nlk->work, netlink_sock_destruct_work); | ||
361 | schedule_work(&nlk->work); | ||
362 | return; | ||
363 | } | ||
364 | |||
365 | __netlink_sock_destruct(sk); | ||
366 | } | ||
367 | |||
349 | /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on | 368 | /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on |
350 | * SMP. Look, when several writers sleep and reader wakes them up, all but one | 369 | * SMP. Look, when several writers sleep and reader wakes them up, all but one |
351 | * immediately hit write lock and grab all the cpus. Exclusive sleep solves | 370 | * immediately hit write lock and grab all the cpus. Exclusive sleep solves |
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index 3cfd6cc60504..4fdb38318977 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <linux/rhashtable.h> | 4 | #include <linux/rhashtable.h> |
5 | #include <linux/atomic.h> | 5 | #include <linux/atomic.h> |
6 | #include <linux/workqueue.h> | ||
6 | #include <net/sock.h> | 7 | #include <net/sock.h> |
7 | 8 | ||
8 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) | 9 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) |
@@ -33,6 +34,7 @@ struct netlink_sock { | |||
33 | 34 | ||
34 | struct rhash_head node; | 35 | struct rhash_head node; |
35 | struct rcu_head rcu; | 36 | struct rcu_head rcu; |
37 | struct work_struct work; | ||
36 | }; | 38 | }; |
37 | 39 | ||
38 | static inline struct netlink_sock *nlk_sk(struct sock *sk) | 40 | static inline struct netlink_sock *nlk_sk(struct sock *sk) |