Bluetooth: Lock the L2CAP channel when sending
authorMat Martineau <mathewm@codeaurora.org>
Fri, 4 May 2012 21:20:31 +0000 (14:20 -0700)
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>
Wed, 16 May 2012 19:14:02 +0000 (16:14 -0300)
The ERTM and streaming mode transmit queue must only be accessed while
the L2CAP channel lock is held.  Locking the channel before calling
l2cap_chan_send ensures that multiple threads cannot simultaneously
manipulate the queue when sending and receiving concurrently.

L2CAP channel locking had previously moved to the l2cap_chan struct
instead of the associated socket, so some of the old socket locking
can also be removed in this patch.

Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
Signed-off-by: Gustavo Padovan <gustavo@padovan.org>
include/net/bluetooth/bluetooth.h
net/bluetooth/l2cap_sock.c

index c34a9a6..7981ca4 100644 (file)
@@ -257,12 +257,10 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk,
 {
        struct sk_buff *skb;
 
-       release_sock(sk);
        if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) {
                skb_reserve(skb, BT_SKB_RESERVE);
                bt_cb(skb)->incoming  = 0;
        }
-       lock_sock(sk);
 
        if (!skb && *err)
                return NULL;
index b7bc7b9..f6d8e13 100644 (file)
@@ -720,16 +720,13 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
        if (msg->msg_flags & MSG_OOB)
                return -EOPNOTSUPP;
 
-       lock_sock(sk);
-
-       if (sk->sk_state != BT_CONNECTED) {
-               release_sock(sk);
+       if (sk->sk_state != BT_CONNECTED)
                return -ENOTCONN;
-       }
 
+       l2cap_chan_lock(chan);
        err = l2cap_chan_send(chan, msg, len, sk->sk_priority);
+       l2cap_chan_unlock(chan);
 
-       release_sock(sk);
        return err;
 }
 
@@ -940,7 +937,10 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
        struct sk_buff *skb;
        int err;
 
+       l2cap_chan_unlock(chan);
        skb = bt_skb_send_alloc(chan->sk, len, nb, &err);
+       l2cap_chan_lock(chan);
+
        if (!skb)
                return ERR_PTR(err);