net/bluetooth/hci_core.c | 6 ++++++ net/bluetooth/hci_sync.c | 22 ++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-)
From: zhangchen <zhangchen01@kylinos.cn>
If hci_resume_dev before hci_unregister_dev, the hci command will
timeout and the reference count of hdev will not reset to zero.
Then the node "hci0" will not release.
The output in question is as follows:
[ 3391.553518][ 7] [T247244] Bluetooth: hci0: command 0x0c01 tx timeout
[ 3391.553588][ 7] [T264732] Bluetooth: hci0: Opcode 0x0c01 failed: -110
[ 3393.569514][ 3] [T247244] Bluetooth: hci0: command 0x0c01 tx timeout
[ 3393.569515][ 3] [T264732] Bluetooth: hci0: Opcode 0x0c1a failed: -110
[ 3393.709645][ 6] [T104579] usb 10-1: new full-speed USB device number 95 using xhci-hcd
[ 3393.862194][ 6] [T104579] usb 10-1: New USB device found, idVendor=13d3, idProduct=3570, bcdDevice= 0.00
[ 3393.862205][ 6] [T104579] usb 10-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 3393.862208][ 6] [T104579] usb 10-1: Product: Bluetooth Radio
[ 3393.862210][ 6] [T104579] usb 10-1: Manufacturer: Realtek
[ 3393.862212][ 6] [T104579] usb 10-1: SerialNumber: 00e04c000001
[ 3393.867589][ 6] [T247244] Bluetooth: hci1: RTL: examining hci_ver=0b hci_rev=000b lmp_ver=0b lmp_subver=8852
[ 3393.868573][ 6] [T247244] Bluetooth: hci1: RTL: rom_version status=0 version=1
[ 3393.868583][ 6] [T247244] Bluetooth: hci1: RTL: loading rtl_bt/rtl8852bu_fw.bin
[ 3393.868672][ 6] [T247244] Bluetooth: hci1: RTL: loading rtl_bt/rtl8852bu_config.bin
[ 3393.869699][ 6] [T247244] Bluetooth: hci1: RTL: cfg_sz 6, total sz 65603
The call sequence in question is as follows:
usb disconnect:
btusb_disconnect
hci_unregister_dev
hci_dev_set_flag
hci_cmd_sync_clear
hci_unregister_suspend_notifier
hci_dev_do_close
device_del
device resume:
hci_suspend_notifier
hci_resume_dev
hci_resume_sync
hci_set_event_mask_sync
__hci_cmd_sync_status
__hci_cmd_sync_status_sk
__hci_cmd_sync_sk
wait_event_interruptible_timeout
The output after adding debug information in question is as follows:
[ 6378.366215][ 6] [T434033] hci_resume_dev hci name hci0
[ 6378.366218][ 6] [T434033] hci_resume_sync set event mask sync
[ 6378.366219][ 6] [T434033] hci_set_event_mask_sync
[ 6378.366220][ 6] [T434033] __hci_cmd_sync_sk hci name hci0 Opcode 0x0c01
[ 6378.366227][ 6] [T434033] __hci_cmd_sync_sk wait event interruptible timeout
[ 6378.367632][ 6] [T420012] btusb_disconnect intf 0000000024117fc1
[ 6378.367637][ 6] [T420012] btusb_disconnect hci_unregister_dev
[ 6378.367638][ 6] [T420012] hci_unregister_dev 0000000064bfd783 name hci0 bus 1
[ 6378.367641][ 6] [T420012] hci_unregister_dev set flag
[ 6378.367804][ 6] [T420012] hci_unregister_dev cmd sync clear
[ 6378.367807][ 6] [T420012] hci_unregister_dev unregister suspend notifier
[ 6380.367544][ 6] [T434033] __hci_cmd_sync_sk cmd timeout
[ 6380.367542][ 6] [T197498] Bluetooth: hci0: command 0x0c01 tx timeout
[ 6380.367550][ 6] [T434033] __hci_cmd_sync_sk hci0 end: err -110
[ 6380.367552][ 6] [T434033] Bluetooth: hci0: Opcode 0x0c01 failed: -110
[ 6380.367555][ 6] [T434033] hci_resume_sync clear event filter
[ 6380.367556][ 6] [T434033] hci_resume_sync resume scan sync
[ 6380.367558][ 6] [T434033] __hci_cmd_sync_sk hci name hci0 Opcode 0x0c1a
[ 6380.367561][ 6] [T434033] __hci_cmd_sync_sk wait event interruptible timeout
[ 6382.383538][ 6] [T197498] Bluetooth: hci0: command 0x0c01 tx timeout
[ 6382.383593][ 6] [T434033] __hci_cmd_sync_sk hci0 end: err -110
[ 6382.383597][ 6] [T434033] Bluetooth: hci0: Opcode 0x0c1a failed: -110
The output after adding debug information in normal is as follows:
[50.039156][ 6] [ T8360] btusb_disconnect intf 00000000fca35842
[50.039160][ 6] [ T8360] btusb_disconnect hci_unregister_dev
[50.039162][ 6] [ T8360] hci_unregister_dev 000000002422b946 name hci0 bus 1
[50.039164][ 6] [ T8360] hci_unregister_dev set flag
[50.039224][ 6] [ T8360] hci_unregister_dev cmd sync clear
[50.039227][ 5] [ T8360] hci_unregister_dev unregister suspend notifier
[50.043542][ 5] [ T8284] hci_resume_dev hci name hci0
This patch add hci_cancel_cmd_sync in hci_unregister_dev to wake up
hdev->req_wait_q, and stop __hci_cmd_sync_sk by judging the
HCI_UNREGISTER flag. Then stopping hci_resume_dev process based on the
returned error code.
Fixes: 182ee45da083 ("Bluetooth: hci_sync: Rework hci_suspend_notifier")
Cc: stable@vger.kernel.org
Signed-off-by: zhangchen <zhangchen01@kylinos.cn>
---
net/bluetooth/hci_core.c | 6 ++++++
net/bluetooth/hci_sync.c | 22 ++++++++++++++++------
2 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 3418d7b964a1..c977bcba3e76 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -50,6 +50,7 @@
static void hci_rx_work(struct work_struct *work);
static void hci_cmd_work(struct work_struct *work);
static void hci_tx_work(struct work_struct *work);
+static void hci_cancel_cmd_sync(struct hci_dev *hdev, int err);
/* HCI device list */
LIST_HEAD(hci_dev_list);
@@ -2695,6 +2696,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_dev_set_flag(hdev, HCI_UNREGISTER);
mutex_unlock(&hdev->unregister_lock);
+ hci_cancel_cmd_sync(hdev, EINTR);
+
write_lock(&hci_dev_list_lock);
list_del(&hdev->list);
write_unlock(&hci_dev_list_lock);
@@ -2877,6 +2880,9 @@ int hci_resume_dev(struct hci_dev *hdev)
ret = hci_resume_sync(hdev);
hci_req_sync_unlock(hdev);
+ if (ret && hci_dev_test_flag(hdev, HCI_UNREGISTER))
+ return 0;
+
mgmt_resuming(hdev, hdev->wake_reason, &hdev->wake_addr,
hdev->wake_addr_type);
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 6e76798ec786..f48d34fbfff2 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -174,10 +174,11 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
return ERR_PTR(err);
err = wait_event_interruptible_timeout(hdev->req_wait_q,
- hdev->req_status != HCI_REQ_PEND,
+ hdev->req_status != HCI_REQ_PEND ||
+ hci_dev_test_flag(hdev, HCI_UNREGISTER),
timeout);
- if (err == -ERESTARTSYS)
+ if (err == -ERESTARTSYS || hci_dev_test_flag(hdev, HCI_UNREGISTER))
return ERR_PTR(-EINTR);
switch (hdev->req_status) {
@@ -6296,6 +6297,7 @@ static int hci_resume_scan_sync(struct hci_dev *hdev)
*/
int hci_resume_sync(struct hci_dev *hdev)
{
+ int err;
/* If not marked as suspended there nothing to do */
if (!hdev->suspended)
return 0;
@@ -6303,10 +6305,14 @@ int hci_resume_sync(struct hci_dev *hdev)
hdev->suspended = false;
/* Restore event mask */
- hci_set_event_mask_sync(hdev);
+ err = hci_set_event_mask_sync(hdev);
+ if (err && hci_dev_test_flag(hdev, HCI_UNREGISTER))
+ return err;
/* Clear any event filters and restore scan state */
- hci_clear_event_filter_sync(hdev);
+ err = hci_clear_event_filter_sync(hdev);
+ if (err && hci_dev_test_flag(hdev, HCI_UNREGISTER))
+ return err;
/* Resume scanning */
hci_resume_scan_sync(hdev);
@@ -6315,10 +6321,14 @@ int hci_resume_sync(struct hci_dev *hdev)
hci_resume_monitor_sync(hdev);
/* Resume other advertisements */
- hci_resume_advertising_sync(hdev);
+ err = hci_resume_advertising_sync(hdev);
+ if (err && hci_dev_test_flag(hdev, HCI_UNREGISTER))
+ return err;
/* Resume discovery */
- hci_resume_discovery_sync(hdev);
+ err = hci_resume_discovery_sync(hdev);
+ if (err && hci_dev_test_flag(hdev, HCI_UNREGISTER))
+ return err;
return 0;
}
--
2.25.1
© 2016 - 2026 Red Hat, Inc.