linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/1] device: Fix device recreation after failed restore
       [not found] <d364976e93e23f5defbbf711dcda4787bdad3beb>
@ 2025-08-29  9:48 ` xinpeng.wang
  2025-08-29  9:48   ` [PATCH v2 1/1] device: Recreate paired device from storage " xinpeng.wang
  0 siblings, 1 reply; 3+ messages in thread
From: xinpeng.wang @ 2025-08-29  9:48 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: xinpeng.wang

During S4 suspend/resume stress testing, I observed that some paired
devices disappeared after system resume. This happened because
adapter_create_device() skipped restoring from storage, even if the 
initial restore had failed.

My desktop application treats temporary and paired devices differently,
so the disappearance of paired devices led to a poor user experience.
I believe this is a valid issue that should be addressed.

This patch introduces a list of pending restore addresses. When a
device in this list is created, it will be reloaded from storage to
ensure pairing information is properly restored.

Changes since v1:
- Fix code formatting (checkpatch.pl warnings)
- Align logic with BlueZ's existing restore pattern
- Fix a bug in list handling that could cause double-free

Please review ,thanks.

xinpeng.wang (1):
  device: Recreate paired device from storage after failed restore

 src/adapter.c | 113 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 101 insertions(+), 12 deletions(-)

-- 
2.20.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v2 1/1] device: Recreate paired device from storage after failed restore
  2025-08-29  9:48 ` [PATCH v2 0/1] device: Fix device recreation after failed restore xinpeng.wang
@ 2025-08-29  9:48   ` xinpeng.wang
  2025-08-29 11:10     ` device: Fix device recreation " bluez.test.bot
  0 siblings, 1 reply; 3+ messages in thread
From: xinpeng.wang @ 2025-08-29  9:48 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: xinpeng.wang

When a USB Bluetooth adapter is resumed from S4 suspend, the kernel
may trigger an "index remove" followed by an "index add". BlueZ
responds by removing all devices and attempting to recreate them
from stored configuration (storage).

However, if a connected A2DP device disconnects just before suspend,
BlueZ may have started a disconnect timer (via set_disconnect_timer)
but not yet freed the session. During this period:
- The session pointer is set to NULL and becomes inaccessible.
- The session still holds a reference to the device, preventing it
  from being freed.
- As a result, the "index add" event fails to recreate the device from
  storage (due to D-Bus path conflict or incomplete cleanup).
- Later, when the timer expires, a new device is created from discovery
  data, bypassing storage and causing it to appear as unpaired.

This leads to loss of pairing information and confuses desktop applications
that rely on paired/unpaired state.

This patch enhances the device creation logic: if loading a paired device
from storage previously failed (e.g., due to pending session cleanup), its
address is recorded in the adapter's pending list. Later, when creating a
device from scan data, BlueZ checks this list and re-attempts creation from
storage if matched, ensuring the correct paired state is restored.

This ensures that devices are properly restored after suspend/resume
cycles, even in race conditions involving delayed session cleanup.

Signed-off-by: xinpeng.wang <wangxinpeng@uniontech.com>
---
 src/adapter.c | 113 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 101 insertions(+), 12 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 549a6c0b8..16163d1f5 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -342,6 +342,8 @@ struct btd_adapter {
 
 	struct queue *exp_pending;
 	struct queue *exps;
+
+	GSList *restore_dev_addrs;
 };
 
 static char *adapter_power_state_str(uint32_t power_state)
@@ -1400,17 +1402,7 @@ static void adapter_add_device(struct btd_adapter *adapter,
 
 static struct btd_device *adapter_create_device(struct btd_adapter *adapter,
 						const bdaddr_t *bdaddr,
-						uint8_t bdaddr_type)
-{
-	struct btd_device *device;
-
-	device = device_create(adapter, bdaddr, bdaddr_type);
-	if (!device)
-		return NULL;
-
-	adapter_add_device(adapter, device);
-	return device;
-}
+						uint8_t bdaddr_type);
 
 static void service_auth_cancel(struct service_auth *auth)
 {
@@ -4969,6 +4961,93 @@ done:
 	mgmt_tlv_list_free(list);
 }
 
+static struct btd_device *adapter_create_device(struct btd_adapter *adapter,
+						const bdaddr_t *bdaddr,
+						uint8_t bdaddr_type)
+{
+	struct btd_device *device;
+	char addr[18];
+	GSList *match = NULL;
+	char *match_addr = NULL;
+	GKeyFile *key_file = NULL;
+
+	ba2str(bdaddr, addr);
+
+	match = g_slist_find_custom(adapter->restore_dev_addrs, addr,
+					(GCompareFunc)strcasecmp);
+	if (match) {
+		char filename[PATH_MAX];
+		GError *gerr = NULL;
+		struct link_key_info *key_info;
+		struct smp_ltk_info *ltk_info;
+		struct smp_ltk_info *peripheral_ltk_info;
+		struct irk_info *irk_info;
+
+		create_filename(filename, PATH_MAX, "/%s/%s/info",
+					btd_adapter_get_storage_dir(adapter),
+					addr);
+
+		key_file = g_key_file_new();
+		if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) {
+			error("Unable to load key file from %s: (%s)", filename,
+								gerr->message);
+			g_clear_error(&gerr);
+		}
+
+		DBG("Found device %s but restoring from storage", addr);
+		device = device_create_from_storage(adapter, addr, key_file);
+		if (!device) {
+			g_key_file_free(key_file);
+			return NULL;
+		}
+		match_addr = match->data;
+		adapter->restore_dev_addrs =
+			g_slist_delete_link(adapter->restore_dev_addrs, match);
+		g_free(match_addr);
+
+		if (bdaddr_type == BDADDR_BREDR)
+			device_set_bredr_support(device);
+		else
+			device_set_le_support(device, bdaddr_type);
+
+		key_info = get_key_info(key_file, addr, bdaddr_type);
+		ltk_info = get_ltk_info(key_file, addr, bdaddr_type);
+		peripheral_ltk_info =
+			get_peripheral_ltk_info(key_file, addr, bdaddr_type);
+		irk_info = get_irk_info(key_file, addr, bdaddr_type);
+		if (key_info) {
+			device_set_paired(device, BDADDR_BREDR);
+			device_set_bonded(device, BDADDR_BREDR);
+		}
+		if (ltk_info || peripheral_ltk_info) {
+			struct smp_ltk_info *info;
+
+			info = ltk_info ? ltk_info : peripheral_ltk_info;
+			device_set_paired(device, info->bdaddr_type);
+			device_set_bonded(device, info->bdaddr_type);
+
+			device_set_ltk(device, info->val, info->central,
+					info->enc_size);
+		}
+		if (irk_info)
+			device_set_rpa(device, true);
+
+		btd_device_set_temporary(device, false);
+		g_free(key_info);
+		g_free(ltk_info);
+		g_free(peripheral_ltk_info);
+		g_free(irk_info);
+		g_key_file_free(key_file);
+	} else {
+		device = device_create(adapter, bdaddr, bdaddr_type);
+		if (!device)
+			return NULL;
+	}
+
+	adapter_add_device(adapter, device);
+	return device;
+}
+
 static void load_devices(struct btd_adapter *adapter)
 {
 	char dirname[PATH_MAX];
@@ -5087,8 +5166,15 @@ static void load_devices(struct btd_adapter *adapter)
 
 		device = device_create_from_storage(adapter, entry->d_name,
 							key_file);
-		if (!device)
+		if (!device) {
+			char *addr_copy;
+
+			addr_copy = g_strdup(entry->d_name);
+			adapter->restore_dev_addrs =
+				g_slist_append(adapter->restore_dev_addrs,
+						addr_copy);
 			goto free;
+		}
 
 		if (irk_info)
 			device_set_rpa(device, true);
@@ -7085,6 +7171,9 @@ static void adapter_remove(struct btd_adapter *adapter)
 	adapter->msd_callbacks = NULL;
 
 	queue_remove_all(adapter->exp_pending, NULL, NULL, cancel_exp_pending);
+
+	g_slist_free_full(adapter->restore_dev_addrs, g_free);
+	adapter->restore_dev_addrs = NULL;
 }
 
 const char *adapter_get_path(struct btd_adapter *adapter)
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* RE: device: Fix device recreation after failed restore
  2025-08-29  9:48   ` [PATCH v2 1/1] device: Recreate paired device from storage " xinpeng.wang
