1 /*
2 * Copyright (c) 2019 Nordic Semiconductor ASA
3 * Copyright (c) 2024 BayLibre SAS
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <zephyr/ztest.h>
11
12 #include <zephyr/drivers/flash.h>
13 #include <zephyr/fs/zms.h>
14 #include <zephyr/stats/stats.h>
15 #include <zephyr/storage/flash_map.h>
16 #include <zephyr/sys/crc.h>
17 #include "zms_priv.h"
18
19 #define TEST_ZMS_AREA storage_partition
20 #define TEST_ZMS_AREA_OFFSET FIXED_PARTITION_OFFSET(TEST_ZMS_AREA)
21 #define TEST_ZMS_AREA_ID FIXED_PARTITION_ID(TEST_ZMS_AREA)
22 #define TEST_ZMS_AREA_DEV DEVICE_DT_GET(DT_MTD_FROM_FIXED_PARTITION(DT_NODELABEL(TEST_ZMS_AREA)))
23 #define TEST_DATA_ID 1
24 #define TEST_SECTOR_COUNT 5U
25
26 static const struct device *const flash_dev = TEST_ZMS_AREA_DEV;
27
28 struct zms_fixture {
29 struct zms_fs fs;
30 #ifdef CONFIG_TEST_ZMS_SIMULATOR
31 struct stats_hdr *sim_stats;
32 struct stats_hdr *sim_thresholds;
33 #endif /* CONFIG_TEST_ZMS_SIMULATOR */
34 };
35
setup(void)36 static void *setup(void)
37 {
38 int err;
39 const struct flash_area *fa;
40 struct flash_pages_info info;
41 static struct zms_fixture fixture;
42
43 __ASSERT_NO_MSG(device_is_ready(flash_dev));
44
45 err = flash_area_open(TEST_ZMS_AREA_ID, &fa);
46 zassert_true(err == 0, "flash_area_open() fail: %d", err);
47
48 fixture.fs.offset = TEST_ZMS_AREA_OFFSET;
49 err = flash_get_page_info_by_offs(flash_area_get_device(fa), fixture.fs.offset, &info);
50 zassert_true(err == 0, "Unable to get page info: %d", err);
51
52 fixture.fs.sector_size = info.size;
53 fixture.fs.sector_count = TEST_SECTOR_COUNT;
54 fixture.fs.flash_device = flash_area_get_device(fa);
55
56 return &fixture;
57 }
58
before(void * data)59 static void before(void *data)
60 {
61 #ifdef CONFIG_TEST_ZMS_SIMULATOR
62 struct zms_fixture *fixture = (struct zms_fixture *)data;
63
64 fixture->sim_stats = stats_group_find("flash_sim_stats");
65 fixture->sim_thresholds = stats_group_find("flash_sim_thresholds");
66 #endif /* CONFIG_TEST_ZMS_SIMULATOR */
67 }
68
after(void * data)69 static void after(void *data)
70 {
71 struct zms_fixture *fixture = (struct zms_fixture *)data;
72
73 #ifdef CONFIG_TEST_ZMS_SIMULATOR
74 if (fixture->sim_stats) {
75 stats_reset(fixture->sim_stats);
76 }
77 if (fixture->sim_thresholds) {
78 stats_reset(fixture->sim_thresholds);
79 }
80 #endif /* CONFIG_TEST_ZMS_SIMULATOR */
81
82 /* Clear ZMS */
83 if (fixture->fs.ready) {
84 int err;
85
86 err = zms_clear(&fixture->fs);
87 zassert_true(err == 0, "zms_clear call failure: %d", err);
88 }
89
90 fixture->fs.sector_count = TEST_SECTOR_COUNT;
91 }
92
93 ZTEST_SUITE(zms, NULL, setup, before, after, NULL);
94
ZTEST_F(zms,test_zms_mount)95 ZTEST_F(zms, test_zms_mount)
96 {
97 int err;
98
99 err = zms_mount(&fixture->fs);
100 zassert_true(err == 0, "zms_mount call failure: %d", err);
101 }
102
execute_long_pattern_write(uint32_t id,struct zms_fs * fs)103 static void execute_long_pattern_write(uint32_t id, struct zms_fs *fs)
104 {
105 char rd_buf[512];
106 char wr_buf[512];
107 char pattern[] = {0xDE, 0xAD, 0xBE, 0xEF};
108 size_t len;
109
110 len = zms_read(fs, id, rd_buf, sizeof(rd_buf));
111 zassert_true(len == -ENOENT, "zms_read unexpected failure: %d", len);
112
113 BUILD_ASSERT((sizeof(wr_buf) % sizeof(pattern)) == 0);
114 for (int i = 0; i < sizeof(wr_buf); i += sizeof(pattern)) {
115 memcpy(wr_buf + i, pattern, sizeof(pattern));
116 }
117
118 len = zms_write(fs, id, wr_buf, sizeof(wr_buf));
119 zassert_true(len == sizeof(wr_buf), "zms_write failed: %d", len);
120
121 len = zms_read(fs, id, rd_buf, sizeof(rd_buf));
122 zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
123 zassert_mem_equal(wr_buf, rd_buf, sizeof(rd_buf), "RD buff should be equal to the WR buff");
124 }
125
ZTEST_F(zms,test_zms_write)126 ZTEST_F(zms, test_zms_write)
127 {
128 int err;
129
130 err = zms_mount(&fixture->fs);
131 zassert_true(err == 0, "zms_mount call failure: %d", err);
132
133 execute_long_pattern_write(TEST_DATA_ID, &fixture->fs);
134 }
135
136 #ifdef CONFIG_TEST_ZMS_SIMULATOR
flash_sim_write_calls_find(struct stats_hdr * hdr,void * arg,const char * name,uint16_t off)137 static int flash_sim_write_calls_find(struct stats_hdr *hdr, void *arg, const char *name,
138 uint16_t off)
139 {
140 if (!strcmp(name, "flash_write_calls")) {
141 uint32_t **flash_write_stat = (uint32_t **)arg;
142 *flash_write_stat = (uint32_t *)((uint8_t *)hdr + off);
143 }
144
145 return 0;
146 }
147
flash_sim_max_write_calls_find(struct stats_hdr * hdr,void * arg,const char * name,uint16_t off)148 static int flash_sim_max_write_calls_find(struct stats_hdr *hdr, void *arg, const char *name,
149 uint16_t off)
150 {
151 if (!strcmp(name, "max_write_calls")) {
152 uint32_t **max_write_calls = (uint32_t **)arg;
153 *max_write_calls = (uint32_t *)((uint8_t *)hdr + off);
154 }
155
156 return 0;
157 }
158
ZTEST_F(zms,test_zms_corrupted_write)159 ZTEST_F(zms, test_zms_corrupted_write)
160 {
161 int err;
162 size_t len;
163 char rd_buf[512];
164 char wr_buf_1[512];
165 char wr_buf_2[512];
166 char pattern_1[] = {0xDE, 0xAD, 0xBE, 0xEF};
167 char pattern_2[] = {0x03, 0xAA, 0x85, 0x6F};
168 uint32_t *flash_write_stat;
169 uint32_t *flash_max_write_calls;
170
171 err = zms_mount(&fixture->fs);
172 zassert_true(err == 0, "zms_mount call failure: %d", err);
173
174 err = zms_read(&fixture->fs, TEST_DATA_ID, rd_buf, sizeof(rd_buf));
175 zassert_true(err == -ENOENT, "zms_read unexpected failure: %d", err);
176
177 BUILD_ASSERT((sizeof(wr_buf_1) % sizeof(pattern_1)) == 0);
178 for (int i = 0; i < sizeof(wr_buf_1); i += sizeof(pattern_1)) {
179 memcpy(wr_buf_1 + i, pattern_1, sizeof(pattern_1));
180 }
181
182 len = zms_write(&fixture->fs, TEST_DATA_ID, wr_buf_1, sizeof(wr_buf_1));
183 zassert_true(len == sizeof(wr_buf_1), "zms_write failed: %d", len);
184
185 len = zms_read(&fixture->fs, TEST_DATA_ID, rd_buf, sizeof(rd_buf));
186 zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
187 zassert_mem_equal(wr_buf_1, rd_buf, sizeof(rd_buf),
188 "RD buff should be equal to the first WR buff");
189
190 BUILD_ASSERT((sizeof(wr_buf_2) % sizeof(pattern_2)) == 0);
191 for (int i = 0; i < sizeof(wr_buf_2); i += sizeof(pattern_2)) {
192 memcpy(wr_buf_2 + i, pattern_2, sizeof(pattern_2));
193 }
194
195 /* Set the maximum number of writes that the flash simulator can
196 * execute.
197 */
198 stats_walk(fixture->sim_thresholds, flash_sim_max_write_calls_find, &flash_max_write_calls);
199 stats_walk(fixture->sim_stats, flash_sim_write_calls_find, &flash_write_stat);
200
201 *flash_max_write_calls = *flash_write_stat - 1;
202 *flash_write_stat = 0;
203
204 /* Flash simulator will lose part of the data at the end of this write.
205 * This should simulate power down during flash write. The written data
206 * are corrupted at this point and should be discarded by the ZMS.
207 */
208 len = zms_write(&fixture->fs, TEST_DATA_ID, wr_buf_2, sizeof(wr_buf_2));
209 zassert_true(len == sizeof(wr_buf_2), "zms_write failed: %d", len);
210
211 /* Reinitialize the ZMS. */
212 memset(&fixture->fs, 0, sizeof(fixture->fs));
213 (void)setup();
214 err = zms_mount(&fixture->fs);
215 zassert_true(err == 0, "zms_mount call failure: %d", err);
216
217 len = zms_read(&fixture->fs, TEST_DATA_ID, rd_buf, sizeof(rd_buf));
218 zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
219 zassert_true(memcmp(wr_buf_2, rd_buf, sizeof(rd_buf)) != 0,
220 "RD buff should not be equal to the second WR buff because of "
221 "corrupted write operation");
222 zassert_mem_equal(wr_buf_1, rd_buf, sizeof(rd_buf),
223 "RD buff should be equal to the first WR buff because subsequent "
224 "write operation has failed");
225 }
226
ZTEST_F(zms,test_zms_gc)227 ZTEST_F(zms, test_zms_gc)
228 {
229 int err;
230 int len;
231 uint8_t buf[32];
232 uint8_t rd_buf[32];
233 const uint8_t max_id = 10;
234 /* 21st write will trigger GC. */
235 const uint16_t max_writes = 21;
236
237 fixture->fs.sector_count = 2;
238
239 err = zms_mount(&fixture->fs);
240 zassert_true(err == 0, "zms_mount call failure: %d", err);
241
242 for (int i = 0; i < max_writes; i++) {
243 uint8_t id = (i % max_id);
244 uint8_t id_data = id + max_id * (i / max_id);
245
246 memset(buf, id_data, sizeof(buf));
247
248 len = zms_write(&fixture->fs, id, buf, sizeof(buf));
249 zassert_true(len == sizeof(buf), "zms_write failed: %d", len);
250 }
251
252 for (int id = 0; id < max_id; id++) {
253 len = zms_read(&fixture->fs, id, rd_buf, sizeof(buf));
254 zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
255
256 for (int i = 0; i < sizeof(rd_buf); i++) {
257 rd_buf[i] = rd_buf[i] % max_id;
258 buf[i] = id;
259 }
260 zassert_mem_equal(buf, rd_buf, sizeof(rd_buf),
261 "RD buff should be equal to the WR buff");
262 }
263
264 err = zms_mount(&fixture->fs);
265 zassert_true(err == 0, "zms_mount call failure: %d", err);
266
267 for (int id = 0; id < max_id; id++) {
268 len = zms_read(&fixture->fs, id, rd_buf, sizeof(buf));
269 zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
270
271 for (int i = 0; i < sizeof(rd_buf); i++) {
272 rd_buf[i] = rd_buf[i] % max_id;
273 buf[i] = id;
274 }
275 zassert_mem_equal(buf, rd_buf, sizeof(rd_buf),
276 "RD buff should be equal to the WR buff");
277 }
278 }
279
write_content(uint32_t max_id,uint32_t begin,uint32_t end,struct zms_fs * fs)280 static void write_content(uint32_t max_id, uint32_t begin, uint32_t end, struct zms_fs *fs)
281 {
282 uint8_t buf[32];
283 ssize_t len;
284
285 for (int i = begin; i < end; i++) {
286 uint8_t id = (i % max_id);
287 uint8_t id_data = id + max_id * (i / max_id);
288
289 memset(buf, id_data, sizeof(buf));
290
291 len = zms_write(fs, id, buf, sizeof(buf));
292 zassert_true(len == sizeof(buf), "zms_write failed: %d", len);
293 }
294 }
295
check_content(uint32_t max_id,struct zms_fs * fs)296 static void check_content(uint32_t max_id, struct zms_fs *fs)
297 {
298 uint8_t rd_buf[32];
299 uint8_t buf[32];
300 ssize_t len;
301
302 for (int id = 0; id < max_id; id++) {
303 len = zms_read(fs, id, rd_buf, sizeof(buf));
304 zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
305
306 for (int i = 0; i < ARRAY_SIZE(rd_buf); i++) {
307 rd_buf[i] = rd_buf[i] % max_id;
308 buf[i] = id;
309 }
310 zassert_mem_equal(buf, rd_buf, sizeof(rd_buf),
311 "RD buff should be equal to the WR buff");
312 }
313 }
314
315 /**
316 * Full round of GC over 3 sectors
317 */
ZTEST_F(zms,test_zms_gc_3sectors)318 ZTEST_F(zms, test_zms_gc_3sectors)
319 {
320 int err;
321 const uint16_t max_id = 10;
322 /* 41st write will trigger 1st GC. */
323 const uint16_t max_writes = 41;
324 /* 61st write will trigger 2nd GC. */
325 const uint16_t max_writes_2 = 41 + 20;
326 /* 81st write will trigger 3rd GC. */
327 const uint16_t max_writes_3 = 41 + 20 + 20;
328 /* 101st write will trigger 4th GC. */
329 const uint16_t max_writes_4 = 41 + 20 + 20 + 20;
330
331 fixture->fs.sector_count = 3;
332
333 err = zms_mount(&fixture->fs);
334 zassert_true(err == 0, "zms_mount call failure: %d", err);
335 zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 0, "unexpected write sector");
336
337 /* Trigger 1st GC */
338 write_content(max_id, 0, max_writes, &fixture->fs);
339
340 /* sector sequence: empty,closed, write */
341 zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 2, "unexpected write sector");
342 check_content(max_id, &fixture->fs);
343
344 err = zms_mount(&fixture->fs);
345 zassert_true(err == 0, "zms_mount call failure: %d", err);
346
347 zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 2, "unexpected write sector");
348 check_content(max_id, &fixture->fs);
349
350 /* Trigger 2nd GC */
351 write_content(max_id, max_writes, max_writes_2, &fixture->fs);
352
353 /* sector sequence: write, empty, closed */
354 zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 0, "unexpected write sector");
355 check_content(max_id, &fixture->fs);
356
357 err = zms_mount(&fixture->fs);
358 zassert_true(err == 0, "zms_mount call failure: %d", err);
359
360 zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 0, "unexpected write sector");
361 check_content(max_id, &fixture->fs);
362
363 /* Trigger 3rd GC */
364 write_content(max_id, max_writes_2, max_writes_3, &fixture->fs);
365
366 /* sector sequence: closed, write, empty */
367 zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 1, "unexpected write sector");
368 check_content(max_id, &fixture->fs);
369
370 err = zms_mount(&fixture->fs);
371 zassert_true(err == 0, "zms_mount call failure: %d", err);
372
373 zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 1, "unexpected write sector");
374 check_content(max_id, &fixture->fs);
375
376 /* Trigger 4th GC */
377 write_content(max_id, max_writes_3, max_writes_4, &fixture->fs);
378
379 /* sector sequence: empty,closed, write */
380 zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 2, "unexpected write sector");
381 check_content(max_id, &fixture->fs);
382
383 err = zms_mount(&fixture->fs);
384 zassert_true(err == 0, "zms_mount call failure: %d", err);
385
386 zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 2, "unexpected write sector");
387 check_content(max_id, &fixture->fs);
388 }
389
flash_sim_max_len_find(struct stats_hdr * hdr,void * arg,const char * name,uint16_t off)390 static int flash_sim_max_len_find(struct stats_hdr *hdr, void *arg, const char *name, uint16_t off)
391 {
392 if (!strcmp(name, "max_len")) {
393 uint32_t **max_len = (uint32_t **)arg;
394 *max_len = (uint32_t *)((uint8_t *)hdr + off);
395 }
396
397 return 0;
398 }
399
ZTEST_F(zms,test_zms_corrupted_sector_close_operation)400 ZTEST_F(zms, test_zms_corrupted_sector_close_operation)
401 {
402 int err;
403 int len;
404 uint8_t buf[32];
405 uint32_t *flash_write_stat;
406 uint32_t *flash_max_write_calls;
407 uint32_t *flash_max_len;
408 const uint16_t max_id = 10;
409 /* 21st write will trigger GC. */
410 const uint16_t max_writes = 21;
411
412 /* Get the address of simulator parameters. */
413 stats_walk(fixture->sim_thresholds, flash_sim_max_write_calls_find, &flash_max_write_calls);
414 stats_walk(fixture->sim_thresholds, flash_sim_max_len_find, &flash_max_len);
415 stats_walk(fixture->sim_stats, flash_sim_write_calls_find, &flash_write_stat);
416
417 err = zms_mount(&fixture->fs);
418 zassert_true(err == 0, "zms_mount call failure: %d", err);
419
420 for (int i = 0; i < max_writes; i++) {
421 uint8_t id = (i % max_id);
422 uint8_t id_data = id + max_id * (i / max_id);
423
424 memset(buf, id_data, sizeof(buf));
425
426 if (i == max_writes - 1) {
427 /* Reset stats. */
428 *flash_write_stat = 0;
429
430 /* Block write calls and simulate power down during
431 * sector closing operation, so only a part of a ZMS
432 * closing ate will be written.
433 */
434 *flash_max_write_calls = 1;
435 *flash_max_len = 4;
436 }
437 len = zms_write(&fixture->fs, id, buf, sizeof(buf));
438 zassert_true(len == sizeof(buf), "zms_write failed: %d", len);
439 }
440
441 /* Make the flash simulator functional again. */
442 *flash_max_write_calls = 0;
443 *flash_max_len = 0;
444
445 err = zms_mount(&fixture->fs);
446 zassert_true(err == 0, "zms_mount call failure: %d", err);
447
448 check_content(max_id, &fixture->fs);
449
450 /* Ensure that the ZMS is able to store new content. */
451 execute_long_pattern_write(max_id, &fixture->fs);
452 }
453 #endif /* CONFIG_TEST_ZMS_SIMULATOR */
454
455 /**
456 * @brief Test case when storage become full, so only deletion is possible.
457 */
ZTEST_F(zms,test_zms_full_sector)458 ZTEST_F(zms, test_zms_full_sector)
459 {
460 int err;
461 ssize_t len;
462 uint32_t filling_id = 0;
463 uint32_t data_read;
464
465 fixture->fs.sector_count = 3;
466
467 err = zms_mount(&fixture->fs);
468 zassert_true(err == 0, "zms_mount call failure: %d", err);
469
470 while (1) {
471 len = zms_write(&fixture->fs, filling_id, &filling_id, sizeof(filling_id));
472 if (len == -ENOSPC) {
473 break;
474 }
475 zassert_true(len == sizeof(filling_id), "zms_write failed: %d", len);
476 filling_id++;
477 }
478
479 /* check whether can delete whatever from full storage */
480 err = zms_delete(&fixture->fs, 1);
481 zassert_true(err == 0, "zms_delete call failure: %d", err);
482
483 /* the last sector is full now, test re-initialization */
484 err = zms_mount(&fixture->fs);
485 zassert_true(err == 0, "zms_mount call failure: %d", err);
486
487 len = zms_write(&fixture->fs, filling_id, &filling_id, sizeof(filling_id));
488 zassert_true(len == sizeof(filling_id), "zms_write failed: %d", len);
489
490 /* coherence check on ZMS content */
491 for (int i = 0; i <= filling_id; i++) {
492 len = zms_read(&fixture->fs, i, &data_read, sizeof(data_read));
493 if (i == 1) {
494 zassert_true(len == -ENOENT, "zms_read shouldn't found the entry: %d", len);
495 } else {
496 zassert_true(len == sizeof(data_read),
497 "zms_read #%d failed: len is %zd instead of %zu", i, len,
498 sizeof(data_read));
499 zassert_equal(data_read, i, "read unexpected data: %d instead of %d",
500 data_read, i);
501 }
502 }
503 }
504
ZTEST_F(zms,test_delete)505 ZTEST_F(zms, test_delete)
506 {
507 int err;
508 ssize_t len;
509 uint32_t filling_id;
510 uint32_t data_read;
511 uint32_t ate_wra;
512 uint32_t data_wra;
513
514 fixture->fs.sector_count = 3;
515
516 err = zms_mount(&fixture->fs);
517 zassert_true(err == 0, "zms_mount call failure: %d", err);
518
519 for (filling_id = 0; filling_id < 10; filling_id++) {
520 len = zms_write(&fixture->fs, filling_id, &filling_id, sizeof(filling_id));
521
522 zassert_true(len == sizeof(filling_id), "zms_write failed: %d", len);
523
524 if (filling_id != 0) {
525 continue;
526 }
527
528 /* delete the first entry while it is the most recent one */
529 err = zms_delete(&fixture->fs, filling_id);
530 zassert_true(err == 0, "zms_delete call failure: %d", err);
531
532 len = zms_read(&fixture->fs, filling_id, &data_read, sizeof(data_read));
533 zassert_true(len == -ENOENT, "zms_read shouldn't found the entry: %d", len);
534 }
535
536 /* delete existing entry */
537 err = zms_delete(&fixture->fs, 1);
538 zassert_true(err == 0, "zms_delete call failure: %d", err);
539
540 len = zms_read(&fixture->fs, 1, &data_read, sizeof(data_read));
541 zassert_true(len == -ENOENT, "zms_read shouldn't found the entry: %d", len);
542
543 ate_wra = fixture->fs.ate_wra;
544 data_wra = fixture->fs.data_wra;
545
546 #ifdef CONFIG_ZMS_NO_DOUBLE_WRITE
547 /* delete already deleted entry */
548 err = zms_delete(&fixture->fs, 1);
549 zassert_true(err == 0, "zms_delete call failure: %d", err);
550 zassert_true(ate_wra == fixture->fs.ate_wra && data_wra == fixture->fs.data_wra,
551 "delete already deleted entry should not make"
552 " any footprint in the storage");
553
554 /* delete nonexisting entry */
555 err = zms_delete(&fixture->fs, filling_id);
556 zassert_true(err == 0, "zms_delete call failure: %d", err);
557 zassert_true(ate_wra == fixture->fs.ate_wra && data_wra == fixture->fs.data_wra,
558 "delete nonexistent entry should not make"
559 " any footprint in the storage");
560 #endif
561 }
562
563 #ifdef CONFIG_TEST_ZMS_SIMULATOR
564 /*
565 * Test that garbage-collection can recover all ate's even when the last ate,
566 * ie close_ate, is corrupt. In this test the close_ate is set to point to the
567 * last ate at -5. A valid ate is however present at -6. Since the close_ate
568 * has an invalid crc8, the offset should not be used and a recover of the
569 * last ate should be done instead.
570 */
ZTEST_F(zms,test_zms_gc_corrupt_close_ate)571 ZTEST_F(zms, test_zms_gc_corrupt_close_ate)
572 {
573 struct zms_ate ate;
574 struct zms_ate close_ate;
575 struct zms_ate empty_ate;
576 uint32_t data;
577 ssize_t len;
578 int err;
579
580 Z_TEST_SKIP_IFNDEF(CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES);
581 memset(&close_ate, 0xff, sizeof(struct zms_ate));
582 close_ate.id = ZMS_HEAD_ID;
583 close_ate.offset = fixture->fs.sector_size - sizeof(struct zms_ate) * 5;
584 close_ate.len = 0;
585 close_ate.cycle_cnt = 1;
586 close_ate.crc8 = 0xff; /* Incorrect crc8 */
587
588 memset(&empty_ate, 0, sizeof(struct zms_ate));
589 empty_ate.id = ZMS_HEAD_ID;
590 empty_ate.len = 0xffff;
591 empty_ate.metadata = FIELD_PREP(ZMS_VERSION_MASK, ZMS_DEFAULT_VERSION) |
592 FIELD_PREP(ZMS_MAGIC_NUMBER_MASK, ZMS_MAGIC_NUMBER) |
593 FIELD_PREP(ZMS_ATE_FORMAT_MASK, ZMS_DEFAULT_ATE_FORMAT);
594 empty_ate.cycle_cnt = 1;
595 empty_ate.crc8 =
596 crc8_ccitt(0xff, (uint8_t *)&empty_ate + SIZEOF_FIELD(struct zms_ate, crc8),
597 sizeof(struct zms_ate) - SIZEOF_FIELD(struct zms_ate, crc8));
598
599 memset(&ate, 0, sizeof(struct zms_ate));
600 ate.id = 0x1;
601 ate.len = sizeof(data);
602 ate.cycle_cnt = 1;
603 data = 0xaa55aa55;
604 memcpy(&ate.data, &data, sizeof(data));
605 ate.crc8 = crc8_ccitt(0xff, (uint8_t *)&ate + SIZEOF_FIELD(struct zms_ate, crc8),
606 sizeof(struct zms_ate) - SIZEOF_FIELD(struct zms_ate, crc8));
607
608 /* Add empty ATE */
609 err = flash_write(fixture->fs.flash_device,
610 fixture->fs.offset + fixture->fs.sector_size - sizeof(struct zms_ate),
611 &empty_ate, sizeof(empty_ate));
612 zassert_true(err == 0, "flash_write failed: %d", err);
613
614 /* Mark sector 0 as closed */
615 err = flash_write(fixture->fs.flash_device,
616 fixture->fs.offset + fixture->fs.sector_size - 2 * sizeof(struct zms_ate),
617 &close_ate, sizeof(close_ate));
618 zassert_true(err == 0, "flash_write failed: %d", err);
619
620 /* Write valid ate at -6 */
621 err = flash_write(fixture->fs.flash_device,
622 fixture->fs.offset + fixture->fs.sector_size - 6 * sizeof(struct zms_ate),
623 &ate, sizeof(ate));
624 zassert_true(err == 0, "flash_write failed: %d", err);
625
626 /* Mark sector 1 as closed */
627 err = flash_write(fixture->fs.flash_device,
628 fixture->fs.offset + (2 * fixture->fs.sector_size) -
629 2 * sizeof(struct zms_ate),
630 &close_ate, sizeof(close_ate));
631 zassert_true(err == 0, "flash_write failed: %d", err);
632
633 fixture->fs.sector_count = 3;
634
635 err = zms_mount(&fixture->fs);
636 zassert_true(err == 0, "zms_mount call failure: %d", err);
637
638 data = 0;
639 len = zms_read(&fixture->fs, 1, &data, sizeof(data));
640 zassert_true(len == sizeof(data), "zms_read should have read %d bytes", sizeof(data));
641 zassert_true(data == 0xaa55aa55, "unexpected value %d", data);
642 }
643 #endif /* CONFIG_TEST_ZMS_SIMULATOR */
644
645 /*
646 * Test that garbage-collection correctly handles corrupt ate's.
647 */
ZTEST_F(zms,test_zms_gc_corrupt_ate)648 ZTEST_F(zms, test_zms_gc_corrupt_ate)
649 {
650 struct zms_ate corrupt_ate;
651 struct zms_ate close_ate;
652 int err;
653
654 close_ate.id = ZMS_HEAD_ID;
655 close_ate.offset = fixture->fs.sector_size / 2;
656 close_ate.len = 0;
657 close_ate.crc8 =
658 crc8_ccitt(0xff, (uint8_t *)&close_ate + SIZEOF_FIELD(struct zms_ate, crc8),
659 sizeof(struct zms_ate) - SIZEOF_FIELD(struct zms_ate, crc8));
660
661 corrupt_ate.id = 0xdeadbeef;
662 corrupt_ate.offset = 0;
663 corrupt_ate.len = 20;
664 corrupt_ate.crc8 = 0xff; /* Incorrect crc8 */
665
666 /* Mark sector 0 as closed */
667 err = flash_write(fixture->fs.flash_device,
668 fixture->fs.offset + fixture->fs.sector_size - 2 * sizeof(struct zms_ate),
669 &close_ate, sizeof(close_ate));
670 zassert_true(err == 0, "flash_write failed: %d", err);
671
672 /* Write a corrupt ate */
673 err = flash_write(fixture->fs.flash_device,
674 fixture->fs.offset + (fixture->fs.sector_size / 2), &corrupt_ate,
675 sizeof(corrupt_ate));
676 zassert_true(err == 0, "flash_write failed: %d", err);
677
678 /* Mark sector 1 as closed */
679 err = flash_write(fixture->fs.flash_device,
680 fixture->fs.offset + (2 * fixture->fs.sector_size) -
681 2 * sizeof(struct zms_ate),
682 &close_ate, sizeof(close_ate));
683 zassert_true(err == 0, "flash_write failed: %d", err);
684
685 fixture->fs.sector_count = 3;
686
687 err = zms_mount(&fixture->fs);
688 zassert_true(err == 0, "zms_mount call failure: %d", err);
689 }
690
691 #ifdef CONFIG_ZMS_LOOKUP_CACHE
num_matching_cache_entries(uint64_t addr,bool compare_sector_only,struct zms_fs * fs)692 static size_t num_matching_cache_entries(uint64_t addr, bool compare_sector_only, struct zms_fs *fs)
693 {
694 size_t num = 0;
695 uint64_t mask = compare_sector_only ? ADDR_SECT_MASK : UINT64_MAX;
696
697 for (int i = 0; i < CONFIG_ZMS_LOOKUP_CACHE_SIZE; i++) {
698 if ((fs->lookup_cache[i] & mask) == addr) {
699 num++;
700 }
701 }
702
703 return num;
704 }
705
num_occupied_cache_entries(struct zms_fs * fs)706 static size_t num_occupied_cache_entries(struct zms_fs *fs)
707 {
708 return CONFIG_ZMS_LOOKUP_CACHE_SIZE -
709 num_matching_cache_entries(ZMS_LOOKUP_CACHE_NO_ADDR, false, fs);
710 }
711 #endif
712
713 /*
714 * Test that ZMS lookup cache is properly rebuilt on zms_mount(), or initialized
715 * to ZMS_LOOKUP_CACHE_NO_ADDR if the store is empty.
716 */
ZTEST_F(zms,test_zms_cache_init)717 ZTEST_F(zms, test_zms_cache_init)
718 {
719 #ifdef CONFIG_ZMS_LOOKUP_CACHE
720 int err;
721 size_t num;
722 uint64_t ate_addr;
723 uint8_t data = 0;
724
725 /* Test cache initialization when the store is empty */
726
727 fixture->fs.sector_count = 3;
728 err = zms_mount(&fixture->fs);
729 zassert_true(err == 0, "zms_mount call failure: %d", err);
730
731 num = num_occupied_cache_entries(&fixture->fs);
732 zassert_equal(num, 0, "uninitialized cache");
733
734 /* Test cache update after zms_write() */
735
736 ate_addr = fixture->fs.ate_wra;
737 err = zms_write(&fixture->fs, 1, &data, sizeof(data));
738 zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
739
740 num = num_occupied_cache_entries(&fixture->fs);
741 zassert_equal(num, 1, "cache not updated after write");
742
743 num = num_matching_cache_entries(ate_addr, false, &fixture->fs);
744 zassert_equal(num, 1, "invalid cache entry after write");
745
746 /* Test cache initialization when the store is non-empty */
747
748 memset(fixture->fs.lookup_cache, 0xAA, sizeof(fixture->fs.lookup_cache));
749 err = zms_mount(&fixture->fs);
750 zassert_true(err == 0, "zms_mount call failure: %d", err);
751
752 num = num_occupied_cache_entries(&fixture->fs);
753 zassert_equal(num, 1, "uninitialized cache after restart");
754
755 num = num_matching_cache_entries(ate_addr, false, &fixture->fs);
756 zassert_equal(num, 1, "invalid cache entry after restart");
757 #else
758 ztest_test_skip();
759 #endif
760 }
761
762 /*
763 * Test that even after writing more ZMS IDs than the number of ZMS lookup cache
764 * entries they all can be read and deleted correctly.
765 */
ZTEST_F(zms,test_zms_cache_collision)766 ZTEST_F(zms, test_zms_cache_collision)
767 {
768 #ifdef CONFIG_ZMS_LOOKUP_CACHE
769 int err;
770 uint16_t data;
771
772 fixture->fs.sector_count = 4;
773 err = zms_mount(&fixture->fs);
774 zassert_true(err == 0, "zms_mount call failure: %d", err);
775
776 for (int id = 0; id < CONFIG_ZMS_LOOKUP_CACHE_SIZE + 1; id++) {
777 data = id;
778 err = zms_write(&fixture->fs, id, &data, sizeof(data));
779 zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
780 }
781
782 for (int id = 0; id < CONFIG_ZMS_LOOKUP_CACHE_SIZE + 1; id++) {
783 err = zms_read(&fixture->fs, id, &data, sizeof(data));
784 zassert_equal(err, sizeof(data), "zms_read call failure: %d", err);
785 zassert_equal(data, id, "incorrect data read");
786 }
787
788 for (int id = 0; id < CONFIG_ZMS_LOOKUP_CACHE_SIZE + 1; id++) {
789 err = zms_delete(&fixture->fs, id);
790 zassert_equal(0, err, "zms_delete failed: %d", err);
791 }
792
793 for (int id = 0; id < CONFIG_ZMS_LOOKUP_CACHE_SIZE + 1; id++) {
794 err = zms_read(&fixture->fs, id, &data, sizeof(data));
795 zassert_equal(-ENOENT, err, "zms_delete failed: %d", err);
796 }
797 #else
798 ztest_test_skip();
799 #endif
800 }
801
802 /*
803 * Test that ZMS lookup cache does not contain any address from gc-ed sector
804 */
ZTEST_F(zms,test_zms_cache_gc)805 ZTEST_F(zms, test_zms_cache_gc)
806 {
807 #ifdef CONFIG_ZMS_LOOKUP_CACHE
808 int err;
809 size_t num;
810 uint16_t data = 0;
811
812 fixture->fs.sector_count = 3;
813 err = zms_mount(&fixture->fs);
814 zassert_true(err == 0, "zms_mount call failure: %d", err);
815
816 /* Fill the first sector with writes of ID 1 */
817
818 while (fixture->fs.data_wra + sizeof(data) + sizeof(struct zms_ate) <=
819 fixture->fs.ate_wra) {
820 ++data;
821 err = zms_write(&fixture->fs, 1, &data, sizeof(data));
822 zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
823 }
824
825 /* Verify that cache contains a single entry for sector 0 */
826
827 num = num_matching_cache_entries(0ULL << ADDR_SECT_SHIFT, true, &fixture->fs);
828 zassert_equal(num, 1, "invalid cache content after filling sector 0");
829
830 /* Fill the second sector with writes of ID 2 */
831
832 while ((fixture->fs.ate_wra >> ADDR_SECT_SHIFT) != 2) {
833 ++data;
834 err = zms_write(&fixture->fs, 2, &data, sizeof(data));
835 zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
836 }
837
838 /*
839 * At this point sector 0 should have been gc-ed. Verify that action is
840 * reflected by the cache content.
841 */
842
843 num = num_matching_cache_entries(0ULL << ADDR_SECT_SHIFT, true, &fixture->fs);
844 zassert_equal(num, 0, "not invalidated cache entries aftetr gc");
845
846 num = num_matching_cache_entries(2ULL << ADDR_SECT_SHIFT, true, &fixture->fs);
847 zassert_equal(num, 2, "invalid cache content after gc");
848 #else
849 ztest_test_skip();
850 #endif
851 }
852
853 /*
854 * Test ZMS lookup cache hash quality.
855 */
ZTEST_F(zms,test_zms_cache_hash_quality)856 ZTEST_F(zms, test_zms_cache_hash_quality)
857 {
858 #ifdef CONFIG_ZMS_LOOKUP_CACHE
859 const size_t MIN_CACHE_OCCUPANCY = CONFIG_ZMS_LOOKUP_CACHE_SIZE * 6 / 10;
860 int err;
861 size_t num;
862 uint32_t id;
863 uint16_t data;
864
865 err = zms_mount(&fixture->fs);
866 zassert_true(err == 0, "zms_mount call failure: %d", err);
867
868 /* Write ZMS IDs from 0 to CONFIG_ZMS_LOOKUP_CACHE_SIZE - 1 */
869
870 for (int i = 0; i < CONFIG_ZMS_LOOKUP_CACHE_SIZE; i++) {
871 id = i;
872 data = 0;
873
874 err = zms_write(&fixture->fs, id, &data, sizeof(data));
875 zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
876 }
877
878 /* Verify that at least 60% cache entries are occupied */
879
880 num = num_occupied_cache_entries(&fixture->fs);
881 TC_PRINT("Cache occupancy: %u\n", (unsigned int)num);
882 zassert_between_inclusive(num, MIN_CACHE_OCCUPANCY, CONFIG_ZMS_LOOKUP_CACHE_SIZE,
883 "too low cache occupancy - poor hash quality");
884
885 err = zms_clear(&fixture->fs);
886 zassert_true(err == 0, "zms_clear call failure: %d", err);
887
888 err = zms_mount(&fixture->fs);
889 zassert_true(err == 0, "zms_mount call failure: %d", err);
890
891 /* Write CONFIG_ZMS_LOOKUP_CACHE_SIZE ZMS IDs that form the following series: 0, 4, 8... */
892
893 for (int i = 0; i < CONFIG_ZMS_LOOKUP_CACHE_SIZE; i++) {
894 id = i * 4;
895 data = 0;
896
897 err = zms_write(&fixture->fs, id, &data, sizeof(data));
898 zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
899 }
900
901 /* Verify that at least 60% cache entries are occupied */
902
903 num = num_occupied_cache_entries(&fixture->fs);
904 TC_PRINT("Cache occupancy: %u\n", (unsigned int)num);
905 zassert_between_inclusive(num, MIN_CACHE_OCCUPANCY, CONFIG_ZMS_LOOKUP_CACHE_SIZE,
906 "too low cache occupancy - poor hash quality");
907 #else
908 ztest_test_skip();
909 #endif
910 }
911
ZTEST_F(zms,test_zms_input_validation)912 ZTEST_F(zms, test_zms_input_validation)
913 {
914 int err;
915
916 err = zms_mount(NULL);
917 zassert_true(err == -EINVAL, "zms_mount call with NULL fs failure: %d", err);
918
919 err = zms_clear(NULL);
920 zassert_true(err == -EINVAL, "zms_clear call with NULL fs failure: %d", err);
921 err = zms_clear(&fixture->fs);
922 zassert_true(err == -EACCES, "zms_clear call before mount fs failure: %d", err);
923
924 err = zms_calc_free_space(NULL);
925 zassert_true(err == -EINVAL, "zms_calc_free_space call with NULL fs failure: %d", err);
926 err = zms_calc_free_space(&fixture->fs);
927 zassert_true(err == -EACCES, "zms_calc_free_space call before mount fs failure: %d", err);
928
929 err = zms_active_sector_free_space(NULL);
930 zassert_true(err == -EINVAL, "zms_active_sector_free_space call with NULL fs failure: %d",
931 err);
932 err = zms_active_sector_free_space(&fixture->fs);
933 zassert_true(err == -EACCES, "zms_calc_free_space call before mount fs failure: %d", err);
934
935 err = zms_sector_use_next(NULL);
936 zassert_true(err == -EINVAL, "zms_sector_use_next call with NULL fs failure: %d", err);
937 err = zms_sector_use_next(&fixture->fs);
938 zassert_true(err == -EACCES, "zms_sector_use_next call before mount fs failure: %d", err);
939
940 /* Read */
941 err = zms_read(NULL, 0, NULL, 0);
942 zassert_true(err == -EINVAL, "zms_read call with NULL fs failure: %d", err);
943 err = zms_read(&fixture->fs, 0, NULL, 0);
944 zassert_true(err == -EACCES, "zms_read call before mount fs failure: %d", err);
945
946 /* zms_read() and zms_get_data_length() are currently wrappers around zms_read_hist() but
947 * add test here in case that is ever changed. Same is true for zms_delete() and zms_write()
948 */
949 err = zms_read_hist(NULL, 0, NULL, 0, 0);
950 zassert_true(err == -EINVAL, "zms_read_hist call with NULL fs failure: %d", err);
951 err = zms_read_hist(&fixture->fs, 0, NULL, 0, 0);
952 zassert_true(err == -EACCES, "zms_read_hist call before mount fs failure: %d", err);
953 err = zms_get_data_length(NULL, 0);
954 zassert_true(err == -EINVAL, "zms_get_data_length call with NULL fs failure: %d", err);
955 err = zms_get_data_length(&fixture->fs, 0);
956 zassert_true(err == -EACCES, "zms_get_data_length call before mount fs failure: %d", err);
957
958 /* Write */
959 err = zms_write(NULL, 0, NULL, 0);
960 zassert_true(err == -EINVAL, "zms_write call with NULL fs failure: %d", err);
961 err = zms_write(&fixture->fs, 0, NULL, 0);
962 zassert_true(err == -EACCES, "zms_write call before mount fs failure: %d", err);
963
964 /* Delete */
965 err = zms_delete(NULL, 0);
966 zassert_true(err == -EINVAL, "zms_delete call with NULL fs failure: %d", err);
967 err = zms_delete(&fixture->fs, 0);
968 zassert_true(err == -EACCES, "zms_delete call before mount fs failure: %d", err);
969 }
970
971 /*
972 * Test 64 bit ZMS ID support.
973 */
ZTEST_F(zms,test_zms_id_64bit)974 ZTEST_F(zms, test_zms_id_64bit)
975 {
976 int err;
977 ssize_t len;
978 uint64_t data_wra;
979 uint64_t filling_id_1 = 0xdeadbeefULL;
980 uint64_t filling_id_2 = 0xdefacedbULL;
981 uint64_t data_1;
982 uint32_t data_2;
983
984 Z_TEST_SKIP_IFNDEF(CONFIG_ZMS_ID_64BIT);
985
986 err = zms_mount(&fixture->fs);
987 zassert_true(err == 0, "zms_mount call failure: %d", err);
988
989 /* Fill the first sector with writes of different IDs */
990
991 while (fixture->fs.data_wra + sizeof(data_1) + sizeof(struct zms_ate) <=
992 fixture->fs.ate_wra) {
993 data_1 = filling_id_1;
994 len = zms_write(&fixture->fs, (zms_id_t)filling_id_1, &data_1, sizeof(data_1));
995 zassert_true(len == sizeof(data_1), "zms_write failed: %d", len);
996
997 /* Choose the next ID so that its lower 32 bits stay invariant.
998 * The purpose is to test that ZMS doesn't mistakenly cast the
999 * 64 bit ID to a 32 bit one somewhere.
1000 */
1001 filling_id_1 += BIT64(32);
1002 }
1003
1004 /* Fill the second sector similarly, except with small data in ATE */
1005
1006 err = zms_sector_use_next(&fixture->fs);
1007 zassert_true(err == 0, "zms_sector_use_next call failure: %d", err);
1008
1009 data_wra = fixture->fs.data_wra;
1010 while (data_wra + sizeof(data_2) + sizeof(struct zms_ate) <= fixture->fs.ate_wra) {
1011 /* Again, the lower 32 bits are invariant, so use the upper bits
1012 * to get unique data contents.
1013 */
1014 data_2 = (uint32_t)(filling_id_2 >> 32);
1015 len = zms_write(&fixture->fs, (zms_id_t)filling_id_2, &data_2, sizeof(data_2));
1016 zassert_true(len == sizeof(data_2), "zms_write failed: %d", len);
1017
1018 /* Expect no data to be stored outside of the ATE */
1019 zassert_equal(data_wra, fixture->fs.data_wra, "data_wra should not have changed");
1020
1021 filling_id_2 += BIT64(32);
1022 }
1023
1024 /* Read back the written entries and check that they're all unique */
1025
1026 for (uint64_t id = 0xdeadbeefULL; id < filling_id_1; id += BIT64(32)) {
1027 len = zms_read_hist(&fixture->fs, (zms_id_t)id, &data_1, sizeof(data_1), 0);
1028 zassert_true(len == sizeof(data_1), "zms_read_hist unexpected failure: %d", len);
1029 zassert_equal(id, data_1, "read unexpected data for id %llx: %llx", id, data_1);
1030
1031 len = zms_read_hist(&fixture->fs, (zms_id_t)id, &data_1, sizeof(data_1), 1);
1032 zassert_true(len == -ENOENT, "zms_read_hist unexpected failure: %d", len);
1033 }
1034
1035 for (uint64_t id = 0xdefacedbULL; id < filling_id_2; id += BIT64(32)) {
1036 len = zms_read_hist(&fixture->fs, (zms_id_t)id, &data_2, sizeof(data_2), 0);
1037 zassert_true(len == sizeof(data_2), "zms_read_hist unexpected failure: %d", len);
1038 zassert_equal((uint32_t)(id >> 32), data_2, "read unexpected data for id %llx: %x",
1039 id, data_2);
1040
1041 len = zms_read_hist(&fixture->fs, (zms_id_t)id, &data_2, sizeof(data_2), 1);
1042 zassert_true(len == -ENOENT, "zms_read_hist unexpected failure: %d", len);
1043 }
1044 }
1045
1046 /*
1047 * Test zms_active_sector_free_space() and zms_calc_free_space().
1048 */
ZTEST_F(zms,test_zms_free_space)1049 ZTEST_F(zms, test_zms_free_space)
1050 {
1051 const size_t max_space_in_sector = fixture->fs.sector_size - sizeof(struct zms_ate) * 5;
1052 size_t free_space_sector;
1053 size_t free_space_total;
1054 size_t write_len;
1055 ssize_t len;
1056 zms_id_t id;
1057 int err;
1058 char write_buf[max_space_in_sector + 1];
1059
1060 fixture->fs.sector_count = 2;
1061
1062 err = zms_mount(&fixture->fs);
1063 zassert_true(err == 0, "zms_mount call failure: %d", err);
1064
1065 /* Set and verify the initial values of free_space_sector and free_space_total */
1066
1067 free_space_sector = max_space_in_sector;
1068 zassert_equal(free_space_sector, zms_active_sector_free_space(&fixture->fs),
1069 "unexpected free space in empty sector");
1070 free_space_total = max_space_in_sector;
1071 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1072 "unexpected free space in empty filesystem");
1073
1074 id = 0;
1075
1076 len = zms_write(&fixture->fs, id, write_buf, sizeof(write_buf));
1077 zassert_true(len == -EINVAL, "zms_write unexpected failure: %d", len);
1078
1079 do {
1080 /* fill the filesystem with a single entry */
1081 write_len = free_space_total;
1082 len = zms_write(&fixture->fs, id, write_buf, write_len);
1083 zassert_true(len == write_len, "zms_write failed: %d", len);
1084 zassert_equal(0, zms_active_sector_free_space(&fixture->fs),
1085 "expected sector to appear full");
1086 zassert_equal(0, zms_calc_free_space(&fixture->fs),
1087 "expected filesystem to appear full");
1088
1089 /* no space in filesystem -> next write must fail */
1090 len = zms_write(&fixture->fs, id + 1, write_buf, 1);
1091 zassert_true(len == -ENOSPC, "zms_write unexpected failure: %d", len);
1092
1093 /* drop the filler entry; expect delete ATE to fit in the active sector */
1094 err = zms_delete(&fixture->fs, id);
1095 zassert_true(err == 0, "zms_delete call failure: %d", err);
1096 zassert_equal(0, zms_active_sector_free_space(&fixture->fs),
1097 "expected sector to appear full");
1098 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1099 "unexpected total free space");
1100
1101 /* Check cases where the active sector is filled in such a way
1102 * that there is only room for one ATE, and there is more space
1103 * for data to be stored within that ATE, than outside of it.
1104 * The calculated free space shall be ZMS_DATA_IN_ATE_SIZE.
1105 */
1106 write_len -= sizeof(struct zms_ate);
1107 while (write_len > ZMS_DATA_IN_ATE_SIZE) {
1108 len = zms_write(&fixture->fs, id, write_buf, write_len);
1109 zassert_true(len == write_len, "zms_write failed: %d", len);
1110 zassert_equal(ZMS_DATA_IN_ATE_SIZE,
1111 zms_active_sector_free_space(&fixture->fs),
1112 "unexpected free space in active sector");
1113 zassert_equal(ZMS_DATA_IN_ATE_SIZE, zms_calc_free_space(&fixture->fs),
1114 "unexpected total free space");
1115
1116 /* no space for data outside of ATE -> next write must fail */
1117 len = zms_write(&fixture->fs, id + 1, write_buf, ZMS_DATA_IN_ATE_SIZE + 1);
1118 zassert_true(len == -ENOSPC, "zms_write unexpected failure: %d", len);
1119
1120 /* add ATE with data inside it */
1121 len = zms_write(&fixture->fs, id + 1, write_buf, ZMS_DATA_IN_ATE_SIZE);
1122 zassert_true(len == ZMS_DATA_IN_ATE_SIZE, "zms_write failed: %d", len);
1123 zassert_equal(0, zms_active_sector_free_space(&fixture->fs),
1124 "expected sector to appear full");
1125 zassert_equal(0, zms_calc_free_space(&fixture->fs),
1126 "expected filesystem to appear full");
1127
1128 /* cleanup; expect delete ATE to fit in the active sector */
1129 err = zms_delete(&fixture->fs, id + 1);
1130 zassert_true(err == 0, "zms_delete call failure: %d", err);
1131 zassert_equal(0, zms_active_sector_free_space(&fixture->fs),
1132 "expected sector to appear full");
1133 zassert_equal(ZMS_DATA_IN_ATE_SIZE, zms_calc_free_space(&fixture->fs),
1134 "unexpected total free space");
1135
1136 err = zms_delete(&fixture->fs, id);
1137 zassert_true(err == 0, "zms_delete call failure: %d", err);
1138 zassert_equal(0, zms_active_sector_free_space(&fixture->fs),
1139 "expected sector to appear full");
1140 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1141 "unexpected total free space");
1142
1143 write_len -= fixture->fs.flash_parameters->write_block_size;
1144
1145 if (write_len <
1146 (free_space_total - sizeof(struct zms_ate) - ZMS_DATA_IN_ATE_SIZE)) {
1147 break;
1148 }
1149 }
1150
1151 /* add small data ATE with unique ID; these will accumulate until the loop ends */
1152 len = zms_write(&fixture->fs, id, write_buf, 1);
1153 zassert_true(len == 1, "zms_write failed: %d", len);
1154 id++;
1155
1156 free_space_sector -= sizeof(struct zms_ate);
1157 zassert_equal(free_space_sector, zms_active_sector_free_space(&fixture->fs),
1158 "unexpected free space in active sector");
1159 free_space_total = free_space_sector;
1160 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1161 "unexpected total free space");
1162 } while (free_space_total > 0);
1163
1164 /* Filesystem is filled with small data ATEs, now delete them all */
1165
1166 for (zms_id_t delete_id = 0; delete_id < id; delete_id++) {
1167 err = zms_delete(&fixture->fs, delete_id);
1168 zassert_true(err == 0, "zms_delete call failure: %d", err);
1169
1170 free_space_total += sizeof(struct zms_ate);
1171 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1172 "unexpected total free space");
1173
1174 if (free_space_sector == 0) {
1175 free_space_sector = free_space_total;
1176 zassert_equal(0, zms_active_sector_free_space(&fixture->fs),
1177 "unexpected free space in active sector");
1178 } else {
1179 free_space_sector -= sizeof(struct zms_ate);
1180 zassert_equal(free_space_sector, zms_active_sector_free_space(&fixture->fs),
1181 "unexpected free space in active sector");
1182 }
1183 }
1184 zassert_equal(free_space_total, max_space_in_sector, "expected file system to be empty");
1185
1186 /* Trigger garbage-collection */
1187
1188 err = zms_sector_use_next(&fixture->fs);
1189 zassert_true(err == 0, "zms_sector_use_next call failure: %d", err);
1190
1191 free_space_sector = max_space_in_sector;
1192 zassert_equal(free_space_sector, zms_active_sector_free_space(&fixture->fs),
1193 "unexpected free space in empty sector");
1194 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1195 "total free space should not have changed");
1196
1197 /* Finally, fill the active sector with redundant entries */
1198
1199 write_len = 64;
1200 len = zms_write(&fixture->fs, id, write_buf, write_len);
1201 zassert_true(len == write_len, "zms_write failed: %d", len);
1202
1203 free_space_sector -= (write_len + sizeof(struct zms_ate));
1204 zassert_equal(free_space_sector, zms_active_sector_free_space(&fixture->fs),
1205 "unexpected free space in active sector");
1206 free_space_total -= (write_len + sizeof(struct zms_ate));
1207 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1208 "unexpected total free space");
1209
1210 #ifndef CONFIG_ZMS_NO_DOUBLE_WRITE
1211 while (free_space_sector >= (write_len + sizeof(struct zms_ate))) {
1212 len = zms_write(&fixture->fs, id, write_buf, write_len);
1213 zassert_true(len == write_len, "zms_write failed: %d", len);
1214
1215 free_space_sector -= (write_len + sizeof(struct zms_ate));
1216 zassert_equal(free_space_sector, zms_active_sector_free_space(&fixture->fs),
1217 "unexpected free space in active sector");
1218 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1219 "total free space should not have changed");
1220 }
1221 #else
1222 /* With no double write, the above loop would never terminate */
1223 len = zms_write(&fixture->fs, id, write_buf, write_len);
1224 zassert_true(len == 0, "zms_write failed: %d", len);
1225
1226 zassert_equal(free_space_sector, zms_active_sector_free_space(&fixture->fs),
1227 "active sector free space should not have changed");
1228 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1229 "total free space should not have changed");
1230 #endif
1231 }
1232
1233 /*
1234 * Test zms_calc_free_space() with more than 2 sectors.
1235 * This is to exercise its handling of closed sectors.
1236 */
ZTEST_F(zms,test_zms_free_space_5sectors)1237 ZTEST_F(zms, test_zms_free_space_5sectors)
1238 {
1239 const size_t max_space_in_sector = fixture->fs.sector_size - sizeof(struct zms_ate) * 5;
1240 size_t free_space_total;
1241 int err;
1242 char write_buf[max_space_in_sector];
1243
1244 fixture->fs.sector_count = 5;
1245
1246 err = zms_mount(&fixture->fs);
1247 zassert_true(err == 0, "zms_mount call failure: %d", err);
1248
1249 free_space_total = max_space_in_sector * (fixture->fs.sector_count - 1);
1250 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1251 "unexpected free space in empty filesystem");
1252
1253 /* Sector 1: add 3 new ATEs */
1254
1255 zms_write(&fixture->fs, 0, write_buf, 100);
1256 zms_write(&fixture->fs, 1, write_buf, 200);
1257 zms_write(&fixture->fs, 2, write_buf, 300);
1258
1259 free_space_total -= (100 + 200 + 300 + 3 * sizeof(struct zms_ate));
1260 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1261 "unexpected total free space");
1262
1263 err = zms_sector_use_next(&fixture->fs);
1264 zassert_true(err == 0, "zms_sector_use_next call failure: %d", err);
1265 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1266 "total free space should not have changed");
1267
1268 /* Sector 2: add 1 new ATE and update 1 existing ATE */
1269
1270 zms_write(&fixture->fs, 3, write_buf, 100);
1271 zms_write(&fixture->fs, 1, write_buf, 800);
1272
1273 free_space_total -= (100 + (800 - 200) + sizeof(struct zms_ate));
1274 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1275 "unexpected total free space");
1276
1277 err = zms_sector_use_next(&fixture->fs);
1278 zassert_true(err == 0, "zms_sector_use_next call failure: %d", err);
1279 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1280 "total free space should not have changed");
1281
1282 /* Sector 3: add 2 new ATEs */
1283
1284 zms_write(&fixture->fs, 4, write_buf, max_space_in_sector - sizeof(struct zms_ate));
1285 zms_write(&fixture->fs, 5, write_buf, ZMS_DATA_IN_ATE_SIZE);
1286
1287 free_space_total -= max_space_in_sector;
1288 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1289 "unexpected total free space");
1290
1291 err = zms_sector_use_next(&fixture->fs);
1292 zassert_true(err == 0, "zms_sector_use_next call failure: %d", err);
1293 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1294 "total free space should not have changed");
1295
1296 /* Sector 4: update 1 existing ATE */
1297
1298 zms_write(&fixture->fs, 4, write_buf, max_space_in_sector);
1299
1300 free_space_total -= sizeof(struct zms_ate);
1301 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1302 "unexpected total free space");
1303
1304 err = zms_sector_use_next(&fixture->fs);
1305 zassert_true(err == 0, "zms_sector_use_next call failure: %d", err);
1306 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1307 "total free space should not have changed");
1308
1309 /* GC all sectors and verify relation with zms_active_sector_free_space() */
1310
1311 free_space_total = 0;
1312 for (int i = 0; i < fixture->fs.sector_count - 1; i++) {
1313 free_space_total += zms_active_sector_free_space(&fixture->fs);
1314
1315 err = zms_sector_use_next(&fixture->fs);
1316 zassert_true(err == 0, "zms_sector_use_next call failure: %d", err);
1317 }
1318 zassert_equal(free_space_total, zms_calc_free_space(&fixture->fs),
1319 "total free space did not match sum of gc'd sectors");
1320 }
1321