1 /*
2  * Copyright (c) 2024 BayLibre SAS
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * This test is designed to be run using flash-simulator which provide
9  * functionality for flash property customization and emulating errors in
10  * flash operation in parallel to regular flash API.
11  * Test should be run on qemu_x86 or native_sim target.
12  */
13 
14 #if !defined(CONFIG_BOARD_QEMU_X86) && !defined(CONFIG_ARCH_POSIX)
15 #error "Run only on qemu_x86 or a posix architecture based target (for ex. native_sim)"
16 #endif
17 
18 #include <stdio.h>
19 #include <string.h>
20 #include <zephyr/ztest.h>
21 
22 #include <zephyr/drivers/flash.h>
23 #include <zephyr/fs/zms.h>
24 #include <zephyr/stats/stats.h>
25 #include <zephyr/storage/flash_map.h>
26 #include <zephyr/sys/crc.h>
27 #include "zms_priv.h"
28 
29 #define TEST_ZMS_AREA        storage_partition
30 #define TEST_ZMS_AREA_OFFSET FIXED_PARTITION_OFFSET(TEST_ZMS_AREA)
31 #define TEST_ZMS_AREA_ID     FIXED_PARTITION_ID(TEST_ZMS_AREA)
32 #define TEST_ZMS_AREA_DEV    DEVICE_DT_GET(DT_MTD_FROM_FIXED_PARTITION(DT_NODELABEL(TEST_ZMS_AREA)))
33 #define TEST_DATA_ID         1
34 #define TEST_SECTOR_COUNT    5U
35 
36 static const struct device *const flash_dev = TEST_ZMS_AREA_DEV;
37 
38 struct zms_fixture {
39 	struct zms_fs fs;
40 	struct stats_hdr *sim_stats;
41 	struct stats_hdr *sim_thresholds;
42 };
43 
setup(void)44 static void *setup(void)
45 {
46 	int err;
47 	const struct flash_area *fa;
48 	struct flash_pages_info info;
49 	static struct zms_fixture fixture;
50 
51 	__ASSERT_NO_MSG(device_is_ready(flash_dev));
52 
53 	err = flash_area_open(TEST_ZMS_AREA_ID, &fa);
54 	zassert_true(err == 0, "flash_area_open() fail: %d", err);
55 
56 	fixture.fs.offset = TEST_ZMS_AREA_OFFSET;
57 	err = flash_get_page_info_by_offs(flash_area_get_device(fa), fixture.fs.offset, &info);
58 	zassert_true(err == 0, "Unable to get page info: %d", err);
59 
60 	fixture.fs.sector_size = info.size;
61 	fixture.fs.sector_count = TEST_SECTOR_COUNT;
62 	fixture.fs.flash_device = flash_area_get_device(fa);
63 
64 	return &fixture;
65 }
66 
before(void * data)67 static void before(void *data)
68 {
69 	struct zms_fixture *fixture = (struct zms_fixture *)data;
70 
71 	fixture->sim_stats = stats_group_find("flash_sim_stats");
72 	fixture->sim_thresholds = stats_group_find("flash_sim_thresholds");
73 }
74 
after(void * data)75 static void after(void *data)
76 {
77 	struct zms_fixture *fixture = (struct zms_fixture *)data;
78 
79 	if (fixture->sim_stats) {
80 		stats_reset(fixture->sim_stats);
81 	}
82 	if (fixture->sim_thresholds) {
83 		stats_reset(fixture->sim_thresholds);
84 	}
85 
86 	/* Clear ZMS */
87 	if (fixture->fs.ready) {
88 		int err;
89 
90 		err = zms_clear(&fixture->fs);
91 		zassert_true(err == 0, "zms_clear call failure: %d", err);
92 	}
93 
94 	fixture->fs.sector_count = TEST_SECTOR_COUNT;
95 }
96 
97 ZTEST_SUITE(zms, NULL, setup, before, after, NULL);
98 
ZTEST_F(zms,test_zms_mount)99 ZTEST_F(zms, test_zms_mount)
100 {
101 	int err;
102 
103 	err = zms_mount(&fixture->fs);
104 	zassert_true(err == 0, "zms_mount call failure: %d", err);
105 }
106 
execute_long_pattern_write(uint32_t id,struct zms_fs * fs)107 static void execute_long_pattern_write(uint32_t id, struct zms_fs *fs)
108 {
109 	char rd_buf[512];
110 	char wr_buf[512];
111 	char pattern[] = {0xDE, 0xAD, 0xBE, 0xEF};
112 	size_t len;
113 
114 	len = zms_read(fs, id, rd_buf, sizeof(rd_buf));
115 	zassert_true(len == -ENOENT, "zms_read unexpected failure: %d", len);
116 
117 	BUILD_ASSERT((sizeof(wr_buf) % sizeof(pattern)) == 0);
118 	for (int i = 0; i < sizeof(wr_buf); i += sizeof(pattern)) {
119 		memcpy(wr_buf + i, pattern, sizeof(pattern));
120 	}
121 
122 	len = zms_write(fs, id, wr_buf, sizeof(wr_buf));
123 	zassert_true(len == sizeof(wr_buf), "zms_write failed: %d", len);
124 
125 	len = zms_read(fs, id, rd_buf, sizeof(rd_buf));
126 	zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
127 	zassert_mem_equal(wr_buf, rd_buf, sizeof(rd_buf), "RD buff should be equal to the WR buff");
128 }
129 
ZTEST_F(zms,test_zms_write)130 ZTEST_F(zms, test_zms_write)
131 {
132 	int err;
133 
134 	err = zms_mount(&fixture->fs);
135 	zassert_true(err == 0, "zms_mount call failure: %d", err);
136 
137 	execute_long_pattern_write(TEST_DATA_ID, &fixture->fs);
138 }
139 
flash_sim_write_calls_find(struct stats_hdr * hdr,void * arg,const char * name,uint16_t off)140 static int flash_sim_write_calls_find(struct stats_hdr *hdr, void *arg, const char *name,
141 				      uint16_t off)
142 {
143 	if (!strcmp(name, "flash_write_calls")) {
144 		uint32_t **flash_write_stat = (uint32_t **)arg;
145 		*flash_write_stat = (uint32_t *)((uint8_t *)hdr + off);
146 	}
147 
148 	return 0;
149 }
150 
flash_sim_max_write_calls_find(struct stats_hdr * hdr,void * arg,const char * name,uint16_t off)151 static int flash_sim_max_write_calls_find(struct stats_hdr *hdr, void *arg, const char *name,
152 					  uint16_t off)
153 {
154 	if (!strcmp(name, "max_write_calls")) {
155 		uint32_t **max_write_calls = (uint32_t **)arg;
156 		*max_write_calls = (uint32_t *)((uint8_t *)hdr + off);
157 	}
158 
159 	return 0;
160 }
161 
ZTEST_F(zms,test_zms_corrupted_write)162 ZTEST_F(zms, test_zms_corrupted_write)
163 {
164 	int err;
165 	size_t len;
166 	char rd_buf[512];
167 	char wr_buf_1[512];
168 	char wr_buf_2[512];
169 	char pattern_1[] = {0xDE, 0xAD, 0xBE, 0xEF};
170 	char pattern_2[] = {0x03, 0xAA, 0x85, 0x6F};
171 	uint32_t *flash_write_stat;
172 	uint32_t *flash_max_write_calls;
173 
174 	err = zms_mount(&fixture->fs);
175 	zassert_true(err == 0, "zms_mount call failure: %d", err);
176 
177 	err = zms_read(&fixture->fs, TEST_DATA_ID, rd_buf, sizeof(rd_buf));
178 	zassert_true(err == -ENOENT, "zms_read unexpected failure: %d", err);
179 
180 	BUILD_ASSERT((sizeof(wr_buf_1) % sizeof(pattern_1)) == 0);
181 	for (int i = 0; i < sizeof(wr_buf_1); i += sizeof(pattern_1)) {
182 		memcpy(wr_buf_1 + i, pattern_1, sizeof(pattern_1));
183 	}
184 
185 	len = zms_write(&fixture->fs, TEST_DATA_ID, wr_buf_1, sizeof(wr_buf_1));
186 	zassert_true(len == sizeof(wr_buf_1), "zms_write failed: %d", len);
187 
188 	len = zms_read(&fixture->fs, TEST_DATA_ID, rd_buf, sizeof(rd_buf));
189 	zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
190 	zassert_mem_equal(wr_buf_1, rd_buf, sizeof(rd_buf),
191 			  "RD buff should be equal to the first WR buff");
192 
193 	BUILD_ASSERT((sizeof(wr_buf_2) % sizeof(pattern_2)) == 0);
194 	for (int i = 0; i < sizeof(wr_buf_2); i += sizeof(pattern_2)) {
195 		memcpy(wr_buf_2 + i, pattern_2, sizeof(pattern_2));
196 	}
197 
198 	/* Set the maximum number of writes that the flash simulator can
199 	 * execute.
200 	 */
201 	stats_walk(fixture->sim_thresholds, flash_sim_max_write_calls_find, &flash_max_write_calls);
202 	stats_walk(fixture->sim_stats, flash_sim_write_calls_find, &flash_write_stat);
203 
204 	*flash_max_write_calls = *flash_write_stat - 1;
205 	*flash_write_stat = 0;
206 
207 	/* Flash simulator will lose part of the data at the end of this write.
208 	 * This should simulate power down during flash write. The written data
209 	 * are corrupted at this point and should be discarded by the ZMS.
210 	 */
211 	len = zms_write(&fixture->fs, TEST_DATA_ID, wr_buf_2, sizeof(wr_buf_2));
212 	zassert_true(len == sizeof(wr_buf_2), "zms_write failed: %d", len);
213 
214 	/* Reinitialize the ZMS. */
215 	memset(&fixture->fs, 0, sizeof(fixture->fs));
216 	(void)setup();
217 	err = zms_mount(&fixture->fs);
218 	zassert_true(err == 0, "zms_mount call failure: %d", err);
219 
220 	len = zms_read(&fixture->fs, TEST_DATA_ID, rd_buf, sizeof(rd_buf));
221 	zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
222 	zassert_true(memcmp(wr_buf_2, rd_buf, sizeof(rd_buf)) != 0,
223 		     "RD buff should not be equal to the second WR buff because of "
224 		     "corrupted write operation");
225 	zassert_mem_equal(wr_buf_1, rd_buf, sizeof(rd_buf),
226 			  "RD buff should be equal to the first WR buff because subsequent "
227 			  "write operation has failed");
228 }
229 
ZTEST_F(zms,test_zms_gc)230 ZTEST_F(zms, test_zms_gc)
231 {
232 	int err;
233 	int len;
234 	uint8_t buf[32];
235 	uint8_t rd_buf[32];
236 	const uint8_t max_id = 10;
237 	/* 21st write will trigger GC. */
238 	const uint16_t max_writes = 21;
239 
240 	fixture->fs.sector_count = 2;
241 
242 	err = zms_mount(&fixture->fs);
243 	zassert_true(err == 0, "zms_mount call failure: %d", err);
244 
245 	for (int i = 0; i < max_writes; i++) {
246 		uint8_t id = (i % max_id);
247 		uint8_t id_data = id + max_id * (i / max_id);
248 
249 		memset(buf, id_data, sizeof(buf));
250 
251 		len = zms_write(&fixture->fs, id, buf, sizeof(buf));
252 		zassert_true(len == sizeof(buf), "zms_write failed: %d", len);
253 	}
254 
255 	for (int id = 0; id < max_id; id++) {
256 		len = zms_read(&fixture->fs, id, rd_buf, sizeof(buf));
257 		zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
258 
259 		for (int i = 0; i < sizeof(rd_buf); i++) {
260 			rd_buf[i] = rd_buf[i] % max_id;
261 			buf[i] = id;
262 		}
263 		zassert_mem_equal(buf, rd_buf, sizeof(rd_buf),
264 				  "RD buff should be equal to the WR buff");
265 	}
266 
267 	err = zms_mount(&fixture->fs);
268 	zassert_true(err == 0, "zms_mount call failure: %d", err);
269 
270 	for (int id = 0; id < max_id; id++) {
271 		len = zms_read(&fixture->fs, id, rd_buf, sizeof(buf));
272 		zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
273 
274 		for (int i = 0; i < sizeof(rd_buf); i++) {
275 			rd_buf[i] = rd_buf[i] % max_id;
276 			buf[i] = id;
277 		}
278 		zassert_mem_equal(buf, rd_buf, sizeof(rd_buf),
279 				  "RD buff should be equal to the WR buff");
280 	}
281 }
282 
write_content(uint32_t max_id,uint32_t begin,uint32_t end,struct zms_fs * fs)283 static void write_content(uint32_t max_id, uint32_t begin, uint32_t end, struct zms_fs *fs)
284 {
285 	uint8_t buf[32];
286 	ssize_t len;
287 
288 	for (int i = begin; i < end; i++) {
289 		uint8_t id = (i % max_id);
290 		uint8_t id_data = id + max_id * (i / max_id);
291 
292 		memset(buf, id_data, sizeof(buf));
293 
294 		len = zms_write(fs, id, buf, sizeof(buf));
295 		zassert_true(len == sizeof(buf), "zms_write failed: %d", len);
296 	}
297 }
298 
check_content(uint32_t max_id,struct zms_fs * fs)299 static void check_content(uint32_t max_id, struct zms_fs *fs)
300 {
301 	uint8_t rd_buf[32];
302 	uint8_t buf[32];
303 	ssize_t len;
304 
305 	for (int id = 0; id < max_id; id++) {
306 		len = zms_read(fs, id, rd_buf, sizeof(buf));
307 		zassert_true(len == sizeof(rd_buf), "zms_read unexpected failure: %d", len);
308 
309 		for (int i = 0; i < ARRAY_SIZE(rd_buf); i++) {
310 			rd_buf[i] = rd_buf[i] % max_id;
311 			buf[i] = id;
312 		}
313 		zassert_mem_equal(buf, rd_buf, sizeof(rd_buf),
314 				  "RD buff should be equal to the WR buff");
315 	}
316 }
317 
318 /**
319  * Full round of GC over 3 sectors
320  */
ZTEST_F(zms,test_zms_gc_3sectors)321 ZTEST_F(zms, test_zms_gc_3sectors)
322 {
323 	int err;
324 	const uint16_t max_id = 10;
325 	/* 41st write will trigger 1st GC. */
326 	const uint16_t max_writes = 41;
327 	/* 61st write will trigger 2nd GC. */
328 	const uint16_t max_writes_2 = 41 + 20;
329 	/* 81st write will trigger 3rd GC. */
330 	const uint16_t max_writes_3 = 41 + 20 + 20;
331 	/* 101st write will trigger 4th GC. */
332 	const uint16_t max_writes_4 = 41 + 20 + 20 + 20;
333 
334 	fixture->fs.sector_count = 3;
335 
336 	err = zms_mount(&fixture->fs);
337 	zassert_true(err == 0, "zms_mount call failure: %d", err);
338 	zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 0, "unexpected write sector");
339 
340 	/* Trigger 1st GC */
341 	write_content(max_id, 0, max_writes, &fixture->fs);
342 
343 	/* sector sequence: empty,closed, write */
344 	zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 2, "unexpected write sector");
345 	check_content(max_id, &fixture->fs);
346 
347 	err = zms_mount(&fixture->fs);
348 	zassert_true(err == 0, "zms_mount call failure: %d", err);
349 
350 	zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 2, "unexpected write sector");
351 	check_content(max_id, &fixture->fs);
352 
353 	/* Trigger 2nd GC */
354 	write_content(max_id, max_writes, max_writes_2, &fixture->fs);
355 
356 	/* sector sequence: write, empty, closed */
357 	zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 0, "unexpected write sector");
358 	check_content(max_id, &fixture->fs);
359 
360 	err = zms_mount(&fixture->fs);
361 	zassert_true(err == 0, "zms_mount call failure: %d", err);
362 
363 	zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 0, "unexpected write sector");
364 	check_content(max_id, &fixture->fs);
365 
366 	/* Trigger 3rd GC */
367 	write_content(max_id, max_writes_2, max_writes_3, &fixture->fs);
368 
369 	/* sector sequence: closed, write, empty */
370 	zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 1, "unexpected write sector");
371 	check_content(max_id, &fixture->fs);
372 
373 	err = zms_mount(&fixture->fs);
374 	zassert_true(err == 0, "zms_mount call failure: %d", err);
375 
376 	zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 1, "unexpected write sector");
377 	check_content(max_id, &fixture->fs);
378 
379 	/* Trigger 4th GC */
380 	write_content(max_id, max_writes_3, max_writes_4, &fixture->fs);
381 
382 	/* sector sequence: empty,closed, write */
383 	zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 2, "unexpected write sector");
384 	check_content(max_id, &fixture->fs);
385 
386 	err = zms_mount(&fixture->fs);
387 	zassert_true(err == 0, "zms_mount call failure: %d", err);
388 
389 	zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 2, "unexpected write sector");
390 	check_content(max_id, &fixture->fs);
391 }
392 
flash_sim_max_len_find(struct stats_hdr * hdr,void * arg,const char * name,uint16_t off)393 static int flash_sim_max_len_find(struct stats_hdr *hdr, void *arg, const char *name, uint16_t off)
394 {
395 	if (!strcmp(name, "max_len")) {
396 		uint32_t **max_len = (uint32_t **)arg;
397 		*max_len = (uint32_t *)((uint8_t *)hdr + off);
398 	}
399 
400 	return 0;
401 }
402 
ZTEST_F(zms,test_zms_corrupted_sector_close_operation)403 ZTEST_F(zms, test_zms_corrupted_sector_close_operation)
404 {
405 	int err;
406 	int len;
407 	uint8_t buf[32];
408 	uint32_t *flash_write_stat;
409 	uint32_t *flash_max_write_calls;
410 	uint32_t *flash_max_len;
411 	const uint16_t max_id = 10;
412 	/* 21st write will trigger GC. */
413 	const uint16_t max_writes = 21;
414 
415 	/* Get the address of simulator parameters. */
416 	stats_walk(fixture->sim_thresholds, flash_sim_max_write_calls_find, &flash_max_write_calls);
417 	stats_walk(fixture->sim_thresholds, flash_sim_max_len_find, &flash_max_len);
418 	stats_walk(fixture->sim_stats, flash_sim_write_calls_find, &flash_write_stat);
419 
420 	err = zms_mount(&fixture->fs);
421 	zassert_true(err == 0, "zms_mount call failure: %d", err);
422 
423 	for (int i = 0; i < max_writes; i++) {
424 		uint8_t id = (i % max_id);
425 		uint8_t id_data = id + max_id * (i / max_id);
426 
427 		memset(buf, id_data, sizeof(buf));
428 
429 		if (i == max_writes - 1) {
430 			/* Reset stats. */
431 			*flash_write_stat = 0;
432 
433 			/* Block write calls and simulate power down during
434 			 * sector closing operation, so only a part of a ZMS
435 			 * closing ate will be written.
436 			 */
437 			*flash_max_write_calls = 1;
438 			*flash_max_len = 4;
439 		}
440 		len = zms_write(&fixture->fs, id, buf, sizeof(buf));
441 		zassert_true(len == sizeof(buf), "zms_write failed: %d", len);
442 	}
443 
444 	/* Make the flash simulator functional again. */
445 	*flash_max_write_calls = 0;
446 	*flash_max_len = 0;
447 
448 	err = zms_mount(&fixture->fs);
449 	zassert_true(err == 0, "zms_mount call failure: %d", err);
450 
451 	check_content(max_id, &fixture->fs);
452 
453 	/* Ensure that the ZMS is able to store new content. */
454 	execute_long_pattern_write(max_id, &fixture->fs);
455 }
456 
457 /**
458  * @brief Test case when storage become full, so only deletion is possible.
459  */
ZTEST_F(zms,test_zms_full_sector)460 ZTEST_F(zms, test_zms_full_sector)
461 {
462 	int err;
463 	ssize_t len;
464 	uint32_t filling_id = 0;
465 	uint32_t data_read;
466 
467 	fixture->fs.sector_count = 3;
468 
469 	err = zms_mount(&fixture->fs);
470 	zassert_true(err == 0, "zms_mount call failure: %d", err);
471 
472 	while (1) {
473 		len = zms_write(&fixture->fs, filling_id, &filling_id, sizeof(filling_id));
474 		if (len == -ENOSPC) {
475 			break;
476 		}
477 		zassert_true(len == sizeof(filling_id), "zms_write failed: %d", len);
478 		filling_id++;
479 	}
480 
481 	/* check whether can delete whatever from full storage */
482 	err = zms_delete(&fixture->fs, 1);
483 	zassert_true(err == 0, "zms_delete call failure: %d", err);
484 
485 	/* the last sector is full now, test re-initialization */
486 	err = zms_mount(&fixture->fs);
487 	zassert_true(err == 0, "zms_mount call failure: %d", err);
488 
489 	len = zms_write(&fixture->fs, filling_id, &filling_id, sizeof(filling_id));
490 	zassert_true(len == sizeof(filling_id), "zms_write failed: %d", len);
491 
492 	/* sanitycheck on ZMS content */
493 	for (int i = 0; i <= filling_id; i++) {
494 		len = zms_read(&fixture->fs, i, &data_read, sizeof(data_read));
495 		if (i == 1) {
496 			zassert_true(len == -ENOENT, "zms_read shouldn't found the entry: %d", len);
497 		} else {
498 			zassert_true(len == sizeof(data_read),
499 				     "zms_read #%d failed: len is %zd instead of %zu", i, len,
500 				     sizeof(data_read));
501 			zassert_equal(data_read, i, "read unexpected data: %d instead of %d",
502 				      data_read, i);
503 		}
504 	}
505 }
506 
ZTEST_F(zms,test_delete)507 ZTEST_F(zms, test_delete)
508 {
509 	int err;
510 	ssize_t len;
511 	uint32_t filling_id;
512 	uint32_t data_read;
513 	uint32_t ate_wra;
514 	uint32_t data_wra;
515 
516 	fixture->fs.sector_count = 3;
517 
518 	err = zms_mount(&fixture->fs);
519 	zassert_true(err == 0, "zms_mount call failure: %d", err);
520 
521 	for (filling_id = 0; filling_id < 10; filling_id++) {
522 		len = zms_write(&fixture->fs, filling_id, &filling_id, sizeof(filling_id));
523 
524 		zassert_true(len == sizeof(filling_id), "zms_write failed: %d", len);
525 
526 		if (filling_id != 0) {
527 			continue;
528 		}
529 
530 		/* delete the first entry while it is the most recent one */
531 		err = zms_delete(&fixture->fs, filling_id);
532 		zassert_true(err == 0, "zms_delete call failure: %d", err);
533 
534 		len = zms_read(&fixture->fs, filling_id, &data_read, sizeof(data_read));
535 		zassert_true(len == -ENOENT, "zms_read shouldn't found the entry: %d", len);
536 	}
537 
538 	/* delete existing entry */
539 	err = zms_delete(&fixture->fs, 1);
540 	zassert_true(err == 0, "zms_delete call failure: %d", err);
541 
542 	len = zms_read(&fixture->fs, 1, &data_read, sizeof(data_read));
543 	zassert_true(len == -ENOENT, "zms_read shouldn't found the entry: %d", len);
544 
545 	ate_wra = fixture->fs.ate_wra;
546 	data_wra = fixture->fs.data_wra;
547 
548 #ifdef CONFIG_ZMS_NO_DOUBLE_WRITE
549 	/* delete already deleted entry */
550 	err = zms_delete(&fixture->fs, 1);
551 	zassert_true(err == 0, "zms_delete call failure: %d", err);
552 	zassert_true(ate_wra == fixture->fs.ate_wra && data_wra == fixture->fs.data_wra,
553 		     "delete already deleted entry should not make"
554 		     " any footprint in the storage");
555 
556 	/* delete nonexisting entry */
557 	err = zms_delete(&fixture->fs, filling_id);
558 	zassert_true(err == 0, "zms_delete call failure: %d", err);
559 	zassert_true(ate_wra == fixture->fs.ate_wra && data_wra == fixture->fs.data_wra,
560 		     "delete nonexistent entry should not make"
561 		     " any footprint in the storage");
562 #endif
563 }
564 
565 /*
566  * Test that garbage-collection can recover all ate's even when the last ate,
567  * ie close_ate, is corrupt. In this test the close_ate is set to point to the
568  * last ate at -5. A valid ate is however present at -6. Since the close_ate
569  * has an invalid crc8, the offset should not be used and a recover of the
570  * last ate should be done instead.
571  */
ZTEST_F(zms,test_zms_gc_corrupt_close_ate)572 ZTEST_F(zms, test_zms_gc_corrupt_close_ate)
573 {
574 	struct zms_ate ate;
575 	struct zms_ate close_ate;
576 	struct zms_ate empty_ate;
577 	uint32_t data;
578 	ssize_t len;
579 	int err;
580 
581 	Z_TEST_SKIP_IFNDEF(CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES);
582 	close_ate.id = 0xffffffff;
583 	close_ate.offset = fixture->fs.sector_size - sizeof(struct zms_ate) * 5;
584 	close_ate.len = 0;
585 	close_ate.metadata = 0xffffffff;
586 	close_ate.cycle_cnt = 1;
587 	close_ate.crc8 = 0xff; /* Incorrect crc8 */
588 
589 	empty_ate.id = 0xffffffff;
590 	empty_ate.offset = 0;
591 	empty_ate.len = 0xffff;
592 	empty_ate.metadata = 0x4201;
593 	empty_ate.cycle_cnt = 1;
594 	empty_ate.crc8 =
595 		crc8_ccitt(0xff, (uint8_t *)&empty_ate + SIZEOF_FIELD(struct zms_ate, crc8),
596 			   sizeof(struct zms_ate) - SIZEOF_FIELD(struct zms_ate, crc8));
597 
598 	memset(&ate, 0, sizeof(struct zms_ate));
599 	ate.id = 0x1;
600 	ate.len = sizeof(data);
601 	ate.cycle_cnt = 1;
602 	data = 0xaa55aa55;
603 	memcpy(&ate.data, &data, sizeof(data));
604 	ate.crc8 = crc8_ccitt(0xff, (uint8_t *)&ate + SIZEOF_FIELD(struct zms_ate, crc8),
605 			      sizeof(struct zms_ate) - SIZEOF_FIELD(struct zms_ate, crc8));
606 
607 	/* Add empty ATE */
608 	err = flash_write(fixture->fs.flash_device,
609 			  fixture->fs.offset + fixture->fs.sector_size - sizeof(struct zms_ate),
610 			  &empty_ate, sizeof(empty_ate));
611 	zassert_true(err == 0, "flash_write failed: %d", err);
612 
613 	/* Mark sector 0 as closed */
614 	err = flash_write(fixture->fs.flash_device,
615 			  fixture->fs.offset + fixture->fs.sector_size - 2 * sizeof(struct zms_ate),
616 			  &close_ate, sizeof(close_ate));
617 	zassert_true(err == 0, "flash_write failed: %d", err);
618 
619 	/* Write valid ate at -6 */
620 	err = flash_write(fixture->fs.flash_device,
621 			  fixture->fs.offset + fixture->fs.sector_size - 6 * sizeof(struct zms_ate),
622 			  &ate, sizeof(ate));
623 	zassert_true(err == 0, "flash_write failed: %d", err);
624 
625 	/* Mark sector 1 as closed */
626 	err = flash_write(fixture->fs.flash_device,
627 			  fixture->fs.offset + (2 * fixture->fs.sector_size) -
628 				  2 * sizeof(struct zms_ate),
629 			  &close_ate, sizeof(close_ate));
630 	zassert_true(err == 0, "flash_write failed: %d", err);
631 
632 	fixture->fs.sector_count = 3;
633 
634 	err = zms_mount(&fixture->fs);
635 	zassert_true(err == 0, "zms_mount call failure: %d", err);
636 
637 	data = 0;
638 	len = zms_read(&fixture->fs, 1, &data, sizeof(data));
639 	zassert_true(len == sizeof(data), "zms_read should have read %d bytes", sizeof(data));
640 	zassert_true(data == 0xaa55aa55, "unexpected value %d", data);
641 }
642 
643 /*
644  * Test that garbage-collection correctly handles corrupt ate's.
645  */
ZTEST_F(zms,test_zms_gc_corrupt_ate)646 ZTEST_F(zms, test_zms_gc_corrupt_ate)
647 {
648 	struct zms_ate corrupt_ate;
649 	struct zms_ate close_ate;
650 	int err;
651 
652 	close_ate.id = 0xffffffff;
653 	close_ate.offset = fixture->fs.sector_size / 2;
654 	close_ate.len = 0;
655 	close_ate.crc8 =
656 		crc8_ccitt(0xff, (uint8_t *)&close_ate + SIZEOF_FIELD(struct zms_ate, crc8),
657 			   sizeof(struct zms_ate) - SIZEOF_FIELD(struct zms_ate, crc8));
658 
659 	corrupt_ate.id = 0xdeadbeef;
660 	corrupt_ate.offset = 0;
661 	corrupt_ate.len = 20;
662 	corrupt_ate.crc8 = 0xff; /* Incorrect crc8 */
663 
664 	/* Mark sector 0 as closed */
665 	err = flash_write(fixture->fs.flash_device,
666 			  fixture->fs.offset + fixture->fs.sector_size - 2 * sizeof(struct zms_ate),
667 			  &close_ate, sizeof(close_ate));
668 	zassert_true(err == 0, "flash_write failed: %d", err);
669 
670 	/* Write a corrupt ate */
671 	err = flash_write(fixture->fs.flash_device,
672 			  fixture->fs.offset + (fixture->fs.sector_size / 2), &corrupt_ate,
673 			  sizeof(corrupt_ate));
674 	zassert_true(err == 0, "flash_write failed: %d", err);
675 
676 	/* Mark sector 1 as closed */
677 	err = flash_write(fixture->fs.flash_device,
678 			  fixture->fs.offset + (2 * fixture->fs.sector_size) -
679 				  2 * sizeof(struct zms_ate),
680 			  &close_ate, sizeof(close_ate));
681 	zassert_true(err == 0, "flash_write failed: %d", err);
682 
683 	fixture->fs.sector_count = 3;
684 
685 	err = zms_mount(&fixture->fs);
686 	zassert_true(err == 0, "zms_mount call failure: %d", err);
687 }
688 
689 #ifdef CONFIG_ZMS_LOOKUP_CACHE
num_matching_cache_entries(uint64_t addr,bool compare_sector_only,struct zms_fs * fs)690 static size_t num_matching_cache_entries(uint64_t addr, bool compare_sector_only, struct zms_fs *fs)
691 {
692 	size_t num = 0;
693 	uint64_t mask = compare_sector_only ? ADDR_SECT_MASK : UINT64_MAX;
694 
695 	for (int i = 0; i < CONFIG_ZMS_LOOKUP_CACHE_SIZE; i++) {
696 		if ((fs->lookup_cache[i] & mask) == addr) {
697 			num++;
698 		}
699 	}
700 
701 	return num;
702 }
703 
num_occupied_cache_entries(struct zms_fs * fs)704 static size_t num_occupied_cache_entries(struct zms_fs *fs)
705 {
706 	return CONFIG_ZMS_LOOKUP_CACHE_SIZE -
707 	       num_matching_cache_entries(ZMS_LOOKUP_CACHE_NO_ADDR, false, fs);
708 }
709 #endif
710 
711 /*
712  * Test that ZMS lookup cache is properly rebuilt on zms_mount(), or initialized
713  * to ZMS_LOOKUP_CACHE_NO_ADDR if the store is empty.
714  */
ZTEST_F(zms,test_zms_cache_init)715 ZTEST_F(zms, test_zms_cache_init)
716 {
717 #ifdef CONFIG_ZMS_LOOKUP_CACHE
718 	int err;
719 	size_t num;
720 	uint64_t ate_addr;
721 	uint8_t data = 0;
722 
723 	/* Test cache initialization when the store is empty */
724 
725 	fixture->fs.sector_count = 3;
726 	err = zms_mount(&fixture->fs);
727 	zassert_true(err == 0, "zms_mount call failure: %d", err);
728 
729 	num = num_occupied_cache_entries(&fixture->fs);
730 	zassert_equal(num, 0, "uninitialized cache");
731 
732 	/* Test cache update after zms_write() */
733 
734 	ate_addr = fixture->fs.ate_wra;
735 	err = zms_write(&fixture->fs, 1, &data, sizeof(data));
736 	zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
737 
738 	num = num_occupied_cache_entries(&fixture->fs);
739 	zassert_equal(num, 1, "cache not updated after write");
740 
741 	num = num_matching_cache_entries(ate_addr, false, &fixture->fs);
742 	zassert_equal(num, 1, "invalid cache entry after write");
743 
744 	/* Test cache initialization when the store is non-empty */
745 
746 	memset(fixture->fs.lookup_cache, 0xAA, sizeof(fixture->fs.lookup_cache));
747 	err = zms_mount(&fixture->fs);
748 	zassert_true(err == 0, "zms_mount call failure: %d", err);
749 
750 	num = num_occupied_cache_entries(&fixture->fs);
751 	zassert_equal(num, 1, "uninitialized cache after restart");
752 
753 	num = num_matching_cache_entries(ate_addr, false, &fixture->fs);
754 	zassert_equal(num, 1, "invalid cache entry after restart");
755 #endif
756 }
757 
758 /*
759  * Test that even after writing more ZMS IDs than the number of ZMS lookup cache
760  * entries they all can be read correctly.
761  */
ZTEST_F(zms,test_zms_cache_collission)762 ZTEST_F(zms, test_zms_cache_collission)
763 {
764 #ifdef CONFIG_ZMS_LOOKUP_CACHE
765 	int err;
766 	uint16_t data;
767 
768 	fixture->fs.sector_count = 4;
769 	err = zms_mount(&fixture->fs);
770 	zassert_true(err == 0, "zms_mount call failure: %d", err);
771 
772 	for (int id = 0; id < CONFIG_ZMS_LOOKUP_CACHE_SIZE + 1; id++) {
773 		data = id;
774 		err = zms_write(&fixture->fs, id, &data, sizeof(data));
775 		zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
776 	}
777 
778 	for (int id = 0; id < CONFIG_ZMS_LOOKUP_CACHE_SIZE + 1; id++) {
779 		err = zms_read(&fixture->fs, id, &data, sizeof(data));
780 		zassert_equal(err, sizeof(data), "zms_read call failure: %d", err);
781 		zassert_equal(data, id, "incorrect data read");
782 	}
783 #endif
784 }
785 
786 /*
787  * Test that ZMS lookup cache does not contain any address from gc-ed sector
788  */
ZTEST_F(zms,test_zms_cache_gc)789 ZTEST_F(zms, test_zms_cache_gc)
790 {
791 #ifdef CONFIG_ZMS_LOOKUP_CACHE
792 	int err;
793 	size_t num;
794 	uint16_t data = 0;
795 
796 	fixture->fs.sector_count = 3;
797 	err = zms_mount(&fixture->fs);
798 	zassert_true(err == 0, "zms_mount call failure: %d", err);
799 
800 	/* Fill the first sector with writes of ID 1 */
801 
802 	while (fixture->fs.data_wra + sizeof(data) + sizeof(struct zms_ate) <=
803 	       fixture->fs.ate_wra) {
804 		++data;
805 		err = zms_write(&fixture->fs, 1, &data, sizeof(data));
806 		zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
807 	}
808 
809 	/* Verify that cache contains a single entry for sector 0 */
810 
811 	num = num_matching_cache_entries(0ULL << ADDR_SECT_SHIFT, true, &fixture->fs);
812 	zassert_equal(num, 1, "invalid cache content after filling sector 0");
813 
814 	/* Fill the second sector with writes of ID 2 */
815 
816 	while ((fixture->fs.ate_wra >> ADDR_SECT_SHIFT) != 2) {
817 		++data;
818 		err = zms_write(&fixture->fs, 2, &data, sizeof(data));
819 		zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
820 	}
821 
822 	/*
823 	 * At this point sector 0 should have been gc-ed. Verify that action is
824 	 * reflected by the cache content.
825 	 */
826 
827 	num = num_matching_cache_entries(0ULL << ADDR_SECT_SHIFT, true, &fixture->fs);
828 	zassert_equal(num, 0, "not invalidated cache entries aftetr gc");
829 
830 	num = num_matching_cache_entries(2ULL << ADDR_SECT_SHIFT, true, &fixture->fs);
831 	zassert_equal(num, 2, "invalid cache content after gc");
832 #endif
833 }
834 
835 /*
836  * Test ZMS lookup cache hash quality.
837  */
ZTEST_F(zms,test_zms_cache_hash_quality)838 ZTEST_F(zms, test_zms_cache_hash_quality)
839 {
840 #ifdef CONFIG_ZMS_LOOKUP_CACHE
841 	const size_t MIN_CACHE_OCCUPANCY = CONFIG_ZMS_LOOKUP_CACHE_SIZE * 6 / 10;
842 	int err;
843 	size_t num;
844 	uint32_t id;
845 	uint16_t data;
846 
847 	err = zms_mount(&fixture->fs);
848 	zassert_true(err == 0, "zms_mount call failure: %d", err);
849 
850 	/* Write ZMS IDs from 0 to CONFIG_ZMS_LOOKUP_CACHE_SIZE - 1 */
851 
852 	for (int i = 0; i < CONFIG_ZMS_LOOKUP_CACHE_SIZE; i++) {
853 		id = i;
854 		data = 0;
855 
856 		err = zms_write(&fixture->fs, id, &data, sizeof(data));
857 		zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
858 	}
859 
860 	/* Verify that at least 60% cache entries are occupied */
861 
862 	num = num_occupied_cache_entries(&fixture->fs);
863 	TC_PRINT("Cache occupancy: %u\n", (unsigned int)num);
864 	zassert_between_inclusive(num, MIN_CACHE_OCCUPANCY, CONFIG_ZMS_LOOKUP_CACHE_SIZE,
865 				  "too low cache occupancy - poor hash quality");
866 
867 	err = zms_clear(&fixture->fs);
868 	zassert_true(err == 0, "zms_clear call failure: %d", err);
869 
870 	err = zms_mount(&fixture->fs);
871 	zassert_true(err == 0, "zms_mount call failure: %d", err);
872 
873 	/* Write CONFIG_ZMS_LOOKUP_CACHE_SIZE ZMS IDs that form the following series: 0, 4, 8... */
874 
875 	for (int i = 0; i < CONFIG_ZMS_LOOKUP_CACHE_SIZE; i++) {
876 		id = i * 4;
877 		data = 0;
878 
879 		err = zms_write(&fixture->fs, id, &data, sizeof(data));
880 		zassert_equal(err, sizeof(data), "zms_write call failure: %d", err);
881 	}
882 
883 	/* Verify that at least 60% cache entries are occupied */
884 
885 	num = num_occupied_cache_entries(&fixture->fs);
886 	TC_PRINT("Cache occupancy: %u\n", (unsigned int)num);
887 	zassert_between_inclusive(num, MIN_CACHE_OCCUPANCY, CONFIG_ZMS_LOOKUP_CACHE_SIZE,
888 				  "too low cache occupancy - poor hash quality");
889 
890 #endif
891 }
892