From fd91149633127f41960aa2a8d9b2829cbd7e677f Mon Sep 17 00:00:00 2001 From: Rupesh Tatiya Date: Thu, 30 Apr 2015 16:51:54 +0530 Subject: 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. Signed-off-by: Rupesh Tatiya --- net/bluetooth/l2cap_core.c | 25 ++++++++++++++++++++++++- net/bluetooth/l2cap_sock.c | 13 ++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c90f6ffae..2bb685312 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1874,13 +1874,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; @@ -1890,14 +1898,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; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index eaab0f580..9d7b2ee5e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -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); -- cgit v1.2.3