diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2013-04-06 14:28:38 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2013-04-17 01:38:36 -0400 |
commit | fc225c3f5d1b6aa6f99c5c300af4605e4923ce79 (patch) | |
tree | 15abcbd5495d423c3634af6b518e1f5ff2c22f84 /net/bluetooth/hci_event.c | |
parent | 93796fa6f21411dab2ce7ba4fd7fd4d4ed4aca2e (diff) |
Bluetooth: remove unneeded hci_conn_hold/put_device()
hci_conn_hold/put_device() is used to control when hci_conn->dev is no
longer needed and can be deleted from the system. Lets first look how they
are currently used throughout the code (excluding HIDP!).
All code that uses hci_conn_hold_device() looks like this:
...
hci_conn_hold_device();
hci_conn_add_sysfs();
...
On the other side, hci_conn_put_device() is exclusively used in
hci_conn_del().
So, considering that hci_conn_del() must not be called twice (which would
fail horribly), we know that hci_conn_put_device() is only called _once_
(which is in hci_conn_del()).
On the other hand, hci_conn_add_sysfs() must not be called twice, either
(it would call device_add twice, which breaks the device, see
drivers/base/core.c). So we know that hci_conn_hold_device() is also
called only once (it's only called directly before hci_conn_add_sysfs()).
So hold and put are known to be called only once. That means we can safely
remove them and directly call hci_conn_del_sysfs() in hci_conn_del().
But there is one issue left: HIDP also uses hci_conn_hold/put_device().
However, this case can be ignored and simply removed as it is totally
broken. The issue is, the only thing HIDP delays with
hci_conn_hold_device() is the removal of the hci_conn->dev from sysfs.
But, the hci_conn device has no mechanism to get notified when its own
parent (hci_dev) gets removed from sysfs. hci_dev_hold/put() does _not_
control when it is removed but only when the device object is created
and destroyed.
And hci_dev calls hci_conn_flush_*() when it removes itself from sysfs,
which itself causes hci_conn_del() to be called, but it does _not_ cause
hci_conn_del_sysfs() to be called, which is wrong.
Hence, we fix it to call hci_conn_del_sysfs() in hci_conn_del(). This
guarantees that a hci_conn object is removed from sysfs _before_ its
parent hci_dev is removed.
The changes to HIDP look scary, wrong and broken. However, if you look at
the HIDP session management, you will notice they're already broken in the
exact _same_ way (ever tried "unplugging" HIDP devices? Breaks _all_ the
time).
So this patch only makes HIDP look _scary_ and _obviously broken_. It does
not break HIDP itself, it already is!
See later patches in this series which fix HIDP to use proper
session-management.
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/hci_event.c')
-rw-r--r-- | net/bluetooth/hci_event.c | 4 |
1 files changed, 0 insertions, 4 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f6ea3c734269..688c1a9949cc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -1706,7 +1706,6 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
1706 | } else | 1706 | } else |
1707 | conn->state = BT_CONNECTED; | 1707 | conn->state = BT_CONNECTED; |
1708 | 1708 | ||
1709 | hci_conn_hold_device(conn); | ||
1710 | hci_conn_add_sysfs(conn); | 1709 | hci_conn_add_sysfs(conn); |
1711 | 1710 | ||
1712 | if (test_bit(HCI_AUTH, &hdev->flags)) | 1711 | if (test_bit(HCI_AUTH, &hdev->flags)) |
@@ -2987,7 +2986,6 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, | |||
2987 | conn->handle = __le16_to_cpu(ev->handle); | 2986 | conn->handle = __le16_to_cpu(ev->handle); |
2988 | conn->state = BT_CONNECTED; | 2987 | conn->state = BT_CONNECTED; |
2989 | 2988 | ||
2990 | hci_conn_hold_device(conn); | ||
2991 | hci_conn_add_sysfs(conn); | 2989 | hci_conn_add_sysfs(conn); |
2992 | break; | 2990 | break; |
2993 | 2991 | ||
@@ -3452,7 +3450,6 @@ static void hci_phy_link_complete_evt(struct hci_dev *hdev, | |||
3452 | hcon->disc_timeout = HCI_DISCONN_TIMEOUT; | 3450 | hcon->disc_timeout = HCI_DISCONN_TIMEOUT; |
3453 | hci_conn_drop(hcon); | 3451 | hci_conn_drop(hcon); |
3454 | 3452 | ||
3455 | hci_conn_hold_device(hcon); | ||
3456 | hci_conn_add_sysfs(hcon); | 3453 | hci_conn_add_sysfs(hcon); |
3457 | 3454 | ||
3458 | amp_physical_cfm(bredr_hcon, hcon); | 3455 | amp_physical_cfm(bredr_hcon, hcon); |
@@ -3586,7 +3583,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
3586 | conn->handle = __le16_to_cpu(ev->handle); | 3583 | conn->handle = __le16_to_cpu(ev->handle); |
3587 | conn->state = BT_CONNECTED; | 3584 | conn->state = BT_CONNECTED; |
3588 | 3585 | ||
3589 | hci_conn_hold_device(conn); | ||
3590 | hci_conn_add_sysfs(conn); | 3586 | hci_conn_add_sysfs(conn); |
3591 | 3587 | ||
3592 | hci_proto_connect_cfm(conn, ev->status); | 3588 | hci_proto_connect_cfm(conn, ev->status); |