Skip to content

Commit 7986cae

Browse files
joerchannashif
authored andcommitted
Bluetooth: host: Remove cancel sync from database hash commit
Fix deadlock when db_hash_commit has to wait for the delayed work to finish. This creates a deadlock if the delayed work for database hash calculation needs to store the hash since the settings API is locked when calling the commit callback. Remove call to k_work_cancel_delayable_sync from db_hash_commit in order to avoid the deadlock. Instead move comparing of the stored hash to the delayed work and reschedule the work with no wait. Signed-off-by: Joakim Andersson <[email protected]>
1 parent 46efe3e commit 7986cae

File tree

1 file changed

+47
-35
lines changed

1 file changed

+47
-35
lines changed

subsys/bluetooth/host/gatt.c

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ enum {
229229

230230
#if defined(CONFIG_BT_GATT_CACHING)
231231
DB_HASH_VALID, /* Database hash needs to be calculated */
232+
DB_HASH_LOAD, /* Database hash loaded from settings. */
232233
#endif
233234
/* Total number of flags - must be at the end of the enum */
234235
SC_NUM_FLAGS,
@@ -248,6 +249,9 @@ static struct gatt_sc {
248249
#if defined(CONFIG_BT_GATT_CACHING)
249250
static struct db_hash {
250251
uint8_t hash[16];
252+
#if defined(CONFIG_BT_SETTINGS)
253+
uint8_t stored_hash[16];
254+
#endif
251255
struct k_work_delayable work;
252256
struct k_work_sync sync;
253257
} db_hash;
@@ -719,8 +723,44 @@ static void db_hash_gen(bool store)
719723
atomic_set_bit(gatt_sc.flags, DB_HASH_VALID);
720724
}
721725

726+
#if defined(CONFIG_BT_SETTINGS)
727+
static void sc_indicate(uint16_t start, uint16_t end);
728+
#endif
729+
722730
static void db_hash_process(struct k_work *work)
723731
{
732+
#if defined(CONFIG_BT_SETTINGS)
733+
if (atomic_test_and_clear_bit(gatt_sc.flags, DB_HASH_LOAD)) {
734+
if (!atomic_test_bit(gatt_sc.flags, DB_HASH_VALID)) {
735+
db_hash_gen(false);
736+
}
737+
738+
/* Check if hash matches then skip SC update */
739+
if (!memcmp(db_hash.stored_hash, db_hash.hash,
740+
sizeof(db_hash.stored_hash))) {
741+
BT_DBG("Database Hash matches");
742+
k_work_cancel_delayable(&gatt_sc.work);
743+
atomic_clear_bit(gatt_sc.flags, SC_RANGE_CHANGED);
744+
return;
745+
}
746+
747+
BT_HEXDUMP_DBG(db_hash.hash, sizeof(db_hash.hash),
748+
"New Hash: ");
749+
750+
/* GATT database has been modified since last boot, likely due
751+
* to a firmware update or a dynamic service that was not
752+
* re-registered on boot.
753+
* Indicate Service Changed to all bonded devices for the full
754+
* database range to invalidate client-side cache and force
755+
* discovery on reconnect.
756+
*/
757+
sc_indicate(0x0001, 0xffff);
758+
759+
/* Hash did not match, overwrite with current hash */
760+
db_hash_store();
761+
return;
762+
}
763+
#endif /* defined(CONFIG_BT_SETTINGS) */
724764
db_hash_gen(true);
725765
}
726766

@@ -5147,58 +5187,30 @@ static int cf_set(const char *name, size_t len_rd, settings_read_cb read_cb,
51475187

51485188
SETTINGS_STATIC_HANDLER_DEFINE(bt_cf, "bt/cf", NULL, cf_set, NULL, NULL);
51495189

5150-
static uint8_t stored_hash[16];
5151-
51525190
static int db_hash_set(const char *name, size_t len_rd,
51535191
settings_read_cb read_cb, void *cb_arg)
51545192
{
51555193
ssize_t len;
51565194

5157-
len = read_cb(cb_arg, stored_hash, sizeof(stored_hash));
5195+
len = read_cb(cb_arg, db_hash.stored_hash, sizeof(db_hash.stored_hash));
51585196
if (len < 0) {
51595197
BT_ERR("Failed to decode value (err %zd)", len);
51605198
return len;
51615199
}
51625200

5163-
BT_HEXDUMP_DBG(stored_hash, sizeof(stored_hash), "Stored Hash: ");
5201+
BT_HEXDUMP_DBG(db_hash.stored_hash, sizeof(db_hash.stored_hash),
5202+
"Stored Hash: ");
51645203

51655204
return 0;
51665205
}
51675206

51685207
static int db_hash_commit(void)
51695208
{
5170-
5171-
k_sched_lock();
5172-
5173-
/* Stop work and generate the hash */
5174-
(void)k_work_cancel_delayable_sync(&db_hash.work, &db_hash.sync);
5175-
if (!atomic_test_bit(gatt_sc.flags, DB_HASH_VALID)) {
5176-
db_hash_gen(false);
5177-
}
5178-
5179-
k_sched_unlock();
5180-
5181-
/* Check if hash matches then skip SC update */
5182-
if (!memcmp(stored_hash, db_hash.hash, sizeof(stored_hash))) {
5183-
BT_DBG("Database Hash matches");
5184-
k_work_cancel_delayable(&gatt_sc.work);
5185-
atomic_clear_bit(gatt_sc.flags, SC_RANGE_CHANGED);
5186-
return 0;
5187-
}
5188-
5189-
BT_HEXDUMP_DBG(db_hash.hash, sizeof(db_hash.hash), "New Hash: ");
5190-
5191-
/**
5192-
* GATT database has been modified since last boot, likely due to
5193-
* a firmware update or a dynamic service that was not re-registered on
5194-
* boot. Indicate Service Changed to all bonded devices for the full
5195-
* database range to invalidate client-side cache and force discovery on
5196-
* reconnect.
5209+
atomic_set_bit(gatt_sc.flags, DB_HASH_LOAD);
5210+
/* Reschedule work to calculate and compare against the Hash value
5211+
* loaded from flash.
51975212
*/
5198-
sc_indicate(0x0001, 0xffff);
5199-
5200-
/* Hash did not match overwrite with current hash */
5201-
db_hash_store();
5213+
k_work_reschedule(&db_hash.work, K_NO_WAIT);
52025214

52035215
return 0;
52045216
}

0 commit comments

Comments
 (0)