diff options
| author | Peter Hurley <peter@hurleysoftware.com> | 2015-01-23 12:16:53 -0500 | 
|---|---|---|
| committer | Johan Hedberg <johan.hedberg@intel.com> | 2015-01-23 20:29:42 +0200 | 
| commit | dfb2fae7cd0a1aa13610b11d54203bcd3893da07 (patch) | |
| tree | 3aa293285c349233441ae31661c72773992e603e /net/bluetooth | |
| parent | a1443f5a273713d4bfda360e45aa6e1d14fe7324 (diff) | |
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 <condition> set?
                                  | no
set <condition>                   |
                                  |
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 <condition> 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 <peter@hurleysoftware.com>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'net/bluetooth')
| -rw-r--r-- | net/bluetooth/l2cap_sock.c | 9 | ||||
| -rw-r--r-- | net/bluetooth/rfcomm/sock.c | 9 | ||||
| -rw-r--r-- | net/bluetooth/sco.c | 8 | 
3 files changed, 11 insertions, 15 deletions
| 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) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index d8a95755a8a8..3c6d2c8ac1a4 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -468,7 +468,7 @@ done:  static int rfcomm_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; @@ -487,8 +487,6 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f  	/* 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; @@ -509,10 +507,11 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f  		}  		release_sock(sk); -		timeo = schedule_timeout(timeo); + +		timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo); +  		lock_sock_nested(sk, SINGLE_DEPTH_NESTING);  	} -	__set_current_state(TASK_RUNNING);  	remove_wait_queue(sk_sleep(sk), &wait);  	if (err) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 07ec7d23b843..76321b546e84 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -618,7 +618,7 @@ done:  static int sco_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, *ch;  	long timeo;  	int err = 0; @@ -632,8 +632,6 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag  	/* 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; @@ -654,10 +652,10 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag  		}  		release_sock(sk); -		timeo = schedule_timeout(timeo); + +		timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);  		lock_sock(sk);  	} -	__set_current_state(TASK_RUNNING);  	remove_wait_queue(sk_sleep(sk), &wait);  	if (err) | 