@ 2025-08-29 11:10     ` bluez.test.bot
  0 siblings, 0 replies; 3+ messages in thread
From: bluez.test.bot @ 2025-08-29 11:10 UTC (permalink / raw)
  To: linux-bluetooth, wangxinpeng

[-- Attachment #1: Type: text/plain, Size: 1261 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=996842

---Test result---

Test Summary:
CheckPatch                    PENDING   0.30 seconds
GitLint                       PENDING   0.33 seconds
BuildEll                      PASS      19.97 seconds
BluezMake                     PASS      2536.81 seconds
MakeCheck                     PASS      20.07 seconds
MakeDistcheck                 PASS      183.38 seconds
CheckValgrind                 PASS      235.79 seconds
CheckSmatch                   PASS      306.13 seconds
bluezmakeextell               PASS      127.95 seconds
IncrementalBuild              PENDING   0.31 seconds
ScanBuild                     PASS      909.52 seconds

Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:

##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:

##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:



---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-08-29 11:10 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <d364976e93e23f5defbbf711dcda4787bdad3beb>
2025-08-29  9:48 ` [PATCH v2 0/1] device: Fix device recreation after failed restore xinpeng.wang
2025-08-29  9:48   ` [PATCH v2 1/1] device: Recreate paired device from storage " xinpeng.wang
2025-08-29 11:10     ` device: Fix device recreation " bluez.test.bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).