Skip to content

Commit

Permalink
[nrf fromlist] settings: zms: fix some bugs related to the name's ID
Browse files Browse the repository at this point in the history
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.

Upstream PR #: 86170

Signed-off-by: Riadh Ghaddab <[email protected]>
(cherry picked from commit e56b55885b19628c6944a2544ca724717fbbb7b3)
  • Loading branch information
rghaddab committed Feb 25, 2025
1 parent 3969763 commit 9c8274f
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 18 deletions.
3 changes: 1 addition & 2 deletions subsys/settings/include/settings/settings_zms.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,9 @@ extern "C" {
#define ZMS_COLLISIONS_MASK GENMASK(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS, 1)
#define ZMS_HASH_TOTAL_MASK GENMASK(29, 1)
#define ZMS_MAX_COLLISIONS (BIT(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS) - 1)
#define ZMS_HEADER_HASH 0x80000000

/* some useful macros */
#define ZMS_NAME_HASH_ID(x) (x & ZMS_HASH_TOTAL_MASK)
#define ZMS_NAME_HASH_ID(x) ((x & ZMS_HASH_TOTAL_MASK) | BIT(31))
#define ZMS_UPDATE_COLLISION_NUM(x, y) \
((x & ~ZMS_COLLISIONS_MASK) | ((y << 1) & ZMS_COLLISIONS_MASK))
#define ZMS_COLLISION_NUM(x) ((x & ZMS_COLLISIONS_MASK) >> 1)
Expand Down
44 changes: 28 additions & 16 deletions subsys/settings/src/settings_zms.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ static int settings_zms_load(struct settings_store *cs, const struct settings_lo
static int settings_zms_save(struct settings_store *cs, const char *name, const char *value,
size_t val_len);
static void *settings_zms_storage_get(struct settings_store *cs);
static int settings_zms_get_last_hash_ids(struct settings_zms *cf);

static struct settings_store_itf settings_zms_itf = {.csi_load = settings_zms_load,
.csi_save = settings_zms_save,
Expand Down Expand Up @@ -232,6 +233,8 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
delete = ((value == NULL) || (val_len == 0));

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

/* Let's find out if there is no hash collisions in the storage */
write_name = true;
Expand Down Expand Up @@ -311,6 +314,16 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
}
/* write linked list structure element */
settings_element.next_hash = 0;
/* Verify first that the linked list last element is not broken.
* Settings subsystem uses ID that starts from ZMS_LL_HEAD_HASH_ID.
*/
if (cf->last_hash_id < ZMS_LL_HEAD_HASH_ID) {
LOG_WRN("Linked list for hashes is broken, Trying to recover");
rc = settings_zms_get_last_hash_ids(cf);
if (rc < 0) {
return rc;
}
}
settings_element.previous_hash = cf->last_hash_id;
rc = zms_write(&cf->cf_zms, name_hash | 1, &settings_element,
sizeof(struct settings_hash_linked_list));
Expand Down Expand Up @@ -342,9 +355,22 @@ static int settings_zms_get_last_hash_ids(struct settings_zms *cf)
do {
rc = zms_read(&cf->cf_zms, ll_last_hash_id, &settings_element,
sizeof(settings_element));
if (rc) {
if (rc == -ENOENT) {
/* header doesn't exist or linked list broken, reinitialize the header */
const struct settings_hash_linked_list settings_element = {
.previous_hash = 0, .next_hash = 0};
rc = zms_write(&cf->cf_zms, ZMS_LL_HEAD_HASH_ID, &settings_element,
sizeof(struct settings_hash_linked_list));
if (rc < 0) {
return rc;
}
cf->last_hash_id = ZMS_LL_HEAD_HASH_ID;
cf->second_to_last_hash_id = 0;
return 0;
} else if (rc < 0) {
return rc;
}

/* increment hash collision number if necessary */
if (ZMS_COLLISION_NUM(ll_last_hash_id) > cf->hash_collision_num) {
cf->hash_collision_num = ZMS_COLLISION_NUM(ll_last_hash_id);
Expand Down Expand Up @@ -375,23 +401,9 @@ static int settings_zms_backend_init(struct settings_zms *cf)
cf->hash_collision_num = 0;

rc = settings_zms_get_last_hash_ids(cf);
if (rc == -ENOENT) {
/* header doesn't exist or linked list broken, reinitialize the header */
const struct settings_hash_linked_list settings_element = {.previous_hash = 0,
.next_hash = 0};
rc = zms_write(&cf->cf_zms, ZMS_LL_HEAD_HASH_ID, &settings_element,
sizeof(struct settings_hash_linked_list));
if (rc < 0) {
return rc;
}
cf->last_hash_id = ZMS_LL_HEAD_HASH_ID;
cf->second_to_last_hash_id = 0;
} else if (rc < 0) {
return rc;
}

LOG_DBG("ZMS backend initialized");
return 0;
return rc;
}

int settings_backend_init(void)
Expand Down

0 comments on commit 9c8274f

Please sign in to comment.