diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/bluetooth/l2cap_core.c | 25 | ||||
| -rw-r--r-- | net/bluetooth/l2cap_sock.c | 13 |
2 files changed, 36 insertions, 2 deletions
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); |
