@@ -72,11 +72,39 @@ static int settings_zms_unlink_ll_node(struct settings_zms *cf, uint32_t name_ha
7272 struct settings_hash_linked_list settings_update_element ;
7373
7474 /* let's update the linked list */
75- rc = zms_read (& cf -> cf_zms , name_hash | 1 , & settings_element ,
75+ rc = zms_read (& cf -> cf_zms , ZMS_LL_NODE_FROM_NAME_ID ( name_hash ) , & settings_element ,
7676 sizeof (struct settings_hash_linked_list ));
7777 if (rc < 0 ) {
7878 return rc ;
7979 }
80+
81+ /* update the previous element */
82+ if (settings_element .previous_hash ) {
83+ rc = zms_read (& cf -> cf_zms , settings_element .previous_hash , & settings_update_element ,
84+ sizeof (struct settings_hash_linked_list ));
85+ if (rc < 0 ) {
86+ return rc ;
87+ }
88+ if (!settings_element .next_hash ) {
89+ /* we are deleting the last element of the linked list,
90+ * let's update the second_to_last_hash_id
91+ */
92+ cf -> second_to_last_hash_id = settings_update_element .previous_hash ;
93+ }
94+ settings_update_element .next_hash = settings_element .next_hash ;
95+ rc = zms_write (& cf -> cf_zms , settings_element .previous_hash ,
96+ & settings_update_element , sizeof (struct settings_hash_linked_list ));
97+ if (rc < 0 ) {
98+ return rc ;
99+ }
100+ }
101+
102+ /* Now delete the current linked list element */
103+ rc = zms_delete (& cf -> cf_zms , ZMS_LL_NODE_FROM_NAME_ID (name_hash ));
104+ if (rc < 0 ) {
105+ return rc ;
106+ }
107+
80108 /* update the next element */
81109 if (settings_element .next_hash ) {
82110 rc = zms_read (& cf -> cf_zms , settings_element .next_hash , & settings_update_element ,
@@ -100,28 +128,8 @@ static int settings_zms_unlink_ll_node(struct settings_zms *cf, uint32_t name_ha
100128 */
101129 cf -> last_hash_id = settings_element .previous_hash ;
102130 }
103- /* update the previous element */
104- if (settings_element .previous_hash ) {
105- rc = zms_read (& cf -> cf_zms , settings_element .previous_hash , & settings_update_element ,
106- sizeof (struct settings_hash_linked_list ));
107- if (rc < 0 ) {
108- return rc ;
109- }
110- if (!settings_element .next_hash ) {
111- /* we are deleting the last element of the linked list,
112- * let's update the second_to_last_hash_id
113- */
114- cf -> second_to_last_hash_id = settings_update_element .previous_hash ;
115- }
116- settings_update_element .next_hash = settings_element .next_hash ;
117- rc = zms_write (& cf -> cf_zms , settings_element .previous_hash ,
118- & settings_update_element , sizeof (struct settings_hash_linked_list ));
119- if (rc < 0 ) {
120- return rc ;
121- }
122- }
123131
124- return rc ;
132+ return 0 ;
125133}
126134#endif /* CONFIG_SETTINGS_ZMS_NO_LL_DELETE */
127135
@@ -182,11 +190,6 @@ static int settings_zms_delete(struct settings_zms *cf, uint32_t name_hash)
182190 return rc ;
183191 }
184192
185- /* Now delete the current linked list element */
186- rc = zms_delete (& cf -> cf_zms , name_hash | 1 );
187- if (rc < 0 ) {
188- return rc ;
189- }
190193#endif /* CONFIG_SETTINGS_ZMS_NO_LL_DELETE */
191194#ifdef CONFIG_SETTINGS_ZMS_NAME_CACHE
192195 /* Update the flag of the Settings entry in cache. */
@@ -538,16 +541,13 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
538541
539542 /* write the name if required */
540543 if (write_name ) {
541- rc = zms_write (& cf -> cf_zms , name_hash , name , strlen (name ));
542- if (rc < 0 ) {
543- return rc ;
544- }
544+ /* First let's update the linked list */
545545#ifdef CONFIG_SETTINGS_ZMS_NO_LL_DELETE
546546 if (ll_node_exist ) {
547547 goto no_ll_update ;
548548 }
549549 /* verify that the ll_node doesn't exist otherwise do not update it */
550- rc = zms_read (& cf -> cf_zms , name_hash | 1 , & settings_element ,
550+ rc = zms_read (& cf -> cf_zms , ZMS_LL_NODE_FROM_NAME_ID ( name_hash ) , & settings_element ,
551551 sizeof (struct settings_hash_linked_list ));
552552 if (rc >= 0 ) {
553553 goto no_ll_update ;
@@ -569,7 +569,7 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
569569 }
570570 }
571571 settings_element .previous_hash = cf -> last_hash_id ;
572- rc = zms_write (& cf -> cf_zms , name_hash | 1 , & settings_element ,
572+ rc = zms_write (& cf -> cf_zms , ZMS_LL_NODE_FROM_NAME_ID ( name_hash ) , & settings_element ,
573573 sizeof (struct settings_hash_linked_list ));
574574 if (rc < 0 ) {
575575 return rc ;
@@ -580,25 +580,31 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
580580 }
581581#endif
582582 /* Now update the previous linked list element */
583- settings_element .next_hash = name_hash | 1 ;
583+ settings_element .next_hash = ZMS_LL_NODE_FROM_NAME_ID ( name_hash ) ;
584584 settings_element .previous_hash = cf -> second_to_last_hash_id ;
585585 rc = zms_write (& cf -> cf_zms , cf -> last_hash_id , & settings_element ,
586586 sizeof (struct settings_hash_linked_list ));
587587 if (rc < 0 ) {
588588 return rc ;
589589 }
590590 cf -> second_to_last_hash_id = cf -> last_hash_id ;
591- cf -> last_hash_id = name_hash | 1 ;
591+ cf -> last_hash_id = ZMS_LL_NODE_FROM_NAME_ID ( name_hash ) ;
592592#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
593593 if ((cf -> ll_cache_next <= CONFIG_SETTINGS_ZMS_LL_CACHE_SIZE ) &&
594594 (cf -> ll_cache_next > 1 )) {
595595 cf -> ll_cache [cf -> ll_cache_next - 2 ] = settings_element ;
596596 }
597597#endif
598- }
599598#ifdef CONFIG_SETTINGS_ZMS_NO_LL_DELETE
600599no_ll_update :
601600#endif /* CONFIG_SETTINGS_ZMS_NO_LL_DELETE */
601+ /* Now let's write the name */
602+ rc = zms_write (& cf -> cf_zms , name_hash , name , strlen (name ));
603+ if (rc < 0 ) {
604+ return rc ;
605+ }
606+ }
607+
602608#ifdef CONFIG_SETTINGS_ZMS_NAME_CACHE
603609 /* Add the flags of the written settings entry in cache */
604610 cache_flags = 0 ;
@@ -615,6 +621,7 @@ static int settings_zms_get_last_hash_ids(struct settings_zms *cf)
615621{
616622 struct settings_hash_linked_list settings_element ;
617623 uint32_t ll_last_hash_id = ZMS_LL_HEAD_HASH_ID ;
624+ uint32_t previous_ll_hash_id = 0 ;
618625 int rc = 0 ;
619626
620627#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
@@ -646,6 +653,27 @@ static int settings_zms_get_last_hash_ids(struct settings_zms *cf)
646653 return rc ;
647654 }
648655
656+ if (settings_element .previous_hash != previous_ll_hash_id ) {
657+ /* This is a special case that can happen when a power down occurred
658+ * when deleting a linked list node.
659+ * If the power down occurred after updating the previous linked list node,
660+ * then we would end up with a state where the previous_hash of the linked
661+ * list is broken. Let's recover from this
662+ */
663+ rc = zms_delete (& cf -> cf_zms , settings_element .previous_hash );
664+ if (rc < 0 ) {
665+ return rc ;
666+ }
667+ /* Now recover the linked list */
668+ settings_element .previous_hash = previous_ll_hash_id ;
669+ zms_write (& cf -> cf_zms , ll_last_hash_id , & settings_element ,
670+ sizeof (struct settings_hash_linked_list ));
671+ if (rc < 0 ) {
672+ return rc ;
673+ }
674+ }
675+ previous_ll_hash_id = ll_last_hash_id ;
676+
649677#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
650678 if (cf -> ll_cache_next <= CONFIG_SETTINGS_ZMS_LL_CACHE_SIZE ) {
651679 cf -> ll_cache [cf -> ll_cache_next ++ ] = settings_element ;
0 commit comments