forked from mirrors/linux
		
	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>
			
			
This commit is contained in:
		
							parent
							
								
									a1443f5a27
								
							
						
					
					
						commit
						dfb2fae7cd
					
				
					 3 changed files with 11 additions and 15 deletions
				
			
		| 
						 | 
				
			
			@ -302,7 +302,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
 | 
			
		|||
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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -468,7 +468,7 @@ static int rfcomm_sock_listen(struct socket *sock, int backlog)
 | 
			
		|||
 | 
			
		||||
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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -618,7 +618,7 @@ static int sco_sock_listen(struct socket *sock, int backlog)
 | 
			
		|||
 | 
			
		||||
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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue