aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2015-03-28 05:17:36 -0400
committerMarcel Holtmann <marcel@holtmann.org>2015-03-28 15:05:11 -0400
commit600b21507eb64bcd85bb87d06c2c2c451b565f02 (patch)
tree74e5e9ab26ecd95f15ad855c3026800b424e6889 /net/bluetooth
parent6331c686e664909988ecc35b040e1e96c137f5e0 (diff)
Bluetooth: Fix race condition with HCI_RESET flag
During the HCI init phase a completed request might be the last part of the setup procedure after which the actual init procedure starts. The init procedure begins with a call to hci_reset_req() which sets the HCI_RESET flag. The purpose of this flag is to make us ignore any updates to ncmd/cmd_cnt as long as we haven't received the command complete event for the HCI_Reset. There's a potential race with this however: hci_req_cmd_complete(hdev, opcode, status); if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) queue_work(hdev->workqueue, &hdev->cmd_work); } Since the hci_req_cmd_complete() will trigger the completion of the setup stage, it's possible that hci_reset_req() gets called before we try to read ev->ncmd and the HCI_RESET flag. Because of this the cmd_cnt would never be updated and the hci_reset_req() in practice ends up blocking itself. This patch fixes the issue by updating cmd_cnt before notifying the request completion, and then reading it again to determine whether the cmd_work should be queued or not. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hci_event.c20
1 files changed, 10 insertions, 10 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 62f92a508961..3ac23964e108 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3027,13 +3027,13 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
3027 if (opcode != HCI_OP_NOP) 3027 if (opcode != HCI_OP_NOP)
3028 cancel_delayed_work(&hdev->cmd_timer); 3028 cancel_delayed_work(&hdev->cmd_timer);
3029 3029
3030 if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags))
3031 atomic_set(&hdev->cmd_cnt, 1);
3032
3030 hci_req_cmd_complete(hdev, opcode, status); 3033 hci_req_cmd_complete(hdev, opcode, status);
3031 3034
3032 if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { 3035 if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q))
3033 atomic_set(&hdev->cmd_cnt, 1); 3036 queue_work(hdev->workqueue, &hdev->cmd_work);
3034 if (!skb_queue_empty(&hdev->cmd_q))
3035 queue_work(hdev->workqueue, &hdev->cmd_work);
3036 }
3037} 3037}
3038 3038
3039static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) 3039static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -3122,15 +3122,15 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
3122 if (opcode != HCI_OP_NOP) 3122 if (opcode != HCI_OP_NOP)
3123 cancel_delayed_work(&hdev->cmd_timer); 3123 cancel_delayed_work(&hdev->cmd_timer);
3124 3124
3125 if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags))
3126 atomic_set(&hdev->cmd_cnt, 1);
3127
3125 if (ev->status || 3128 if (ev->status ||
3126 (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req_event)) 3129 (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req_event))
3127 hci_req_cmd_complete(hdev, opcode, ev->status); 3130 hci_req_cmd_complete(hdev, opcode, ev->status);
3128 3131
3129 if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { 3132 if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q))
3130 atomic_set(&hdev->cmd_cnt, 1); 3133 queue_work(hdev->workqueue, &hdev->cmd_work);
3131 if (!skb_queue_empty(&hdev->cmd_q))
3132 queue_work(hdev->workqueue, &hdev->cmd_work);
3133 }
3134} 3134}
3135 3135
3136static void hci_hardware_error_evt(struct hci_dev *hdev, struct sk_buff *skb) 3136static void hci_hardware_error_evt(struct hci_dev *hdev, struct sk_buff *skb)