mirror of https://gitee.com/openkylin/linux.git
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
|
@ -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 New Issue