Bluetooth: Release locks before sleeping for L2CAP socket shutdown
If there are unacknowledged frames during an ongoing L2CAP transfer and if socket is shutdown, it will result in deadlock as locks are not released before going to sleep. The L2CAP receive thread will be waiting on locks to update unacknowledged frame count, whereas socket shutdown thread will be sleeping till unacknowledged count becomes 0 resulting in deadlock. Change-Id: Id54c04afc4cd0d2adeb2fa69149a701fc4062ad2 Signed-off-by: Rupesh Tatiya <rtatiya@codeaurora.org>
This commit is contained in:
parent
7a7dca4023
commit
ac699ff0c3
|
@ -1877,13 +1877,21 @@ done:
|
|||
int __l2cap_wait_ack(struct sock *sk)
|
||||
{
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
struct l2cap_conn *conn;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int err = 0;
|
||||
int timeo = HZ/5;
|
||||
|
||||
add_wait_queue(sk_sleep(sk), &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
while (chan->unacked_frames > 0 && chan->conn) {
|
||||
|
||||
conn = chan->conn;
|
||||
if (conn)
|
||||
mutex_lock(&conn->chan_lock);
|
||||
l2cap_chan_lock(chan);
|
||||
lock_sock(sk);
|
||||
|
||||
while (chan->unacked_frames > 0 && conn) {
|
||||
if (!timeo)
|
||||
timeo = HZ/5;
|
||||
|
||||
|
@ -1893,14 +1901,29 @@ int __l2cap_wait_ack(struct sock *sk)
|
|||
}
|
||||
|
||||
release_sock(sk);
|
||||
l2cap_chan_unlock(chan);
|
||||
if (conn)
|
||||
mutex_unlock(&conn->chan_lock);
|
||||
|
||||
timeo = schedule_timeout(timeo);
|
||||
|
||||
if (conn)
|
||||
mutex_lock(&conn->chan_lock);
|
||||
l2cap_chan_lock(chan);
|
||||
lock_sock(sk);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
err = sock_error(sk);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
l2cap_chan_unlock(chan);
|
||||
if (conn)
|
||||
mutex_unlock(&conn->chan_lock);
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(sk_sleep(sk), &wait);
|
||||
return err;
|
||||
|
|
|
@ -882,9 +882,20 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
|
|||
lock_sock(sk);
|
||||
|
||||
if (!sk->sk_shutdown) {
|
||||
if (chan->mode == L2CAP_MODE_ERTM)
|
||||
if (chan->mode == L2CAP_MODE_ERTM) {
|
||||
release_sock(sk);
|
||||
l2cap_chan_unlock(chan);
|
||||
if (conn)
|
||||
mutex_unlock(&conn->chan_lock);
|
||||
|
||||
err = __l2cap_wait_ack(sk);
|
||||
|
||||
if (conn)
|
||||
mutex_lock(&conn->chan_lock);
|
||||
l2cap_chan_lock(chan);
|
||||
lock_sock(sk);
|
||||
}
|
||||
|
||||
sk->sk_shutdown = SHUTDOWN_MASK;
|
||||
|
||||
release_sock(sk);
|
||||
|
|
Loading…
Reference in New Issue