mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
UPSTREAM: Bluetooth: hci_sync: add lock to protect HCI_UNREGISTER
[ Upstream commit1857c19941] 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:0b94f2651f("Bluetooth: hci_sync: Fix queuing commands when HCI_UNREGISTER is set") Change-Id: I565a2ad87dc2ce4fd62ee0d09a5d28342fec8ad3 Signed-off-by: Zhengping Jiang <jiangzp@google.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Signed-off-by: Sasha Levin <sashal@kernel.org> (cherry picked from commit17aac12002) Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
committed by
Carlos Llamas
parent
855c5479cb
commit
d890debdaf
@@ -514,6 +514,7 @@ struct hci_dev {
|
|||||||
struct work_struct cmd_sync_work;
|
struct work_struct cmd_sync_work;
|
||||||
struct list_head cmd_sync_work_list;
|
struct list_head cmd_sync_work_list;
|
||||||
struct mutex cmd_sync_work_lock;
|
struct mutex cmd_sync_work_lock;
|
||||||
|
struct mutex unregister_lock;
|
||||||
struct work_struct cmd_sync_cancel_work;
|
struct work_struct cmd_sync_cancel_work;
|
||||||
struct work_struct reenable_adv_work;
|
struct work_struct reenable_adv_work;
|
||||||
|
|
||||||
|
|||||||
@@ -2685,7 +2685,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
|
|||||||
{
|
{
|
||||||
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
|
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
|
||||||
|
|
||||||
|
mutex_lock(&hdev->unregister_lock);
|
||||||
hci_dev_set_flag(hdev, HCI_UNREGISTER);
|
hci_dev_set_flag(hdev, HCI_UNREGISTER);
|
||||||
|
mutex_unlock(&hdev->unregister_lock);
|
||||||
|
|
||||||
write_lock(&hci_dev_list_lock);
|
write_lock(&hci_dev_list_lock);
|
||||||
list_del(&hdev->list);
|
list_del(&hdev->list);
|
||||||
|
|||||||
@@ -629,6 +629,7 @@ void hci_cmd_sync_init(struct hci_dev *hdev)
|
|||||||
INIT_WORK(&hdev->cmd_sync_work, hci_cmd_sync_work);
|
INIT_WORK(&hdev->cmd_sync_work, hci_cmd_sync_work);
|
||||||
INIT_LIST_HEAD(&hdev->cmd_sync_work_list);
|
INIT_LIST_HEAD(&hdev->cmd_sync_work_list);
|
||||||
mutex_init(&hdev->cmd_sync_work_lock);
|
mutex_init(&hdev->cmd_sync_work_lock);
|
||||||
|
mutex_init(&hdev->unregister_lock);
|
||||||
|
|
||||||
INIT_WORK(&hdev->cmd_sync_cancel_work, hci_cmd_sync_cancel_work);
|
INIT_WORK(&hdev->cmd_sync_cancel_work, hci_cmd_sync_cancel_work);
|
||||||
INIT_WORK(&hdev->reenable_adv_work, reenable_adv);
|
INIT_WORK(&hdev->reenable_adv_work, reenable_adv);
|
||||||
@@ -688,14 +689,19 @@ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
|
|||||||
void *data, hci_cmd_sync_work_destroy_t destroy)
|
void *data, hci_cmd_sync_work_destroy_t destroy)
|
||||||
{
|
{
|
||||||
struct hci_cmd_sync_work_entry *entry;
|
struct hci_cmd_sync_work_entry *entry;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
|
mutex_lock(&hdev->unregister_lock);
|
||||||
return -ENODEV;
|
if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
|
||||||
|
err = -ENODEV;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
|
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
|
||||||
if (!entry)
|
if (!entry) {
|
||||||
return -ENOMEM;
|
err = -ENOMEM;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
entry->func = func;
|
entry->func = func;
|
||||||
entry->data = data;
|
entry->data = data;
|
||||||
entry->destroy = destroy;
|
entry->destroy = destroy;
|
||||||
@@ -706,7 +712,9 @@ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
|
|||||||
|
|
||||||
queue_work(hdev->req_workqueue, &hdev->cmd_sync_work);
|
queue_work(hdev->req_workqueue, &hdev->cmd_sync_work);
|
||||||
|
|
||||||
return 0;
|
unlock:
|
||||||
|
mutex_unlock(&hdev->unregister_lock);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(hci_cmd_sync_queue);
|
EXPORT_SYMBOL(hci_cmd_sync_queue);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user