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 13:29:42 -0500 |
commit | dfb2fae7cd0a1aa13610b11d54203bcd3893da07 (patch) | |
tree | 3aa293285c349233441ae31661c72773992e603e /net/bluetooth/rfcomm/sock.c | |
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/rfcomm/sock.c')
-rw-r--r-- | net/bluetooth/rfcomm/sock.c | 9 |
1 files changed, 4 insertions, 5 deletions
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: | |||
468 | 468 | ||
469 | static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags) | 469 | static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags) |
470 | { | 470 | { |
471 | DECLARE_WAITQUEUE(wait, current); | 471 | DEFINE_WAIT_FUNC(wait, woken_wake_function); |
472 | struct sock *sk = sock->sk, *nsk; | 472 | struct sock *sk = sock->sk, *nsk; |
473 | long timeo; | 473 | long timeo; |
474 | int err = 0; | 474 | int err = 0; |
@@ -487,8 +487,6 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f | |||
487 | /* Wait for an incoming connection. (wake-one). */ | 487 | /* Wait for an incoming connection. (wake-one). */ |
488 | add_wait_queue_exclusive(sk_sleep(sk), &wait); | 488 | add_wait_queue_exclusive(sk_sleep(sk), &wait); |
489 | while (1) { | 489 | while (1) { |
490 | set_current_state(TASK_INTERRUPTIBLE); | ||
491 | |||
492 | if (sk->sk_state != BT_LISTEN) { | 490 | if (sk->sk_state != BT_LISTEN) { |
493 | err = -EBADFD; | 491 | err = -EBADFD; |
494 | break; | 492 | break; |
@@ -509,10 +507,11 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f | |||
509 | } | 507 | } |
510 | 508 | ||
511 | release_sock(sk); | 509 | release_sock(sk); |
512 | timeo = schedule_timeout(timeo); | 510 | |
511 | timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo); | ||
512 | |||
513 | lock_sock_nested(sk, SINGLE_DEPTH_NESTING); | 513 | lock_sock_nested(sk, SINGLE_DEPTH_NESTING); |
514 | } | 514 | } |
515 | __set_current_state(TASK_RUNNING); | ||
516 | remove_wait_queue(sk_sleep(sk), &wait); | 515 | remove_wait_queue(sk_sleep(sk), &wait); |
517 | 516 | ||
518 | if (err) | 517 | if (err) |