aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hci_conn.c
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-04-06 14:28:38 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2013-04-17 01:38:36 -0400
commitfc225c3f5d1b6aa6f99c5c300af4605e4923ce79 (patch)
tree15abcbd5495d423c3634af6b518e1f5ff2c22f84 /net/bluetooth/hci_conn.c
parent93796fa6f21411dab2ce7ba4fd7fd4d4ed4aca2e (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_conn.c')
-rw-r--r--net/bluetooth/hci_conn.c17
1 files changed, 1 insertions, 16 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index b1a02ce39a20..6b5b8e77cf0b 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -410,8 +410,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
410 if (hdev->notify) 410 if (hdev->notify)
411 hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); 411 hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
412 412
413 atomic_set(&conn->devref, 0);
414
415 hci_conn_init_sysfs(conn); 413 hci_conn_init_sysfs(conn);
416 414
417 return conn; 415 return conn;
@@ -460,7 +458,7 @@ int hci_conn_del(struct hci_conn *conn)
460 458
461 skb_queue_purge(&conn->data_q); 459 skb_queue_purge(&conn->data_q);
462 460
463 hci_conn_put_device(conn); 461 hci_conn_del_sysfs(conn);
464 462
465 hci_dev_put(hdev); 463 hci_dev_put(hdev);
466 464
@@ -847,19 +845,6 @@ void hci_conn_check_pending(struct hci_dev *hdev)
847 hci_dev_unlock(hdev); 845 hci_dev_unlock(hdev);
848} 846}
849 847
850void hci_conn_hold_device(struct hci_conn *conn)
851{
852 atomic_inc(&conn->devref);
853}
854EXPORT_SYMBOL(hci_conn_hold_device);
855
856void hci_conn_put_device(struct hci_conn *conn)
857{
858 if (atomic_dec_and_test(&conn->devref))
859 hci_conn_del_sysfs(conn);
860}
861EXPORT_SYMBOL(hci_conn_put_device);
862
863int hci_get_conn_list(void __user *arg) 848int hci_get_conn_list(void __user *arg)
864{ 849{
865 struct hci_conn *c; 850 struct hci_conn *c;