Bluetooth: Lock sockets when closing HCI device
When a Bluetooth device is powered down while RFCOMM connections are
open, there are race conditions where RFCOMM tries to use an HCI
connection after the data structures have been deleted. Since the
powerdown procedure runs in process context, it is possible to lock
sockets before accessing them to close connections. This change adds
that locking, which will serialize socket access between processors
during powerdown.
Change-Id: I587720799b35d9ee6e66340bdeda8a2b9e2ea7b5
CRs-fixed: 336893
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 4c2bd37..c0eb50c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -626,7 +626,7 @@
return ret;
}
-static int hci_dev_do_close(struct hci_dev *hdev)
+static int hci_dev_do_close(struct hci_dev *hdev, u8 is_process)
{
unsigned long keepflags = 0;
@@ -647,7 +647,7 @@
hci_dev_lock_bh(hdev);
inquiry_cache_flush(hdev);
- hci_conn_hash_flush(hdev);
+ hci_conn_hash_flush(hdev, is_process);
hci_dev_unlock_bh(hdev);
hci_notify(hdev, HCI_DEV_DOWN);
@@ -714,7 +714,7 @@
hdev = hci_dev_get(dev);
if (!hdev)
return -ENODEV;
- err = hci_dev_do_close(hdev);
+ err = hci_dev_do_close(hdev, 1);
hci_dev_put(hdev);
return err;
}
@@ -740,7 +740,7 @@
hci_dev_lock_bh(hdev);
inquiry_cache_flush(hdev);
- hci_conn_hash_flush(hdev);
+ hci_conn_hash_flush(hdev, 0);
hci_dev_unlock_bh(hdev);
if (hdev->flush)
@@ -953,7 +953,7 @@
if (!blocked)
return 0;
- hci_dev_do_close(hdev);
+ hci_dev_do_close(hdev, 0);
return 0;
}
@@ -1563,7 +1563,7 @@
list_del(&hdev->list);
write_unlock_bh(&hci_dev_list_lock);
- hci_dev_do_close(hdev);
+ hci_dev_do_close(hdev, 0);
for (i = 0; i < NUM_REASSEMBLY; i++)
kfree_skb(hdev->reassembly[i]);