summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeitor Alves de Siqueira <halves@igalia.com>2026-05-26 16:50:58 +0300
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2026-05-28 15:52:21 +0300
commit525daaea459fc215f432de1b8debbd9144bf97b0 (patch)
tree8d69068986506793426f55e5901ca6b7ba46cca0
parent40b87657200cfae93e48904fd9c9c8fc3e192cae (diff)
downloadlinux-525daaea459fc215f432de1b8debbd9144bf97b0.tar.xz
Bluetooth: hci_sync: Set HCI_CMD_DRAIN_WORKQUEUE during device close
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>
-rw-r--r--net/bluetooth/hci_sync.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 1faf8df6d159..0f016d269c62 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -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));