}
 
 /* Find channel with given SCID.
- * Returns locked channel. */
+ * Returns a reference locked channel.
+ */
 static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn,
                                                 u16 cid)
 {
 
        mutex_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_scid(conn, cid);
-       if (c)
-               l2cap_chan_lock(c);
+       if (c) {
+               /* Only lock if chan reference is not 0 */
+               c = l2cap_chan_hold_unless_zero(c);
+               if (c)
+                       l2cap_chan_lock(c);
+       }
        mutex_unlock(&conn->chan_lock);
 
        return c;
 }
 
 /* Find channel with given DCID.
- * Returns locked channel.
+ * Returns a reference locked channel.
  */
 static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
                                                 u16 cid)
 
        mutex_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_dcid(conn, cid);
-       if (c)
-               l2cap_chan_lock(c);
+       if (c) {
+               /* Only lock if chan reference is not 0 */
+               c = l2cap_chan_hold_unless_zero(c);
+               if (c)
+                       l2cap_chan_lock(c);
+       }
        mutex_unlock(&conn->chan_lock);
 
        return c;
 
        mutex_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_ident(conn, ident);
-       if (c)
-               l2cap_chan_lock(c);
+       if (c) {
+               /* Only lock if chan reference is not 0 */
+               c = l2cap_chan_hold_unless_zero(c);
+               if (c)
+                       l2cap_chan_lock(c);
+       }
        mutex_unlock(&conn->chan_lock);
 
        return c;
        kref_get(&c->kref);
 }
 
+struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c)
+{
+       BT_DBG("chan %p orig refcnt %u", c, kref_read(&c->kref));
+
+       if (!kref_get_unless_zero(&c->kref))
+               return NULL;
+
+       return c;
+}
+
 void l2cap_chan_put(struct l2cap_chan *c)
 {
        BT_DBG("chan %p orig refcnt %u", c, kref_read(&c->kref));
                        src_match = !bacmp(&c->src, src);
                        dst_match = !bacmp(&c->dst, dst);
                        if (src_match && dst_match) {
-                               l2cap_chan_hold(c);
+                               c = l2cap_chan_hold_unless_zero(c);
+                               if (!c)
+                                       continue;
+
                                read_unlock(&chan_list_lock);
                                return c;
                        }
        }
 
        if (c1)
-               l2cap_chan_hold(c1);
+               c1 = l2cap_chan_hold_unless_zero(c1);
 
        read_unlock(&chan_list_lock);
 
 
 unlock:
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
        return err;
 }
 
 
 done:
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
        return err;
 }
 
        l2cap_send_move_chan_rsp(chan, result);
 
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 
        return 0;
 }
        }
 
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 }
 
 static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid,
        l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
 
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 }
 
 static int l2cap_move_channel_rsp(struct l2cap_conn *conn,
        l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
 
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 
        return 0;
 }
        }
 
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 
        return 0;
 }
        if (credits > max_credits) {
                BT_ERR("LE credits overflow");
                l2cap_send_disconn_req(chan, ECONNRESET);
-               l2cap_chan_unlock(chan);
 
                /* Return 0 so that we don't trigger an unnecessary
                 * command reject packet.
                 */
-               return 0;
+               goto unlock;
        }
 
        chan->tx_credits += credits;
        if (chan->tx_credits)
                chan->ops->resume(chan);
 
+unlock:
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 
        return 0;
 }
 
 done:
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 }
 
 static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
                if (src_type != c->src_type)
                        continue;
 
-               l2cap_chan_hold(c);
+               c = l2cap_chan_hold_unless_zero(c);
                read_unlock(&chan_list_lock);
                return c;
        }