Skip to content

Commit 1857c19

Browse files
Zhengping JiangVudentz
authored andcommitted
Bluetooth: hci_sync: add lock to protect HCI_UNREGISTER
When the HCI_UNREGISTER flag is set, no jobs should be scheduled. Fix potential race when HCI_UNREGISTER is set after the flag is tested in hci_cmd_sync_queue. Fixes: 0b94f26 ("Bluetooth: hci_sync: Fix queuing commands when HCI_UNREGISTER is set") Signed-off-by: Zhengping Jiang <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent c5d2b6f commit 1857c19

File tree

3 files changed

+17
-6
lines changed

3 files changed

+17
-6
lines changed

include/net/bluetooth/hci_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ struct hci_dev {
515515
struct work_struct cmd_sync_work;
516516
struct list_head cmd_sync_work_list;
517517
struct mutex cmd_sync_work_lock;
518+
struct mutex unregister_lock;
518519
struct work_struct cmd_sync_cancel_work;
519520
struct work_struct reenable_adv_work;
520521

net/bluetooth/hci_core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2686,7 +2686,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
26862686
{
26872687
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
26882688

2689+
mutex_lock(&hdev->unregister_lock);
26892690
hci_dev_set_flag(hdev, HCI_UNREGISTER);
2691+
mutex_unlock(&hdev->unregister_lock);
26902692

26912693
write_lock(&hci_dev_list_lock);
26922694
list_del(&hdev->list);

net/bluetooth/hci_sync.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ void hci_cmd_sync_init(struct hci_dev *hdev)
629629
INIT_WORK(&hdev->cmd_sync_work, hci_cmd_sync_work);
630630
INIT_LIST_HEAD(&hdev->cmd_sync_work_list);
631631
mutex_init(&hdev->cmd_sync_work_lock);
632+
mutex_init(&hdev->unregister_lock);
632633

633634
INIT_WORK(&hdev->cmd_sync_cancel_work, hci_cmd_sync_cancel_work);
634635
INIT_WORK(&hdev->reenable_adv_work, reenable_adv);
@@ -692,14 +693,19 @@ int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
692693
void *data, hci_cmd_sync_work_destroy_t destroy)
693694
{
694695
struct hci_cmd_sync_work_entry *entry;
696+
int err = 0;
695697

696-
if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
697-
return -ENODEV;
698+
mutex_lock(&hdev->unregister_lock);
699+
if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
700+
err = -ENODEV;
701+
goto unlock;
702+
}
698703

699704
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
700-
if (!entry)
701-
return -ENOMEM;
702-
705+
if (!entry) {
706+
err = -ENOMEM;
707+
goto unlock;
708+
}
703709
entry->func = func;
704710
entry->data = data;
705711
entry->destroy = destroy;
@@ -710,7 +716,9 @@ int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
710716

711717
queue_work(hdev->req_workqueue, &hdev->cmd_sync_work);
712718

713-
return 0;
719+
unlock:
720+
mutex_unlock(&hdev->unregister_lock);
721+
return err;
714722
}
715723
EXPORT_SYMBOL(hci_cmd_sync_submit);
716724

0 commit comments

Comments
 (0)