From dfb2fae7cd0a1aa13610b11d54203bcd3893da07 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Fri, 23 Jan 2015 12:16:53 -0500 Subject: Bluetooth: Fix nested sleeps l2cap/rfcomm/sco_sock_accept() are wait loops which may acquire sleeping locks. Since both wait loops and sleeping locks use task_struct.state to sleep and wake, the nested sleeping locks destroy the wait loop state. Use the newly-minted wait_woken() and DEFINE_WAIT_FUNC() for the wait loop. DEFINE_WAIT_FUNC() allows an alternate wake function to be specified; in this case, the predefined scheduler function, woken_wake_function(). This wait construct ensures wakeups will not be missed without requiring the wait loop to set the task state before condition evaluation. How this works: CPU 0 | CPU 1 | | is set? | no set | | wake_up_interruptible | woken_wake_function | set WQ_FLAG_WOKEN | try_to_wake_up | | wait_woken | set TASK_INTERRUPTIBLE | WQ_FLAG_WOKEN? yes | set TASK_RUNNING | | - loop - | | is set? | yes - exit wait loop Fixes "do not call blocking ops when !TASK_RUNNING" warnings in l2cap_sock_accept(), rfcomm_sock_accept() and sco_sock_accept(). Signed-off-by: Peter Hurley Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_sock.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 20206cd3acbc..60694f0f4c73 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -302,7 +302,7 @@ done: static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags) { - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT_FUNC(wait, woken_wake_function); struct sock *sk = sock->sk, *nsk; long timeo; int err = 0; @@ -316,8 +316,6 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, /* Wait for an incoming connection. (wake-one). */ add_wait_queue_exclusive(sk_sleep(sk), &wait); while (1) { - set_current_state(TASK_INTERRUPTIBLE); - if (sk->sk_state != BT_LISTEN) { err = -EBADFD; break; @@ -338,10 +336,11 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, } release_sock(sk); - timeo = schedule_timeout(timeo); + + timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo); + lock_sock_nested(sk, L2CAP_NESTING_PARENT); } - __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); if (err) -- cgit