Bluetooth: Add debug logs to help track locking issues
[cascardo/linux.git] / net / bluetooth / l2cap_sock.c
index 31f106e..b0efb72 100644 (file)
@@ -285,6 +285,12 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
        sk->sk_max_ack_backlog = backlog;
        sk->sk_ack_backlog = 0;
 
+       /* Listening channels need to use nested locking in order not to
+        * cause lockdep warnings when the created child channels end up
+        * being locked in the same thread as the parent channel.
+        */
+       atomic_set(&chan->nesting, L2CAP_NESTING_PARENT);
+
        chan->state = BT_LISTEN;
        sk->sk_state = BT_LISTEN;
 
@@ -301,7 +307,7 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock,
        long timeo;
        int err = 0;
 
-       lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
+       lock_sock_nested(sk, L2CAP_NESTING_PARENT);
 
        timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
 
@@ -333,7 +339,7 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock,
 
                release_sock(sk);
                timeo = schedule_timeout(timeo);
-               lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
+               lock_sock_nested(sk, L2CAP_NESTING_PARENT);
        }
        __set_current_state(TASK_RUNNING);
        remove_wait_queue(sk_sleep(sk), &wait);
@@ -1096,6 +1102,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
        chan = l2cap_pi(sk)->chan;
        conn = chan->conn;
 
+       BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
+
        if (conn)
                mutex_lock(&conn->chan_lock);
 
@@ -1153,12 +1161,16 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
 {
        struct sock *sk;
 
-       BT_DBG("parent %p", parent);
+       BT_DBG("parent %p state %s", parent,
+              state_to_string(parent->sk_state));
 
        /* Close not yet accepted channels */
        while ((sk = bt_accept_dequeue(parent, NULL))) {
                struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 
+               BT_DBG("child chan %p state %s", chan,
+                      state_to_string(chan->state));
+
                l2cap_chan_lock(chan);
                __clear_chan_timer(chan);
                l2cap_chan_close(chan, ECONNRESET);
@@ -1246,7 +1258,16 @@ static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
        struct sock *sk = chan->data;
        struct sock *parent;
 
-       lock_sock(sk);
+       BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
+
+       /* This callback can be called both for server (BT_LISTEN)
+        * sockets as well as "normal" ones. To avoid lockdep warnings
+        * with child socket locking (through l2cap_sock_cleanup_listen)
+        * we need separation into separate nesting levels. The simplest
+        * way to accomplish this is to inherit the nesting level used
+        * for the channel.
+        */
+       lock_sock_nested(sk, atomic_read(&chan->nesting));
 
        parent = bt_sk(sk)->parent;