Skip to content

Commit 333fadd

Browse files
rghaddabfabiobaltieri
authored andcommitted
settings: zms: fix some bugs related to the name's ID
To avoid collisions between IDs used by settings and IDs used directly by subsystems using ZMS API, the MSB is always set to 1 for Setting's name ID written to ZMS backend Add as well a recovery path if the hash linked list is broken. Signed-off-by: Riadh Ghaddab <rghaddab@baylibre.com>
1 parent 91cf42c commit 333fadd

File tree

2 files changed

+36
-24
lines changed

2 files changed

+36
-24
lines changed

subsys/settings/include/settings/settings_zms.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,9 @@ extern "C" {
6060
#define ZMS_COLLISIONS_MASK GENMASK(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS, 1)
6161
#define ZMS_HASH_TOTAL_MASK GENMASK(29, 1)
6262
#define ZMS_MAX_COLLISIONS (BIT(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS) - 1)
63-
#define ZMS_HEADER_HASH 0x80000000
6463

6564
/* some useful macros */
66-
#define ZMS_NAME_HASH_ID(x) (x & ZMS_HASH_TOTAL_MASK)
65+
#define ZMS_NAME_ID_FROM_LL_NODE(x) (x & ~BIT(0))
6766
#define ZMS_UPDATE_COLLISION_NUM(x, y) \
6867
((x & ~ZMS_COLLISIONS_MASK) | ((y << 1) & ZMS_COLLISIONS_MASK))
6968
#define ZMS_COLLISION_NUM(x) ((x & ZMS_COLLISIONS_MASK) >> 1)

subsys/settings/src/settings_zms.c

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ static int settings_zms_load(struct settings_store *cs, const struct settings_lo
3030
static int settings_zms_save(struct settings_store *cs, const char *name, const char *value,
3131
size_t val_len);
3232
static void *settings_zms_storage_get(struct settings_store *cs);
33+
static int settings_zms_get_last_hash_ids(struct settings_zms *cf);
3334

3435
static struct settings_store_itf settings_zms_itf = {.csi_load = settings_zms_load,
3536
.csi_save = settings_zms_save,
@@ -169,18 +170,19 @@ static int settings_zms_load(struct settings_store *cs, const struct settings_lo
169170
* entries one for the setting's name and one with the
170171
* setting's value.
171172
*/
172-
rc1 = zms_read(&cf->cf_zms, ZMS_NAME_HASH_ID(ll_hash_id), &name, sizeof(name) - 1);
173+
rc1 = zms_read(&cf->cf_zms, ZMS_NAME_ID_FROM_LL_NODE(ll_hash_id), &name,
174+
sizeof(name) - 1);
173175
/* get the length of data and verify that it exists */
174-
rc2 = zms_get_data_length(&cf->cf_zms,
175-
ZMS_NAME_HASH_ID(ll_hash_id) + ZMS_DATA_ID_OFFSET);
176+
rc2 = zms_get_data_length(&cf->cf_zms, ZMS_NAME_ID_FROM_LL_NODE(ll_hash_id) +
177+
ZMS_DATA_ID_OFFSET);
176178

177179
if ((rc1 <= 0) || (rc2 <= 0)) {
178180
/* Settings item is not stored correctly in the ZMS.
179181
* ZMS entry for its name or value is either missing
180182
* or deleted. Clean dirty entries to make space for
181183
* future settings item.
182184
*/
183-
ret = settings_zms_delete(cf, ZMS_NAME_HASH_ID(ll_hash_id));
185+
ret = settings_zms_delete(cf, ZMS_NAME_ID_FROM_LL_NODE(ll_hash_id));
184186
if (ret < 0) {
185187
return ret;
186188
}
@@ -190,7 +192,7 @@ static int settings_zms_load(struct settings_store *cs, const struct settings_lo
190192
/* Found a name, this might not include a trailing \0 */
191193
name[rc1] = '\0';
192194
read_fn_arg.fs = &cf->cf_zms;
193-
read_fn_arg.id = ZMS_NAME_HASH_ID(ll_hash_id) + ZMS_DATA_ID_OFFSET;
195+
read_fn_arg.id = ZMS_NAME_ID_FROM_LL_NODE(ll_hash_id) + ZMS_DATA_ID_OFFSET;
194196

195197
ret = settings_call_set_handler(name, rc2, settings_zms_read_fn, &read_fn_arg,
196198
(void *)arg);
@@ -232,8 +234,10 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
232234
delete = ((value == NULL) || (val_len == 0));
233235

234236
name_hash = sys_hash32(name, strlen(name)) & ZMS_HASH_MASK;
237+
/* MSB is always 1 */
238+
name_hash |= BIT(31);
235239

236-
/* Let's find out if there is no hash collisions in the storage */
240+
/* Let's find out if there are hash collisions in the storage */
237241
write_name = true;
238242
hash_collision = true;
239243

@@ -311,6 +315,16 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
311315
}
312316
/* write linked list structure element */
313317
settings_element.next_hash = 0;
318+
/* Verify first that the linked list last element is not broken.
319+
* Settings subsystem uses ID that starts from ZMS_LL_HEAD_HASH_ID.
320+
*/
321+
if (cf->last_hash_id < ZMS_LL_HEAD_HASH_ID) {
322+
LOG_WRN("Linked list for hashes is broken, Trying to recover");
323+
rc = settings_zms_get_last_hash_ids(cf);
324+
if (rc < 0) {
325+
return rc;
326+
}
327+
}
314328
settings_element.previous_hash = cf->last_hash_id;
315329
rc = zms_write(&cf->cf_zms, name_hash | 1, &settings_element,
316330
sizeof(struct settings_hash_linked_list));
@@ -342,9 +356,22 @@ static int settings_zms_get_last_hash_ids(struct settings_zms *cf)
342356
do {
343357
rc = zms_read(&cf->cf_zms, ll_last_hash_id, &settings_element,
344358
sizeof(settings_element));
345-
if (rc) {
359+
if (rc == -ENOENT) {
360+
/* header doesn't exist or linked list broken, reinitialize the header */
361+
const struct settings_hash_linked_list settings_element = {
362+
.previous_hash = 0, .next_hash = 0};
363+
rc = zms_write(&cf->cf_zms, ZMS_LL_HEAD_HASH_ID, &settings_element,
364+
sizeof(struct settings_hash_linked_list));
365+
if (rc < 0) {
366+
return rc;
367+
}
368+
cf->last_hash_id = ZMS_LL_HEAD_HASH_ID;
369+
cf->second_to_last_hash_id = 0;
370+
return 0;
371+
} else if (rc < 0) {
346372
return rc;
347373
}
374+
348375
/* increment hash collision number if necessary */
349376
if (ZMS_COLLISION_NUM(ll_last_hash_id) > cf->hash_collision_num) {
350377
cf->hash_collision_num = ZMS_COLLISION_NUM(ll_last_hash_id);
@@ -375,23 +402,9 @@ static int settings_zms_backend_init(struct settings_zms *cf)
375402
cf->hash_collision_num = 0;
376403

377404
rc = settings_zms_get_last_hash_ids(cf);
378-
if (rc == -ENOENT) {
379-
/* header doesn't exist or linked list broken, reinitialize the header */
380-
const struct settings_hash_linked_list settings_element = {.previous_hash = 0,
381-
.next_hash = 0};
382-
rc = zms_write(&cf->cf_zms, ZMS_LL_HEAD_HASH_ID, &settings_element,
383-
sizeof(struct settings_hash_linked_list));
384-
if (rc < 0) {
385-
return rc;
386-
}
387-
cf->last_hash_id = ZMS_LL_HEAD_HASH_ID;
388-
cf->second_to_last_hash_id = 0;
389-
} else if (rc < 0) {
390-
return rc;
391-
}
392405

393406
LOG_DBG("ZMS backend initialized");
394-
return 0;
407+
return rc;
395408
}
396409

397410
int settings_backend_init(void)

0 commit comments

Comments
 (0)