diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2013-04-06 14:28:44 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2013-04-17 02:02:10 -0400 |
commit | 9c903e373c11f62d62bce1209f662ca92589a075 (patch) | |
tree | 285f6ef70c1e869b7ebd86dcad2a4057ea61134e /net/bluetooth | |
parent | 3764eaa922c78037ad9bed06be5c8b8a5c83b37d (diff) |
Bluetooth: l2cap: introduce l2cap_conn ref-counting
If we want to use l2cap_conn outside of l2cap_core.c, we need refcounting
for these objects. Otherwise, we cannot synchronize l2cap locks with
outside locks and end up with deadlocks.
Hence, introduce ref-counting for l2cap_conn objects. This doesn't affect
l2cap internals at all, as they use a direct synchronization.
We also keep a reference to the parent hci_conn for locking purposes as
l2cap_conn depends on this. This doesn't affect the connection itself but
only the lifetime of the (dead) object.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/l2cap_core.c | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e09b89be1c4d..be9ad89339cd 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -1486,7 +1486,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) | |||
1486 | } | 1486 | } |
1487 | 1487 | ||
1488 | hcon->l2cap_data = NULL; | 1488 | hcon->l2cap_data = NULL; |
1489 | kfree(conn); | 1489 | conn->hchan = NULL; |
1490 | l2cap_conn_put(conn); | ||
1490 | } | 1491 | } |
1491 | 1492 | ||
1492 | static void security_timeout(struct work_struct *work) | 1493 | static void security_timeout(struct work_struct *work) |
@@ -1520,8 +1521,10 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) | |||
1520 | return NULL; | 1521 | return NULL; |
1521 | } | 1522 | } |
1522 | 1523 | ||
1524 | kref_init(&conn->ref); | ||
1523 | hcon->l2cap_data = conn; | 1525 | hcon->l2cap_data = conn; |
1524 | conn->hcon = hcon; | 1526 | conn->hcon = hcon; |
1527 | hci_conn_get(conn->hcon); | ||
1525 | conn->hchan = hchan; | 1528 | conn->hchan = hchan; |
1526 | 1529 | ||
1527 | BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); | 1530 | BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); |
@@ -1558,6 +1561,26 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) | |||
1558 | return conn; | 1561 | return conn; |
1559 | } | 1562 | } |
1560 | 1563 | ||
1564 | static void l2cap_conn_free(struct kref *ref) | ||
1565 | { | ||
1566 | struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref); | ||
1567 | |||
1568 | hci_conn_put(conn->hcon); | ||
1569 | kfree(conn); | ||
1570 | } | ||
1571 | |||
1572 | void l2cap_conn_get(struct l2cap_conn *conn) | ||
1573 | { | ||
1574 | kref_get(&conn->ref); | ||
1575 | } | ||
1576 | EXPORT_SYMBOL(l2cap_conn_get); | ||
1577 | |||
1578 | void l2cap_conn_put(struct l2cap_conn *conn) | ||
1579 | { | ||
1580 | kref_put(&conn->ref, l2cap_conn_free); | ||
1581 | } | ||
1582 | EXPORT_SYMBOL(l2cap_conn_put); | ||
1583 | |||
1561 | /* ---- Socket interface ---- */ | 1584 | /* ---- Socket interface ---- */ |
1562 | 1585 | ||
1563 | /* Find socket with psm and source / destination bdaddr. | 1586 | /* Find socket with psm and source / destination bdaddr. |