@@ -72,11 +72,39 @@ static int settings_zms_unlink_ll_node(struct settings_zms *cf, uint32_t name_ha
72
72
struct settings_hash_linked_list settings_update_element ;
73
73
74
74
/* 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 ,
76
76
sizeof (struct settings_hash_linked_list ));
77
77
if (rc < 0 ) {
78
78
return rc ;
79
79
}
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
+
80
108
/* update the next element */
81
109
if (settings_element .next_hash ) {
82
110
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
100
128
*/
101
129
cf -> last_hash_id = settings_element .previous_hash ;
102
130
}
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
- }
123
131
124
- return rc ;
132
+ return 0 ;
125
133
}
126
134
#endif /* CONFIG_SETTINGS_ZMS_NO_LL_DELETE */
127
135
@@ -146,12 +154,6 @@ static int settings_zms_delete(struct settings_zms *cf, uint32_t name_hash)
146
154
return rc ;
147
155
}
148
156
149
- /* Now delete the current linked list element */
150
- rc = zms_delete (& cf -> cf_zms , name_hash | 1 );
151
- if (rc < 0 ) {
152
- return rc ;
153
- }
154
-
155
157
#endif /* CONFIG_SETTINGS_ZMS_NO_LL_DELETE */
156
158
return rc ;
157
159
}
@@ -469,13 +471,10 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
469
471
470
472
/* write the name if required */
471
473
if (write_name ) {
472
- rc = zms_write (& cf -> cf_zms , name_hash , name , strlen (name ));
473
- if (rc < 0 ) {
474
- return rc ;
475
- }
474
+ /* First let's update the linked list */
476
475
#ifdef CONFIG_SETTINGS_ZMS_NO_LL_DELETE
477
476
/* verify that the ll_node doesn't exist otherwise do not update it */
478
- rc = zms_read (& cf -> cf_zms , name_hash | 1 , & settings_element ,
477
+ rc = zms_read (& cf -> cf_zms , ZMS_LL_NODE_FROM_NAME_ID ( name_hash ) , & settings_element ,
479
478
sizeof (struct settings_hash_linked_list ));
480
479
if (rc >= 0 ) {
481
480
goto no_ll_update ;
@@ -497,28 +496,36 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
497
496
}
498
497
}
499
498
settings_element .previous_hash = cf -> last_hash_id ;
500
- rc = zms_write (& cf -> cf_zms , name_hash | 1 , & settings_element ,
499
+ rc = zms_write (& cf -> cf_zms , ZMS_LL_NODE_FROM_NAME_ID ( name_hash ) , & settings_element ,
501
500
sizeof (struct settings_hash_linked_list ));
502
501
if (rc < 0 ) {
503
502
return rc ;
504
503
}
505
504
506
505
/* Now update the previous linked list element */
507
- settings_element .next_hash = name_hash | 1 ;
506
+ settings_element .next_hash = ZMS_LL_NODE_FROM_NAME_ID ( name_hash ) ;
508
507
settings_element .previous_hash = cf -> second_to_last_hash_id ;
509
508
rc = zms_write (& cf -> cf_zms , cf -> last_hash_id , & settings_element ,
510
509
sizeof (struct settings_hash_linked_list ));
511
510
if (rc < 0 ) {
512
511
return rc ;
513
512
}
514
513
cf -> second_to_last_hash_id = cf -> last_hash_id ;
515
- cf -> last_hash_id = name_hash | 1 ;
514
+ cf -> last_hash_id = ZMS_LL_NODE_FROM_NAME_ID ( name_hash ) ;
516
515
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
517
516
if (cf -> ll_cache_next < CONFIG_SETTINGS_ZMS_LL_CACHE_SIZE ) {
518
517
cf -> ll_cache [cf -> ll_cache_next ] = settings_element ;
519
518
cf -> ll_cache_next = cf -> ll_cache_next + 1 ;
520
519
}
521
520
#endif
521
+ #ifdef CONFIG_SETTINGS_ZMS_NO_LL_DELETE
522
+ no_ll_update :
523
+ #endif /* CONFIG_SETTINGS_ZMS_NO_LL_DELETE */
524
+ /* Now let's write the name */
525
+ rc = zms_write (& cf -> cf_zms , name_hash , name , strlen (name ));
526
+ if (rc < 0 ) {
527
+ return rc ;
528
+ }
522
529
}
523
530
#ifdef CONFIG_SETTINGS_ZMS_NO_LL_DELETE
524
531
no_ll_update :
@@ -530,6 +537,7 @@ static int settings_zms_get_last_hash_ids(struct settings_zms *cf)
530
537
{
531
538
struct settings_hash_linked_list settings_element ;
532
539
uint32_t ll_last_hash_id = ZMS_LL_HEAD_HASH_ID ;
540
+ uint32_t previous_ll_hash_id = 0 ;
533
541
int rc = 0 ;
534
542
535
543
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
@@ -555,6 +563,27 @@ static int settings_zms_get_last_hash_ids(struct settings_zms *cf)
555
563
return rc ;
556
564
}
557
565
566
+ if (settings_element .previous_hash != previous_ll_hash_id ) {
567
+ /* This is a special case that can happen when a power down occurred
568
+ * when deleting a linked list node.
569
+ * If the power down occurred after updating the previous linked list node,
570
+ * then we would end up with a state where the previous_hash of the linked
571
+ * list is broken. Let's recover from this
572
+ */
573
+ rc = zms_delete (& cf -> cf_zms , settings_element .previous_hash );
574
+ if (rc < 0 ) {
575
+ return rc ;
576
+ }
577
+ /* Now recover the linked list */
578
+ settings_element .previous_hash = previous_ll_hash_id ;
579
+ zms_write (& cf -> cf_zms , ll_last_hash_id , & settings_element ,
580
+ sizeof (struct settings_hash_linked_list ));
581
+ if (rc < 0 ) {
582
+ return rc ;
583
+ }
584
+ }
585
+ previous_ll_hash_id = ll_last_hash_id ;
586
+
558
587
#ifdef CONFIG_SETTINGS_ZMS_LL_CACHE
559
588
if ((cf -> ll_cache_next < CONFIG_SETTINGS_ZMS_LL_CACHE_SIZE ) &&
560
589
(settings_element .next_hash )) {
0 commit comments