]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Bluetooth: hci_sync: Set HCI_CMD_DRAIN_WORKQUEUE during device close
authorHeitor Alves de Siqueira <halves@igalia.com>
Tue, 26 May 2026 13:50:58 +0000 (10:50 -0300)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 28 May 2026 12:52:21 +0000 (08:52 -0400)
Since hci_dev_close_sync() can now be called during the reset path, we
should also set HCI_CMD_DRAIN_WORKQUEUE. This avoids queuing timeouts
while the hdev workqueue is being drained.

Fixes: 877afadad2dc ("Bluetooth: When HCI work queue is drained, only queue chained work")
Signed-off-by: Heitor Alves de Siqueira <halves@igalia.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/hci_sync.c

index 1faf8df6d159d04c044c8b920f86e9261b7b0796..0f016d269c6224d1651fb05d12599abd408fc739 100644 (file)
@@ -5301,6 +5301,12 @@ int hci_dev_close_sync(struct hci_dev *hdev)
 
        bt_dev_dbg(hdev, "");
 
+       /* Set HCI_DRAIN_WORKQUEUE flag to prevent queuing work during
+        * reset/close. See hci_cmd_work() and handle_cmd_cnt_and_timer().
+        */
+       hci_dev_set_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
+       synchronize_rcu();
+
        if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
                disable_delayed_work(&hdev->power_off);
                disable_delayed_work(&hdev->ncmd_timer);
@@ -5324,6 +5330,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
 
        if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
                cancel_delayed_work_sync(&hdev->cmd_timer);
+               hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
                return err;
        }
 
@@ -5423,6 +5430,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
        /* Clear flags */
        hdev->flags &= BIT(HCI_RAW);
        hci_dev_clear_volatile_flags(hdev);
+       hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
 
        memset(hdev->eir, 0, sizeof(hdev->eir));
        memset(hdev->dev_class, 0, sizeof(hdev->dev_class));