diff options
author | Peter Zijlstra <[email protected]> | 2014-10-29 17:04:56 +0100 |
---|---|---|
committer | Ingo Molnar <[email protected]> | 2014-11-04 07:17:48 +0100 |
commit | ff960a731788a7408b6f66ec4fd772ff18833211 (patch) | |
tree | 081795cb185495198e5966ea171e7701241775f1 | |
parent | eedf7e47daa0b8530246a8c9107c007fbf8231bf (diff) |
netdev, sched/wait: Fix sleeping inside wait event
rtnl_lock_unregistering*() take rtnl_lock() -- a mutex -- inside a
wait loop. The wait loop relies on current->state to function, but so
does mutex_lock(), nesting them makes for the inner to destroy the
outer state.
Fix this using the new wait_woken() bits.
Reported-by: Fengguang Wu <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Acked-by: David S. Miller <[email protected]>
Cc: Oleg Nesterov <[email protected]>
Cc: Cong Wang <[email protected]>
Cc: David Gibson <[email protected]>
Cc: Eric Biederman <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Jamal Hadi Salim <[email protected]>
Cc: Jerry Chu <[email protected]>
Cc: Jiri Pirko <[email protected]>
Cc: John Fastabend <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Nicolas Dichtel <[email protected]>
Cc: [email protected] <[email protected]>
Cc: stephen hemminger <[email protected]>
Cc: Tom Gundersen <[email protected]>
Cc: Tom Herbert <[email protected]>
Cc: Veaceslav Falico <[email protected]>
Cc: Vlad Yasevich <[email protected]>
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
-rw-r--r-- | net/core/dev.c | 10 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 10 |
2 files changed, 10 insertions, 10 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index b793e3521a36..c5a9d73147a6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -7196,11 +7196,10 @@ static void __net_exit rtnl_lock_unregistering(struct list_head *net_list) */ struct net *net; bool unregistering; - DEFINE_WAIT(wait); + DEFINE_WAIT_FUNC(wait, woken_wake_function); + add_wait_queue(&netdev_unregistering_wq, &wait); for (;;) { - prepare_to_wait(&netdev_unregistering_wq, &wait, - TASK_UNINTERRUPTIBLE); unregistering = false; rtnl_lock(); list_for_each_entry(net, net_list, exit_list) { @@ -7212,9 +7211,10 @@ static void __net_exit rtnl_lock_unregistering(struct list_head *net_list) if (!unregistering) break; __rtnl_unlock(); - schedule(); + + wait_woken(&wait, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); } - finish_wait(&netdev_unregistering_wq, &wait); + remove_wait_queue(&netdev_unregistering_wq, &wait); } static void __net_exit default_device_exit_batch(struct list_head *net_list) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index a6882686ca3a..b095296f711f 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -365,11 +365,10 @@ static void rtnl_lock_unregistering_all(void) { struct net *net; bool unregistering; - DEFINE_WAIT(wait); + DEFINE_WAIT_FUNC(wait, woken_wake_function); + add_wait_queue(&netdev_unregistering_wq, &wait); for (;;) { - prepare_to_wait(&netdev_unregistering_wq, &wait, - TASK_UNINTERRUPTIBLE); unregistering = false; rtnl_lock(); for_each_net(net) { @@ -381,9 +380,10 @@ static void rtnl_lock_unregistering_all(void) if (!unregistering) break; __rtnl_unlock(); - schedule(); + + wait_woken(&wait, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); } - finish_wait(&netdev_unregistering_wq, &wait); + remove_wait_queue(&netdev_unregistering_wq, &wait); } /** |