Bluetooth: Avoid deadlock in management ops code
Fixes a deadlock issue due to spinlock being acquired
first in the process context and followed by a second
acquisition in the interrupt context
CRs-fixed: 319052
Change-Id: If17be9fa6f020dd1abd248f8999c2614251fc509
Signed-off-by: Subramanian Srinivasan <subrsrin@codeaurora.org>
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 6e5d9fc..4a976a9 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -208,7 +208,7 @@
hci_del_off_timer(hdev);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
set_bit(HCI_MGMT, &hdev->flags);
@@ -237,7 +237,7 @@
memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
@@ -377,7 +377,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
up = test_bit(HCI_UP, &hdev->flags);
if ((cp->val && up) || (!cp->val && !up)) {
@@ -404,7 +404,7 @@
err = 0;
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
}
@@ -467,7 +467,7 @@
return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
@@ -521,7 +521,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -547,7 +547,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
@@ -582,7 +582,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -608,7 +608,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
@@ -642,7 +642,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -703,7 +703,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (cp->val)
set_bit(HCI_PAIRABLE, &hdev->flags);
@@ -719,7 +719,7 @@
err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -887,7 +887,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
if (!uuid) {
@@ -911,7 +911,7 @@
err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -936,7 +936,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
err = hci_uuids_clear(hdev);
@@ -971,7 +971,7 @@
err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
unlock:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -995,7 +995,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
hdev->major_class &= ~MGMT_MAJOR_CLASS_MASK;
hdev->major_class |= cp->major & MGMT_MAJOR_CLASS_MASK;
@@ -1006,7 +1006,7 @@
if (err == 0)
err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1028,7 +1028,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
BT_DBG("hci%u enable %d", index, cp->enable);
@@ -1046,7 +1046,7 @@
err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
0);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1080,7 +1080,7 @@
BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
key_count);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
hci_link_keys_clear(hdev);
@@ -1118,7 +1118,7 @@
err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1140,7 +1140,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
err = hci_remove_link_key(hdev, &cp->bdaddr);
if (err < 0) {
@@ -1163,7 +1163,7 @@
}
unlock:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1189,7 +1189,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
@@ -1225,7 +1225,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1246,7 +1246,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
count = 0;
list_for_each(p, &hdev->conn_hash.list) {
@@ -1277,7 +1277,7 @@
unlock:
kfree(rp);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
}
@@ -1302,7 +1302,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
@@ -1324,7 +1324,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1409,7 +1409,7 @@
return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
@@ -1430,7 +1430,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1453,14 +1453,14 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
hdev->io_capability = cp->io_capability;
BT_DBG("%s IO capability set to 0x%02x", hdev->name,
hdev->io_capability);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
@@ -1600,7 +1600,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
BT_DBG("SSP Cap is %d", cp->ssp_cap);
io_cap = cp->io_cap;
@@ -1655,7 +1655,7 @@
err = 0;
unlock:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1685,7 +1685,7 @@
if (!hdev)
return cmd_status(sk, index, mgmt_op, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, mgmt_op, ENETDOWN);
@@ -1711,7 +1711,7 @@
mgmt_pending_remove(cmd);
done:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1735,7 +1735,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
if (!cmd) {
@@ -1751,7 +1751,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1776,7 +1776,7 @@
return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
if (!conn) {
@@ -1793,7 +1793,7 @@
err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1817,7 +1817,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
if (!cmd) {
@@ -1832,7 +1832,7 @@
mgmt_pending_remove(cmd);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1883,9 +1883,6 @@
hdev = hci_dev_get(index);
- if (hdev)
- hci_dev_lock(hdev);
-
if (!hdev || !lmp_le_capable(hdev)) {
struct mgmt_mode cp = {0};
@@ -1919,7 +1916,6 @@
discovery_terminated, NULL);
done:
- hci_dev_unlock(hdev);
hci_dev_put(hdev);
}
@@ -1935,7 +1931,7 @@
hdev = hci_dev_get(ilp->index);
if (hdev) {
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
@@ -1960,7 +1956,7 @@
mgmt_pending_remove(cmd);
}
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
}
}
@@ -1977,7 +1973,7 @@
hdev = hci_dev_get(ilp->index);
if (hdev) {
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
@@ -1996,7 +1992,7 @@
} else
ilp->mode = SCAN_IDLE;
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
}
}
@@ -2014,7 +2010,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
if (!cmd) {
@@ -2069,7 +2065,7 @@
}
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -2090,7 +2086,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (lmp_le_capable(hdev)) {
cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
@@ -2124,7 +2120,7 @@
mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
failed:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
if (err < 0)
@@ -2146,7 +2142,7 @@
return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
@@ -2176,7 +2172,7 @@
mgmt_pending_remove(cmd);
unlock:
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -2200,7 +2196,7 @@
return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
cp->randomizer);
@@ -2210,7 +2206,7 @@
err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
0);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -2234,7 +2230,7 @@
return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
ENODEV);
- hci_dev_lock(hdev);
+ hci_dev_lock_bh(hdev);
err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
if (err < 0)
@@ -2244,7 +2240,7 @@
err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
NULL, 0);
- hci_dev_unlock(hdev);
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -2765,9 +2761,7 @@
hdev = hci_dev_get(index);
if (hdev) {
- hci_dev_lock_bh(hdev);
update_eir(hdev);
- hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
}