Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da1b3e65 authored by Rupesh Tatiya's avatar Rupesh Tatiya
Browse files

Bluetooth: Release locks before sleeping for L2CAP socket shutdown



If there are unacknowledged frames during an L2CAP transfer and if we
do not release locks, it will result in deadlock. The L2CAP receive
thread will be waiting on locks to update unacknowledged frame count
and release thread will be sleeping till unacknowledged count becomes 0.

Change-Id: Id54c04afc4cd0d2adeb2fa69149a701fc4062ad2
Signed-off-by: default avatarRupesh Tatiya <rtatiya@codeaurora.org>
parent 53d2912c
Loading
Loading
Loading
Loading
+36 −2
Original line number Diff line number Diff line
@@ -1052,13 +1052,21 @@ static void l2cap_sock_kill(struct sock *sk)
static 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;

@@ -1068,14 +1076,29 @@ static 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;
@@ -1103,9 +1126,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);