xref: /spdk/test/unit/lib/ftl/ftl_sb/ftl_sb_ut.c (revision 6d6179ff420a322c5161a49a5af5bfd30e78674e)
1c8ab874dSKozlowski Mateusz /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2022 Intel Corporation.
3d9f2ae9dSMateusz Kozlowski  *   Copyright 2023 Solidigm All Rights Reserved
4c8ab874dSKozlowski Mateusz  *   All rights reserved.
5c8ab874dSKozlowski Mateusz  */
6c8ab874dSKozlowski Mateusz 
7c8ab874dSKozlowski Mateusz #include <sys/queue.h>
8c8ab874dSKozlowski Mateusz 
9c8ab874dSKozlowski Mateusz #include "spdk/stdinc.h"
10ae431e31SKonrad Sztyber #include "spdk_internal/cunit.h"
11c8ab874dSKozlowski Mateusz #include "common/lib/test_env.c"
12c8ab874dSKozlowski Mateusz 
132bb1753bSLukasz Lasek #include "ftl/utils/ftl_layout_tracker_bdev.c"
14fa1fc76cSLukasz Lasek #include "ftl/upgrade/ftl_sb_v3.c"
152bb1753bSLukasz Lasek #include "ftl/upgrade/ftl_sb_v5.c"
16c8ab874dSKozlowski Mateusz #include "ftl/ftl_sb.c"
172bb1753bSLukasz Lasek #include "ftl/ftl_layout.c"
18c8ab874dSKozlowski Mateusz #include "ftl/upgrade/ftl_sb_upgrade.c"
192bb1753bSLukasz Lasek 
202bb1753bSLukasz Lasek static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = {
212bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_SB] = {
222bb1753bSLukasz Lasek 		.latest_ver = FTL_SB_VERSION_CURRENT,
232bb1753bSLukasz Lasek 		.count = FTL_SB_VERSION_CURRENT,
242bb1753bSLukasz Lasek 	},
252bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_SB_BASE] = {
262bb1753bSLukasz Lasek 		.latest_ver = FTL_SB_VERSION_CURRENT,
272bb1753bSLukasz Lasek 		.count = FTL_SB_VERSION_CURRENT,
282bb1753bSLukasz Lasek 	},
292bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_L2P] = {},
302bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_BAND_MD] = {
312bb1753bSLukasz Lasek 		.latest_ver = FTL_BAND_VERSION_CURRENT,
322bb1753bSLukasz Lasek 		.count = FTL_BAND_VERSION_CURRENT,
332bb1753bSLukasz Lasek 	},
342bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = {
352bb1753bSLukasz Lasek 		.latest_ver = FTL_BAND_VERSION_CURRENT,
362bb1753bSLukasz Lasek 		.count = FTL_BAND_VERSION_CURRENT,
372bb1753bSLukasz Lasek 	},
382bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_VALID_MAP] = {},
392bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_NVC_MD] = {
402bb1753bSLukasz Lasek 		.latest_ver = FTL_NVC_VERSION_CURRENT,
412bb1753bSLukasz Lasek 		.count = FTL_NVC_VERSION_CURRENT,
422bb1753bSLukasz Lasek 	},
432bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = {
442bb1753bSLukasz Lasek 		.latest_ver = FTL_NVC_VERSION_CURRENT,
452bb1753bSLukasz Lasek 		.count = FTL_NVC_VERSION_CURRENT,
462bb1753bSLukasz Lasek 	},
472bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_DATA_NVC] = {},
482bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_DATA_BASE] = {},
492bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = {
502bb1753bSLukasz Lasek 		.latest_ver = FTL_P2L_VERSION_CURRENT,
512bb1753bSLukasz Lasek 		.count = FTL_P2L_VERSION_CURRENT,
522bb1753bSLukasz Lasek 	},
532bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = {
542bb1753bSLukasz Lasek 		.latest_ver = FTL_P2L_VERSION_CURRENT,
552bb1753bSLukasz Lasek 		.count = FTL_P2L_VERSION_CURRENT,
562bb1753bSLukasz Lasek 	},
572bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = {
582bb1753bSLukasz Lasek 		.latest_ver = FTL_P2L_VERSION_CURRENT,
592bb1753bSLukasz Lasek 		.count = FTL_P2L_VERSION_CURRENT,
602bb1753bSLukasz Lasek 	},
612bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = {
622bb1753bSLukasz Lasek 		.latest_ver = FTL_P2L_VERSION_CURRENT,
632bb1753bSLukasz Lasek 		.count = FTL_P2L_VERSION_CURRENT,
642bb1753bSLukasz Lasek 	},
652bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_TRIM_MD] = {},
662bb1753bSLukasz Lasek 	[FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = {},
672d613454SMateusz Kozlowski 	[FTL_LAYOUT_REGION_TYPE_TRIM_LOG] = {},
682d613454SMateusz Kozlowski 	[FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR] = {},
69*6d6179ffSMateusz Kozlowski 	[FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN] = {},
70*6d6179ffSMateusz Kozlowski 	[FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX] = {},
712bb1753bSLukasz Lasek };
722bb1753bSLukasz Lasek 
73c8ab874dSKozlowski Mateusz #include "ftl/upgrade/ftl_layout_upgrade.c"
74c8ab874dSKozlowski Mateusz #include "ftl/mngt/ftl_mngt_md.c"
75c8ab874dSKozlowski Mateusz 
76c8ab874dSKozlowski Mateusz DEFINE_STUB_V(ftl_mngt_fail_step, (struct ftl_mngt_process *mngt));
77c8ab874dSKozlowski Mateusz DEFINE_STUB_V(ftl_mngt_next_step, (struct ftl_mngt_process *mngt));
78c8ab874dSKozlowski Mateusz DEFINE_STUB_V(ftl_md_persist, (struct ftl_md *md));
79c8ab874dSKozlowski Mateusz DEFINE_STUB(ftl_nv_cache_load_state, int, (struct ftl_nv_cache *nv_cache), 0);
80c8ab874dSKozlowski Mateusz DEFINE_STUB_V(ftl_valid_map_load_state, (struct spdk_ftl_dev *dev));
81cb00e90aSMateusz Kozlowski DEFINE_STUB(ftl_bands_load_state, int, (struct spdk_ftl_dev *dev), 0);
82c8ab874dSKozlowski Mateusz DEFINE_STUB(ftl_md_get_region, const struct ftl_layout_region *, (struct ftl_md *md), 0);
83c8ab874dSKozlowski Mateusz DEFINE_STUB_V(ftl_md_restore, (struct ftl_md *md));
84c8ab874dSKozlowski Mateusz DEFINE_STUB(ftl_nv_cache_save_state, int, (struct ftl_nv_cache *nv_cache), 0);
85c8ab874dSKozlowski Mateusz DEFINE_STUB(ftl_mngt_get_step_ctx, void *, (struct ftl_mngt_process *mngt), 0);
86c8ab874dSKozlowski Mateusz DEFINE_STUB_V(ftl_mngt_persist_bands_p2l, (struct ftl_mngt_process *mngt));
87c8ab874dSKozlowski Mateusz DEFINE_STUB_V(ftl_band_init_gc_iter, (struct spdk_ftl_dev *dev));
88c8ab874dSKozlowski Mateusz DEFINE_STUB(ftl_md_create_region_flags, int, (struct spdk_ftl_dev *dev, int region_type), 0);
89c8ab874dSKozlowski Mateusz DEFINE_STUB(ftl_md_create, struct ftl_md *, (struct spdk_ftl_dev *dev, uint64_t blocks,
90c8ab874dSKozlowski Mateusz 		uint64_t vss_blksz, const char *name, int flags, const struct ftl_layout_region *region), NULL);
91c8ab874dSKozlowski Mateusz DEFINE_STUB(ftl_md_destroy_region_flags, int, (struct spdk_ftl_dev *dev, int region_type), 0);
92c8ab874dSKozlowski Mateusz DEFINE_STUB(ftl_md_destroy_shm_flags, int, (struct spdk_ftl_dev *dev), 0);
93c8ab874dSKozlowski Mateusz DEFINE_STUB_V(ftl_md_destroy, (struct ftl_md *md, int flags));
94c8ab874dSKozlowski Mateusz DEFINE_STUB_V(ftl_mngt_call_process, (struct ftl_mngt_process *mngt,
959452abe6SMateusz Kozlowski 				      const struct ftl_mngt_process_desc *process,
969452abe6SMateusz Kozlowski 				      void *init_ctx));
97c8ab874dSKozlowski Mateusz DEFINE_STUB(ftl_md_get_buffer, void *, (struct ftl_md *md), NULL);
982bb1753bSLukasz Lasek DEFINE_STUB(spdk_bdev_desc_get_bdev, struct spdk_bdev *, (struct spdk_bdev_desc *desc), NULL);
992bb1753bSLukasz Lasek DEFINE_STUB(spdk_bdev_get_write_unit_size, uint32_t, (const struct spdk_bdev *bdev), 0);
1002bb1753bSLukasz Lasek DEFINE_STUB(spdk_bdev_get_num_blocks, uint64_t, (const struct spdk_bdev *bdev), 0);
1012bb1753bSLukasz Lasek DEFINE_STUB(ftl_nv_cache_chunk_tail_md_num_blocks, size_t, (const struct ftl_nv_cache *nv_cache),
1022bb1753bSLukasz Lasek 	    0);
1032bb1753bSLukasz Lasek DEFINE_STUB(ftl_band_user_blocks, size_t, (const struct ftl_band *band), 0);
1042bb1753bSLukasz Lasek 
1052bb1753bSLukasz Lasek struct spdk_bdev_desc {
1062bb1753bSLukasz Lasek 	int dummy;
1072bb1753bSLukasz Lasek };
108c8ab874dSKozlowski Mateusz 
109c8ab874dSKozlowski Mateusz struct spdk_ftl_dev g_dev;
110c8ab874dSKozlowski Mateusz struct ftl_superblock_shm g_sb_shm = {0};
1112bb1753bSLukasz Lasek struct ftl_base_device_type g_base_type = { .name = "base_dev" };
11226f3b551SMateusz Kozlowski struct ftl_nv_cache_device_type g_nvc_type = { .name = "nvc_dev" };
1132bb1753bSLukasz Lasek struct spdk_bdev_desc g_base_bdev_desc = {0};
1142bb1753bSLukasz Lasek struct spdk_bdev_desc g_nvc_bdev_desc = {0};
115c8ab874dSKozlowski Mateusz static uint8_t g_sb_buf[FTL_SUPERBLOCK_SIZE] = {0};
116c8ab874dSKozlowski Mateusz 
117c8ab874dSKozlowski Mateusz struct ftl_region_upgrade_desc p2l_upgrade_desc[0];
118c8ab874dSKozlowski Mateusz struct ftl_region_upgrade_desc nvc_upgrade_desc[0];
119c8ab874dSKozlowski Mateusz struct ftl_region_upgrade_desc band_upgrade_desc[0];
120c8ab874dSKozlowski Mateusz 
121c8ab874dSKozlowski Mateusz #define TEST_OP 0x1984
122c8ab874dSKozlowski Mateusz #define TEST_REG_BLKS 0x10000
123c8ab874dSKozlowski Mateusz #define TEST_NVC_BLKS 0x1000000;
124c8ab874dSKozlowski Mateusz #define TEST_BASE_BLKS 0x1000000000;
125c8ab874dSKozlowski Mateusz 
126c8ab874dSKozlowski Mateusz static int
127c8ab874dSKozlowski Mateusz test_setup(void)
128c8ab874dSKozlowski Mateusz {
1292bb1753bSLukasz Lasek 	int regno_nvc = 0, regno_base = 0, *regno_dev;
1302bb1753bSLukasz Lasek 
131c8ab874dSKozlowski Mateusz 	/* setup a dummy dev: */
132c8ab874dSKozlowski Mateusz 	g_dev.sb = (void *)g_sb_buf;
133c8ab874dSKozlowski Mateusz 	g_dev.sb_shm = &g_sb_shm;
134c8ab874dSKozlowski Mateusz 	g_dev.conf.overprovisioning = TEST_OP;
135c8ab874dSKozlowski Mateusz 	for (uint64_t n = 0; n < sizeof(g_dev.conf.uuid); n++) {
136c8ab874dSKozlowski Mateusz 		g_dev.conf.uuid.u.raw[n] = n;
137c8ab874dSKozlowski Mateusz 	}
138c8ab874dSKozlowski Mateusz 
139c8ab874dSKozlowski Mateusz 	g_dev.layout.nvc.total_blocks = TEST_NVC_BLKS;
140c8ab874dSKozlowski Mateusz 	g_dev.layout.base.total_blocks = TEST_BASE_BLKS;
1412bb1753bSLukasz Lasek 	g_dev.base_type = &g_base_type;
14226f3b551SMateusz Kozlowski 	g_dev.nv_cache.nvc_type = &g_nvc_type;
1432bb1753bSLukasz Lasek 	g_dev.base_layout_tracker = ftl_layout_tracker_bdev_init(UINT32_MAX);
1442bb1753bSLukasz Lasek 	g_dev.nvc_layout_tracker = ftl_layout_tracker_bdev_init(UINT32_MAX);
1452bb1753bSLukasz Lasek 	g_dev.base_bdev_desc = &g_base_bdev_desc;
1462bb1753bSLukasz Lasek 	g_dev.nv_cache.bdev_desc = &g_nvc_bdev_desc;
147c8ab874dSKozlowski Mateusz 
148c8ab874dSKozlowski Mateusz 	for (int regno = 0; regno < FTL_LAYOUT_REGION_TYPE_MAX; regno++) {
149c8ab874dSKozlowski Mateusz 		struct ftl_layout_region *reg = &g_dev.layout.region[regno];
1502bb1753bSLukasz Lasek 
151c8ab874dSKozlowski Mateusz 		reg->current.blocks = TEST_REG_BLKS;
1522bb1753bSLukasz Lasek 		regno_dev = sb_v3_md_region_is_nvc(regno) ? &regno_nvc : &regno_base;
1532bb1753bSLukasz Lasek 		reg->current.offset = *regno_dev * TEST_REG_BLKS;
1542bb1753bSLukasz Lasek 		(*regno_dev)++;
1552bb1753bSLukasz Lasek 		reg->current.version = ftl_layout_upgrade_region_get_latest_version(regno);
156c8ab874dSKozlowski Mateusz 		reg->type = regno;
157c8ab874dSKozlowski Mateusz 		reg->name = "region_test";
1582bb1753bSLukasz Lasek 		reg->bdev_desc = sb_v3_md_region_is_nvc(regno) ? &g_nvc_bdev_desc : &g_base_bdev_desc;
159c8ab874dSKozlowski Mateusz 		reg->ioch = 0;
160c8ab874dSKozlowski Mateusz 	}
161c8ab874dSKozlowski Mateusz 	return 0;
162c8ab874dSKozlowski Mateusz }
163c8ab874dSKozlowski Mateusz 
1642bb1753bSLukasz Lasek static int
1652bb1753bSLukasz Lasek test_teardown(void)
1662bb1753bSLukasz Lasek {
1672bb1753bSLukasz Lasek 	if (g_dev.base_layout_tracker) {
1682bb1753bSLukasz Lasek 		ftl_layout_tracker_bdev_fini(g_dev.base_layout_tracker);
1692bb1753bSLukasz Lasek 		g_dev.base_layout_tracker = NULL;
1702bb1753bSLukasz Lasek 	}
1712bb1753bSLukasz Lasek 	if (g_dev.nvc_layout_tracker) {
1722bb1753bSLukasz Lasek 		ftl_layout_tracker_bdev_fini(g_dev.nvc_layout_tracker);
1732bb1753bSLukasz Lasek 		g_dev.nvc_layout_tracker = NULL;
1742bb1753bSLukasz Lasek 	}
1752bb1753bSLukasz Lasek 	return 0;
1762bb1753bSLukasz Lasek }
1772bb1753bSLukasz Lasek 
178c8ab874dSKozlowski Mateusz static void
179c8ab874dSKozlowski Mateusz test_setup_sb_ver(uint64_t ver, uint64_t clean)
180c8ab874dSKozlowski Mateusz {
181c8ab874dSKozlowski Mateusz 	union ftl_superblock_ver *sb = (void *)g_sb_buf;
1822bb1753bSLukasz Lasek 	uint64_t zero_offs;
183c8ab874dSKozlowski Mateusz 
184c8ab874dSKozlowski Mateusz 	memset(&g_sb_buf, 0, sizeof(g_sb_buf));
185c8ab874dSKozlowski Mateusz 	ftl_mngt_init_default_sb(&g_dev, NULL);
186c8ab874dSKozlowski Mateusz 	if (ver <= FTL_SB_VERSION_3) {
187c8ab874dSKozlowski Mateusz 		sb->header.magic = FTL_SUPERBLOCK_MAGIC_V2;
188c8ab874dSKozlowski Mateusz 	}
189c8ab874dSKozlowski Mateusz 	sb->header.version = ver;
1902bb1753bSLukasz Lasek 
1912bb1753bSLukasz Lasek 	switch (ver) {
1922bb1753bSLukasz Lasek 	case FTL_SB_VERSION_0:
1932bb1753bSLukasz Lasek 	case FTL_SB_VERSION_1:
1942bb1753bSLukasz Lasek 	case FTL_SB_VERSION_2:
1952bb1753bSLukasz Lasek 		zero_offs = sizeof(struct ftl_superblock_v2);
1962bb1753bSLukasz Lasek 		memset(g_sb_buf + zero_offs, 0, sizeof(g_sb_buf) - zero_offs);
197c8ab874dSKozlowski Mateusz 		sb->v2.clean = clean;
1982bb1753bSLukasz Lasek 		break;
1992bb1753bSLukasz Lasek 
2002bb1753bSLukasz Lasek 	case FTL_SB_VERSION_3:
2012bb1753bSLukasz Lasek 	case FTL_SB_VERSION_4:
2022bb1753bSLukasz Lasek 		zero_offs = sizeof(struct ftl_superblock_v3);
2032bb1753bSLukasz Lasek 		memset(g_sb_buf + zero_offs, 0, sizeof(g_sb_buf) - zero_offs);
2042bb1753bSLukasz Lasek 		sb->v3.clean = clean;
2052bb1753bSLukasz Lasek 		sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_INVALID;
2062bb1753bSLukasz Lasek 		break;
2072bb1753bSLukasz Lasek 
2082bb1753bSLukasz Lasek 	case FTL_SB_VERSION_5:
2092bb1753bSLukasz Lasek 		zero_offs = sizeof(struct ftl_superblock_v5);
2102bb1753bSLukasz Lasek 		memset(g_sb_buf + zero_offs, 0, sizeof(g_sb_buf) - zero_offs);
2112bb1753bSLukasz Lasek 		sb->v5.clean = clean;
2122bb1753bSLukasz Lasek 		break;
2132bb1753bSLukasz Lasek 	}
2142bb1753bSLukasz Lasek 
215fa1fc76cSLukasz Lasek 	sb->header.crc = get_sb_crc(&sb->current);
216c8ab874dSKozlowski Mateusz }
217c8ab874dSKozlowski Mateusz 
218c8ab874dSKozlowski Mateusz static void
219c8ab874dSKozlowski Mateusz test_setup_sb_v2(uint64_t clean)
220c8ab874dSKozlowski Mateusz {
221c8ab874dSKozlowski Mateusz 	test_setup_sb_ver(FTL_SB_VERSION_2, clean);
222c8ab874dSKozlowski Mateusz }
223c8ab874dSKozlowski Mateusz 
224c8ab874dSKozlowski Mateusz static void
225c8ab874dSKozlowski Mateusz test_setup_sb_v3(uint64_t clean)
226c8ab874dSKozlowski Mateusz {
2272bb1753bSLukasz Lasek 	test_setup_sb_ver(FTL_SB_VERSION_3, clean);
2282bb1753bSLukasz Lasek }
229c8ab874dSKozlowski Mateusz 
2302bb1753bSLukasz Lasek static void
2312bb1753bSLukasz Lasek test_setup_sb_v5(uint64_t clean)
2322bb1753bSLukasz Lasek {
2332bb1753bSLukasz Lasek 	test_setup_sb_ver(FTL_SB_VERSION_5, clean);
234c8ab874dSKozlowski Mateusz }
235c8ab874dSKozlowski Mateusz 
236c8ab874dSKozlowski Mateusz static void
237c8ab874dSKozlowski Mateusz test_sb_crc_v2(void)
238c8ab874dSKozlowski Mateusz {
239c8ab874dSKozlowski Mateusz 	union ftl_superblock_ver *sb = (void *)g_sb_buf;
240c8ab874dSKozlowski Mateusz 	uint64_t crc;
241c8ab874dSKozlowski Mateusz 
242c8ab874dSKozlowski Mateusz 	/* v2-specific crc: it's not really working */
243c8ab874dSKozlowski Mateusz 	test_setup_sb_v2(true);
244c8ab874dSKozlowski Mateusz 	crc = sb->header.crc;
245c8ab874dSKozlowski Mateusz 
246c8ab874dSKozlowski Mateusz 	sb->header.crc++;
247fa1fc76cSLukasz Lasek 	sb->header.crc = get_sb_crc(&sb->current);
248c8ab874dSKozlowski Mateusz 	CU_ASSERT_EQUAL(crc, sb->header.crc);
249c8ab874dSKozlowski Mateusz 
250c8ab874dSKozlowski Mateusz 	g_sb_buf[sizeof(struct ftl_superblock_v2)]++;
251fa1fc76cSLukasz Lasek 	sb->header.crc = get_sb_crc(&sb->current);
252c8ab874dSKozlowski Mateusz 	CU_ASSERT_EQUAL(crc, sb->header.crc);
253c8ab874dSKozlowski Mateusz 
254c8ab874dSKozlowski Mateusz 	g_sb_buf[sizeof(g_sb_buf) - 1]++;
255fa1fc76cSLukasz Lasek 	sb->header.crc = get_sb_crc(&sb->current);
256c8ab874dSKozlowski Mateusz 	CU_ASSERT_EQUAL(crc, sb->header.crc);
257c8ab874dSKozlowski Mateusz }
258c8ab874dSKozlowski Mateusz 
259c8ab874dSKozlowski Mateusz static void
260c8ab874dSKozlowski Mateusz test_sb_crc_v3(void)
261c8ab874dSKozlowski Mateusz {
262c8ab874dSKozlowski Mateusz 	union ftl_superblock_ver *sb = (void *)g_sb_buf;
263c8ab874dSKozlowski Mateusz 	uint64_t crc;
264c8ab874dSKozlowski Mateusz 
265c8ab874dSKozlowski Mateusz 	/* v3 crc: covers the entire buf */
266c8ab874dSKozlowski Mateusz 	test_setup_sb_v3(true);
267c8ab874dSKozlowski Mateusz 	crc = sb->header.crc;
268c8ab874dSKozlowski Mateusz 
269c8ab874dSKozlowski Mateusz 	sb->header.crc++;
270fa1fc76cSLukasz Lasek 	sb->header.crc = get_sb_crc(&sb->current);
271c8ab874dSKozlowski Mateusz 	CU_ASSERT_EQUAL(crc, sb->header.crc);
272c8ab874dSKozlowski Mateusz 	crc = sb->header.crc;
273c8ab874dSKozlowski Mateusz 
274c8ab874dSKozlowski Mateusz 	g_sb_buf[sizeof(struct ftl_superblock_v2)]++;
275fa1fc76cSLukasz Lasek 	sb->header.crc = get_sb_crc(&sb->current);
276c8ab874dSKozlowski Mateusz 	CU_ASSERT_NOT_EQUAL(crc, sb->header.crc);
277c8ab874dSKozlowski Mateusz 	crc = sb->header.crc;
278c8ab874dSKozlowski Mateusz 
279c8ab874dSKozlowski Mateusz 	g_sb_buf[sizeof(g_sb_buf) - 1]++;
280fa1fc76cSLukasz Lasek 	sb->header.crc = get_sb_crc(&sb->current);
281c8ab874dSKozlowski Mateusz 	CU_ASSERT_NOT_EQUAL(crc, sb->header.crc);
282c8ab874dSKozlowski Mateusz 	crc = sb->header.crc;
283c8ab874dSKozlowski Mateusz 
284c8ab874dSKozlowski Mateusz 	CU_ASSERT_EQUAL(crc, sb->header.crc);
2852bb1753bSLukasz Lasek }
2862bb1753bSLukasz Lasek 
2872bb1753bSLukasz Lasek static int
2882bb1753bSLukasz Lasek test_superblock_v3_md_layout_add(struct spdk_ftl_dev *dev,
2892bb1753bSLukasz Lasek 				 struct ftl_superblock_v3_md_region *sb_reg,
2902bb1753bSLukasz Lasek 				 uint32_t reg_type, uint32_t reg_version, uint64_t blk_offs, uint64_t blk_sz)
2912bb1753bSLukasz Lasek {
2922bb1753bSLukasz Lasek 	if (ftl_superblock_v3_md_region_overflow(dev, sb_reg)) {
2932bb1753bSLukasz Lasek 		return -EOVERFLOW;
2942bb1753bSLukasz Lasek 	}
2952bb1753bSLukasz Lasek 
2962bb1753bSLukasz Lasek 	sb_reg->type = reg_type;
2972bb1753bSLukasz Lasek 	sb_reg->version = reg_version;
2982bb1753bSLukasz Lasek 	sb_reg->blk_offs = blk_offs;
2992bb1753bSLukasz Lasek 	sb_reg->blk_sz = blk_sz;
3002bb1753bSLukasz Lasek 	return 0;
3012bb1753bSLukasz Lasek }
3022bb1753bSLukasz Lasek 
3032bb1753bSLukasz Lasek static int
3042bb1753bSLukasz Lasek test_superblock_v3_md_layout_add_free(struct spdk_ftl_dev *dev,
3052bb1753bSLukasz Lasek 				      struct ftl_superblock_v3_md_region **sb_reg,
3062bb1753bSLukasz Lasek 				      uint32_t reg_type, uint32_t free_type, uint64_t total_blocks)
3072bb1753bSLukasz Lasek {
3082bb1753bSLukasz Lasek 	struct ftl_layout *layout = &dev->layout;
3092bb1753bSLukasz Lasek 	struct ftl_layout_region *reg = &layout->region[reg_type];
3102bb1753bSLukasz Lasek 	uint64_t blks_left = total_blocks - reg->current.offset - reg->current.blocks;
3112bb1753bSLukasz Lasek 
3122bb1753bSLukasz Lasek 	if (blks_left == 0) {
3132bb1753bSLukasz Lasek 		return 0;
3142bb1753bSLukasz Lasek 	}
3152bb1753bSLukasz Lasek 
3162bb1753bSLukasz Lasek 	(*sb_reg)->df_next = ftl_df_get_obj_id(dev->sb, (*sb_reg) + 1);
3172bb1753bSLukasz Lasek 	(*sb_reg) = (*sb_reg) + 1;
3182bb1753bSLukasz Lasek 
3192bb1753bSLukasz Lasek 	if (test_superblock_v3_md_layout_add(dev, *sb_reg, free_type, 0,
3202bb1753bSLukasz Lasek 					     reg->current.offset + reg->current.blocks, blks_left)) {
3212bb1753bSLukasz Lasek 		return -1;
3222bb1753bSLukasz Lasek 	}
3232bb1753bSLukasz Lasek 
3242bb1753bSLukasz Lasek 	(*sb_reg)->df_next = FTL_DF_OBJ_ID_INVALID;
3252bb1753bSLukasz Lasek 
3262bb1753bSLukasz Lasek 	return 0;
3272bb1753bSLukasz Lasek }
3282bb1753bSLukasz Lasek 
3292bb1753bSLukasz Lasek static int
3302bb1753bSLukasz Lasek test_ftl_superblock_v3_md_layout_build(struct spdk_ftl_dev *dev)
3312bb1753bSLukasz Lasek {
3322bb1753bSLukasz Lasek 	union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)dev->sb;
3332bb1753bSLukasz Lasek 	struct ftl_layout *layout = &dev->layout;
3342bb1753bSLukasz Lasek 	struct ftl_layout_region *reg;
3352bb1753bSLukasz Lasek 	int n = 0;
3362bb1753bSLukasz Lasek 	bool is_empty = ftl_superblock_v3_md_layout_is_empty(sb_ver);
3372bb1753bSLukasz Lasek 	struct ftl_superblock_v3_md_region *sb_reg = &sb_ver->v3.md_layout_head;
3382bb1753bSLukasz Lasek 
3392bb1753bSLukasz Lasek 	/* TODO: major upgrades: add all free regions being tracked
3402bb1753bSLukasz Lasek 	 * For now SB MD layout must be empty - otherwise md free regions may be lost */
3412bb1753bSLukasz Lasek 	assert(is_empty);
3422bb1753bSLukasz Lasek 
3432bb1753bSLukasz Lasek 	for (; n < FTL_LAYOUT_REGION_TYPE_MAX_V3;) {
3442bb1753bSLukasz Lasek 		reg = ftl_layout_region_get(dev, n);
3452bb1753bSLukasz Lasek 		assert(reg);
3462bb1753bSLukasz Lasek 		if (md_region_is_fixed(reg->type)) {
3472bb1753bSLukasz Lasek 			n++;
3482bb1753bSLukasz Lasek 
3492bb1753bSLukasz Lasek 			if (n >= FTL_LAYOUT_REGION_TYPE_MAX_V3) {
3502bb1753bSLukasz Lasek 				/* For VSS emulation the last layout type is a fixed region, we need to move back the list and end the list on previous entry */
3512bb1753bSLukasz Lasek 				sb_reg--;
3522bb1753bSLukasz Lasek 				break;
3532bb1753bSLukasz Lasek 			}
3542bb1753bSLukasz Lasek 			continue;
3552bb1753bSLukasz Lasek 		}
3562bb1753bSLukasz Lasek 
3572bb1753bSLukasz Lasek 		if (test_superblock_v3_md_layout_add(dev, sb_reg, reg->type, reg->current.version,
3582bb1753bSLukasz Lasek 						     reg->current.offset, reg->current.blocks)) {
3592bb1753bSLukasz Lasek 			return -1;
3602bb1753bSLukasz Lasek 		}
3612bb1753bSLukasz Lasek 
3622bb1753bSLukasz Lasek 		n++;
3632bb1753bSLukasz Lasek 		if (n < FTL_LAYOUT_REGION_TYPE_MAX_V3) {
3642bb1753bSLukasz Lasek 			/* next region */
3652bb1753bSLukasz Lasek 			sb_reg->df_next = ftl_df_get_obj_id(sb_ver, sb_reg + 1);
3662bb1753bSLukasz Lasek 			sb_reg++;
3672bb1753bSLukasz Lasek 		}
3682bb1753bSLukasz Lasek 	}
3692bb1753bSLukasz Lasek 
3702bb1753bSLukasz Lasek 	/* terminate the list */
3712bb1753bSLukasz Lasek 	sb_reg->df_next = FTL_DF_OBJ_ID_INVALID;
3722bb1753bSLukasz Lasek 
3732bb1753bSLukasz Lasek 	/* create free_nvc/free_base regions on the first run */
3742bb1753bSLukasz Lasek 	if (is_empty) {
3752bb1753bSLukasz Lasek 		test_superblock_v3_md_layout_add_free(dev, &sb_reg, FTL_LAYOUT_REGION_LAST_NVC,
3762bb1753bSLukasz Lasek 						      FTL_LAYOUT_REGION_TYPE_FREE_NVC, layout->nvc.total_blocks);
3772bb1753bSLukasz Lasek 
3782bb1753bSLukasz Lasek 		test_superblock_v3_md_layout_add_free(dev, &sb_reg, FTL_LAYOUT_REGION_LAST_BASE,
3792bb1753bSLukasz Lasek 						      FTL_LAYOUT_REGION_TYPE_FREE_BASE, layout->base.total_blocks);
3802bb1753bSLukasz Lasek 	}
3812bb1753bSLukasz Lasek 
3822bb1753bSLukasz Lasek 	return 0;
3832bb1753bSLukasz Lasek }
3842bb1753bSLukasz Lasek 
3852bb1753bSLukasz Lasek static void
3862bb1753bSLukasz Lasek test_sb_v3_region_reinit(void)
3872bb1753bSLukasz Lasek {
3882bb1753bSLukasz Lasek 	uint32_t reg_type;
3892bb1753bSLukasz Lasek 
3902bb1753bSLukasz Lasek 	for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) {
3912bb1753bSLukasz Lasek 		g_dev.layout.region[reg_type].type = reg_type;
3922bb1753bSLukasz Lasek 	}
3932bb1753bSLukasz Lasek }
3942bb1753bSLukasz Lasek 
3952bb1753bSLukasz Lasek static struct ftl_superblock_v3_md_region *
3962bb1753bSLukasz Lasek test_sb_v3_find_region_ver(enum ftl_layout_region_type reg_type, uint32_t reg_ver)
3972bb1753bSLukasz Lasek {
3982bb1753bSLukasz Lasek 	union ftl_superblock_ver *sb = (void *)g_sb_buf;
3992bb1753bSLukasz Lasek 	struct ftl_superblock_v3_md_region *sb_reg = &sb->v3.md_layout_head;
4002bb1753bSLukasz Lasek 
4012bb1753bSLukasz Lasek 	while (sb_reg->type != FTL_LAYOUT_REGION_TYPE_INVALID) {
4022bb1753bSLukasz Lasek 		if (sb_reg->type == reg_type && sb_reg->version == reg_ver) {
4032bb1753bSLukasz Lasek 			return sb_reg;
4042bb1753bSLukasz Lasek 		}
4052bb1753bSLukasz Lasek 
4062bb1753bSLukasz Lasek 		if (sb_reg->df_next == FTL_DF_OBJ_ID_INVALID) {
4072bb1753bSLukasz Lasek 			break;
4082bb1753bSLukasz Lasek 		}
4092bb1753bSLukasz Lasek 
4102bb1753bSLukasz Lasek 		if (UINT64_MAX - (uintptr_t)sb <= sb_reg->df_next) {
4112bb1753bSLukasz Lasek 			return NULL;
4122bb1753bSLukasz Lasek 		}
4132bb1753bSLukasz Lasek 
4142bb1753bSLukasz Lasek 		sb_reg = ftl_df_get_obj_ptr(sb, sb_reg->df_next);
4152bb1753bSLukasz Lasek 		if (ftl_superblock_v3_md_region_overflow(&g_dev, sb_reg)) {
4162bb1753bSLukasz Lasek 			return NULL;
4172bb1753bSLukasz Lasek 		}
4182bb1753bSLukasz Lasek 	}
4192bb1753bSLukasz Lasek 
4202bb1753bSLukasz Lasek 	return NULL;
4212bb1753bSLukasz Lasek }
4222bb1753bSLukasz Lasek 
4232bb1753bSLukasz Lasek static struct ftl_superblock_v3_md_region *
4242bb1753bSLukasz Lasek test_sb_v3_find_region_latest(enum ftl_layout_region_type reg_type)
4252bb1753bSLukasz Lasek {
4262bb1753bSLukasz Lasek 	return test_sb_v3_find_region_ver(reg_type, ftl_layout_upgrade_region_get_latest_version(reg_type));
427c8ab874dSKozlowski Mateusz }
428c8ab874dSKozlowski Mateusz 
429c8ab874dSKozlowski Mateusz static void
430c8ab874dSKozlowski Mateusz test_sb_v3_md_layout(void)
431c8ab874dSKozlowski Mateusz {
4322bb1753bSLukasz Lasek 	struct ftl_superblock_v3_md_region *sb_reg, *sb_reg_next, *sb_reg_next2;
4332bb1753bSLukasz Lasek 	struct ftl_layout_region *reg_head, *reg;
434c8ab874dSKozlowski Mateusz 	union ftl_superblock_ver *sb = (void *)g_sb_buf;
4352bb1753bSLukasz Lasek 	ftl_df_obj_id df_next_head, df_next_reg;
4362bb1753bSLukasz Lasek 	uint32_t md_type_head;
437c8ab874dSKozlowski Mateusz 	int rc;
438c8ab874dSKozlowski Mateusz 
439c8ab874dSKozlowski Mateusz 	test_setup_sb_v3(false);
4402bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(ftl_superblock_is_blob_area_empty(&sb->current), true);
441c8ab874dSKozlowski Mateusz 
442c8ab874dSKozlowski Mateusz 	/* load failed: empty md list: */
443fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
444c8ab874dSKozlowski Mateusz 	CU_ASSERT_NOT_EQUAL(rc, 0);
4452bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
446c8ab874dSKozlowski Mateusz 
447c8ab874dSKozlowski Mateusz 	/* create md layout: */
4482bb1753bSLukasz Lasek 	test_ftl_superblock_v3_md_layout_build(&g_dev);
4492bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(ftl_superblock_is_blob_area_empty(&sb->current), false);
450c8ab874dSKozlowski Mateusz 
451c8ab874dSKozlowski Mateusz 	/* buf overflow, sb_reg = 1 byte overflow: */
4522bb1753bSLukasz Lasek 	df_next_head = sb->v3.md_layout_head.df_next;
453c8ab874dSKozlowski Mateusz 	sb->v3.md_layout_head.df_next = FTL_SUPERBLOCK_SIZE - sizeof(sb->v3.md_layout_head) + 1;
454fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
455c8ab874dSKozlowski Mateusz 	CU_ASSERT_EQUAL(rc, -EOVERFLOW);
4562bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
457c8ab874dSKozlowski Mateusz 
458c8ab874dSKozlowski Mateusz 	/* buf underflow, sb_reg = -1: */
459c8ab874dSKozlowski Mateusz 	sb->v3.md_layout_head.df_next = UINTPTR_MAX - (uintptr_t)sb;
460fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
461c8ab874dSKozlowski Mateusz 	CU_ASSERT_EQUAL(rc, -EOVERFLOW);
4622bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
463c8ab874dSKozlowski Mateusz 
464c8ab874dSKozlowski Mateusz 	/* buf underflow, sb_reg = 2 bytes underflow */
465c8ab874dSKozlowski Mateusz 	sb->v3.md_layout_head.df_next = UINTPTR_MAX - 1;
466fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
467c8ab874dSKozlowski Mateusz 	CU_ASSERT_EQUAL(rc, -EOVERFLOW);
4682bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
469c8ab874dSKozlowski Mateusz 
470c8ab874dSKozlowski Mateusz 	/* looping md layout list: */
471c8ab874dSKozlowski Mateusz 	sb->v3.md_layout_head.df_next = ftl_df_get_obj_id(sb, &sb->v3.md_layout_head);
472fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
473c8ab874dSKozlowski Mateusz 	CU_ASSERT_NOT_EQUAL(rc, 0);
4742bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
475c8ab874dSKozlowski Mateusz 
4762bb1753bSLukasz Lasek 	sb->v3.md_layout_head.df_next = df_next_head;
477c8ab874dSKozlowski Mateusz 
478c8ab874dSKozlowski Mateusz 	/* unsupported/fixed md region: */
4792bb1753bSLukasz Lasek 	md_type_head = sb->v3.md_layout_head.type;
480c8ab874dSKozlowski Mateusz 	sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_SB;
481fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
482c8ab874dSKozlowski Mateusz 	CU_ASSERT_NOT_EQUAL(rc, 0);
4832bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
484c8ab874dSKozlowski Mateusz 
485c8ab874dSKozlowski Mateusz 	/* unsupported/invalid md region: */
486c8ab874dSKozlowski Mateusz 	sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_MAX;
487fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
488c8ab874dSKozlowski Mateusz 	CU_ASSERT_NOT_EQUAL(rc, 0);
4892bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
4902bb1753bSLukasz Lasek 
4912bb1753bSLukasz Lasek 	/* unsupported/invalid md region: */
4922bb1753bSLukasz Lasek 	sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_MAX_V3;
4932bb1753bSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
4942bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(rc, 0);
4952bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
496c8ab874dSKozlowski Mateusz 
497c8ab874dSKozlowski Mateusz 	/* restore the sb: */
4982bb1753bSLukasz Lasek 	sb->v3.md_layout_head.type = md_type_head;
499c8ab874dSKozlowski Mateusz 
500c8ab874dSKozlowski Mateusz 	/* load succeeded, no prev version found: */
5012bb1753bSLukasz Lasek 	reg_head = &g_dev.layout.region[md_type_head];
502fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
503c8ab874dSKozlowski Mateusz 	CU_ASSERT_EQUAL(rc, 0);
5042bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg_head->current.version,
5052bb1753bSLukasz Lasek 			ftl_layout_upgrade_region_get_latest_version(md_type_head));
5062bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
507c8ab874dSKozlowski Mateusz 
508c8ab874dSKozlowski Mateusz 	/* load succeeded, prev (upgrade, i.e. no current) version discovery: */
5092bb1753bSLukasz Lasek 	reg = &g_dev.layout.region[FTL_LAYOUT_REGION_TYPE_BAND_MD];
5102bb1753bSLukasz Lasek 	sb_reg = test_sb_v3_find_region_latest(FTL_LAYOUT_REGION_TYPE_BAND_MD);
5112bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(sb_reg, NULL);
5122bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg->type, sb_reg->type);
5132bb1753bSLukasz Lasek 	df_next_reg = sb_reg->df_next;
514c8ab874dSKozlowski Mateusz 
5152bb1753bSLukasz Lasek 	sb_reg->version--;
516fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
5172bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(rc, 0);
5182bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg->current.version, sb_reg->version);
5192bb1753bSLukasz Lasek 	sb_reg->version++;
5202bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
5212bb1753bSLukasz Lasek 
5222bb1753bSLukasz Lasek 	/* load succeeded, newer version found: */
5232bb1753bSLukasz Lasek 	sb_reg->df_next = FTL_SUPERBLOCK_SIZE - sizeof(*sb_reg_next);
5242bb1753bSLukasz Lasek 	sb_reg_next = ftl_df_get_obj_ptr(sb, sb_reg->df_next);
5252bb1753bSLukasz Lasek 	rc = test_superblock_v3_md_layout_add(&g_dev, sb_reg_next, sb_reg->type, sb_reg->version + 1,
5262bb1753bSLukasz Lasek 					      sb_reg->blk_offs, sb_reg->blk_sz);
5272bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(rc, 0);
5282bb1753bSLukasz Lasek 	sb_reg_next->df_next = df_next_reg;
5292bb1753bSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
5302bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(rc, 0);
5312bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg->current.version, sb_reg->version);
5322bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
533c8ab874dSKozlowski Mateusz 
534c8ab874dSKozlowski Mateusz 	/* load succeeded, prev version discovery: */
5352bb1753bSLukasz Lasek 	sb_reg_next->version = sb_reg->version - 1;
536fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
537c8ab874dSKozlowski Mateusz 	CU_ASSERT_EQUAL(rc, 0);
5382bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg->current.version, sb_reg_next->version);
5392bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
540c8ab874dSKozlowski Mateusz 
5412bb1753bSLukasz Lasek 	/* looping regions found: */
5422bb1753bSLukasz Lasek 	sb_reg_next->df_next = FTL_SUPERBLOCK_SIZE - 2 * sizeof(*sb_reg_next);
5432bb1753bSLukasz Lasek 	sb_reg_next2 = ftl_df_get_obj_ptr(sb, sb_reg_next->df_next);
5442bb1753bSLukasz Lasek 	rc = test_superblock_v3_md_layout_add(&g_dev, sb_reg_next2, sb_reg_next->type,
5452bb1753bSLukasz Lasek 					      sb_reg_next->version + 2,
5462bb1753bSLukasz Lasek 					      sb_reg_next->blk_offs, sb_reg_next->blk_sz);
547c8ab874dSKozlowski Mateusz 	CU_ASSERT_EQUAL(rc, 0);
5482bb1753bSLukasz Lasek 	sb_reg_next2->df_next = FTL_SUPERBLOCK_SIZE - 2 * sizeof(*sb_reg_next);
549fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
5502bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(rc, -ELOOP);
5512bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
552c8ab874dSKozlowski Mateusz 
5532bb1753bSLukasz Lasek 	/* multiple (same ver) regions found: */
5542bb1753bSLukasz Lasek 	sb_reg_next2->version = sb_reg_next->version;
5552bb1753bSLukasz Lasek 	sb_reg_next2->df_next = df_next_reg;
556fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
5572bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(rc, -EAGAIN);
5582bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
559c8ab874dSKozlowski Mateusz 
560d9f2ae9dSMateusz Kozlowski 	/* multiple (different ver) prev regions found: */
561d9f2ae9dSMateusz Kozlowski 	sb_reg_next2->version = sb_reg_next->version - 1;
562d9f2ae9dSMateusz Kozlowski 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
563d9f2ae9dSMateusz Kozlowski 	CU_ASSERT_EQUAL(rc, 0);
564d9f2ae9dSMateusz Kozlowski 	CU_ASSERT_EQUAL(reg->current.version, sb_reg_next2->version);
565d9f2ae9dSMateusz Kozlowski 	test_sb_v3_region_reinit();
566d9f2ae9dSMateusz Kozlowski 
567c8ab874dSKozlowski Mateusz 	/* multiple current regions found: */
5682bb1753bSLukasz Lasek 	sb_reg_next->version = sb_reg->version;
5692bb1753bSLukasz Lasek 	sb_reg_next->df_next = df_next_reg;
570fa1fc76cSLukasz Lasek 	rc = ftl_superblock_v3_md_layout_load_all(&g_dev);
5712bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(rc, -EAGAIN);
572c8ab874dSKozlowski Mateusz 
573c8ab874dSKozlowski Mateusz 	/* restore the sb: */
5742bb1753bSLukasz Lasek 	sb->v3.md_layout_head.df_next = df_next_head;
5752bb1753bSLukasz Lasek 	test_sb_v3_region_reinit();
5762bb1753bSLukasz Lasek }
5772bb1753bSLukasz Lasek 
5782bb1753bSLukasz Lasek static void
5792bb1753bSLukasz Lasek test_sb_v5_md_layout(void)
5802bb1753bSLukasz Lasek {
5812bb1753bSLukasz Lasek 	struct layout_tracker_blob_entry *tbe;
5822bb1753bSLukasz Lasek 	struct layout_blob_entry *lbe;
5832bb1753bSLukasz Lasek 	struct ftl_layout_region *reg;
5842bb1753bSLukasz Lasek 	union ftl_superblock_ver *sb = (void *)g_sb_buf;
5852bb1753bSLukasz Lasek 	int rc;
5862bb1753bSLukasz Lasek 	const struct ftl_layout_tracker_bdev_region_props *reg_props;
5872bb1753bSLukasz Lasek 	void *blob_nvc, *blob_base, *blob_regs;
5882bb1753bSLukasz Lasek 
5892bb1753bSLukasz Lasek 	test_setup_sb_v5(false);
5902bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(ftl_superblock_is_blob_area_empty(&sb->current), true);
5912bb1753bSLukasz Lasek 
5922bb1753bSLukasz Lasek 	/* load failed: empty md list: */
5932bb1753bSLukasz Lasek 	rc = ftl_superblock_v5_load_blob_area(&g_dev);
5942bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(rc, 0);
5952bb1753bSLukasz Lasek 
5962bb1753bSLukasz Lasek 	/* create md layout: */
5972bb1753bSLukasz Lasek 	for (enum ftl_layout_region_type regno = 0; regno < FTL_LAYOUT_REGION_TYPE_MAX; regno++) {
5982bb1753bSLukasz Lasek 		struct ftl_layout_region *reg = &g_dev.layout.region[regno];
5992bb1753bSLukasz Lasek 		CU_ASSERT_EQUAL(regno, reg->type);
6002bb1753bSLukasz Lasek 		struct ftl_layout_tracker_bdev *tracker = sb_v3_md_region_is_nvc(regno) ? g_dev.nvc_layout_tracker :
6012bb1753bSLukasz Lasek 				g_dev.base_layout_tracker;
6022bb1753bSLukasz Lasek 		const struct ftl_layout_tracker_bdev_region_props *reg_props = ftl_layout_tracker_bdev_add_region(
6032bb1753bSLukasz Lasek 					tracker, reg->type, reg->current.version, reg->current.blocks, TEST_REG_BLKS);
6042bb1753bSLukasz Lasek 
6052bb1753bSLukasz Lasek 		CU_ASSERT_EQUAL(reg->type, reg_props->type);
6062bb1753bSLukasz Lasek 		CU_ASSERT_EQUAL(reg->current.version, reg_props->ver);
6072bb1753bSLukasz Lasek 		CU_ASSERT_EQUAL(reg->current.offset, reg_props->blk_offs);
6082bb1753bSLukasz Lasek 		CU_ASSERT_EQUAL(reg->current.blocks, reg_props->blk_sz);
6092bb1753bSLukasz Lasek 	}
6102bb1753bSLukasz Lasek 	ftl_superblock_v5_store_blob_area(&g_dev);
6112bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(ftl_superblock_is_blob_area_empty(&sb->current), false);
6122bb1753bSLukasz Lasek 
6132bb1753bSLukasz Lasek 	blob_nvc = ftl_df_get_obj_ptr(sb->v5.blob_area, sb->v5.md_layout_nvc.df_id);
6142bb1753bSLukasz Lasek 	blob_base = ftl_df_get_obj_ptr(sb->v5.blob_area, sb->v5.md_layout_base.df_id);
6152bb1753bSLukasz Lasek 	blob_regs = ftl_df_get_obj_ptr(sb->v5.blob_area, sb->v5.layout_params.df_id);
6162bb1753bSLukasz Lasek 
6172bb1753bSLukasz Lasek 	/* unsupported nvc md region type: */
6182bb1753bSLukasz Lasek 	tbe = blob_nvc;
6192bb1753bSLukasz Lasek 	tbe->type += FTL_LAYOUT_REGION_TYPE_MAX;
6202bb1753bSLukasz Lasek 	sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_SB;
6212bb1753bSLukasz Lasek 	rc = ftl_superblock_v5_load_blob_area(&g_dev);
6222bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(rc, 0);
6232bb1753bSLukasz Lasek 	tbe->type -= FTL_LAYOUT_REGION_TYPE_MAX;
6242bb1753bSLukasz Lasek 
6252bb1753bSLukasz Lasek 	/* unsupported base md region type: */
6262bb1753bSLukasz Lasek 	tbe = blob_base;
6272bb1753bSLukasz Lasek 	tbe->type += FTL_LAYOUT_REGION_TYPE_MAX;
6282bb1753bSLukasz Lasek 	sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_SB;
6292bb1753bSLukasz Lasek 	rc = ftl_superblock_v5_load_blob_area(&g_dev);
6302bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(rc, 0);
6312bb1753bSLukasz Lasek 	tbe->type -= FTL_LAYOUT_REGION_TYPE_MAX;
6322bb1753bSLukasz Lasek 
6332bb1753bSLukasz Lasek 	/* load succeeded, no prev version found: */
6342bb1753bSLukasz Lasek 	reg = &g_dev.layout.region[FTL_LAYOUT_REGION_TYPE_BAND_MD];
6352bb1753bSLukasz Lasek 	rc = ftl_superblock_v5_load_blob_area(&g_dev);
6362bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(rc, 0);
6372bb1753bSLukasz Lasek 	reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_latest_region, NULL);
6382bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(reg_props, NULL);
6392bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg_props->ver, reg->current.version);
6402bb1753bSLukasz Lasek 	reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_oldest_region, NULL);
6412bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(reg_props, NULL);
6422bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg_props->ver, reg->current.version);
6432bb1753bSLukasz Lasek 
6442bb1753bSLukasz Lasek 	/* move the sb-stored blobs around: */
6452bb1753bSLukasz Lasek 	CU_ASSERT(blob_nvc < blob_base);
6462bb1753bSLukasz Lasek 	CU_ASSERT(blob_base < blob_regs);
6472bb1753bSLukasz Lasek 	blob_regs = memmove(blob_regs + 8192, blob_regs, sb->v5.layout_params.blob_sz);
6482bb1753bSLukasz Lasek 	sb->v5.layout_params.df_id += 8192;
6492bb1753bSLukasz Lasek 	blob_base = memmove(blob_base + 4096, blob_base, sb->v5.md_layout_base.blob_sz);
6502bb1753bSLukasz Lasek 	sb->v5.md_layout_base.df_id += 4096;
6512bb1753bSLukasz Lasek 
6522bb1753bSLukasz Lasek 	/* load succeeded again, no prev version found: */
6532bb1753bSLukasz Lasek 	rc = ftl_superblock_v5_load_blob_area(&g_dev);
6542bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(rc, 0);
6552bb1753bSLukasz Lasek 	reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_latest_region, NULL);
6562bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(reg_props, NULL);
6572bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg_props->ver, reg->current.version);
6582bb1753bSLukasz Lasek 	reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_oldest_region, NULL);
6592bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(reg_props, NULL);
6602bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg_props->ver, reg->current.version);
6612bb1753bSLukasz Lasek 
6622bb1753bSLukasz Lasek 	/* load failed, regs overlap: */
6632bb1753bSLukasz Lasek 	tbe = blob_nvc;
6642bb1753bSLukasz Lasek 	tbe++;
6652bb1753bSLukasz Lasek 	tbe->blk_offs -= tbe->blk_sz;
6662bb1753bSLukasz Lasek 	rc = ftl_superblock_v5_load_blob_area(&g_dev);
6672bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(rc, 0);
6682bb1753bSLukasz Lasek 	tbe->blk_offs += tbe->blk_sz;
6692bb1753bSLukasz Lasek 
6702bb1753bSLukasz Lasek 	/* load failed, the same region version found twice: */
6712bb1753bSLukasz Lasek 	tbe = (blob_nvc + sb->v5.md_layout_nvc.blob_sz);
6722bb1753bSLukasz Lasek 	sb->v5.md_layout_nvc.blob_sz += sizeof(*tbe);
6732bb1753bSLukasz Lasek 	tbe->type = reg->type;
6742bb1753bSLukasz Lasek 	tbe->ver = reg->current.version;
6752bb1753bSLukasz Lasek 	tbe->blk_offs = reg->current.offset + FTL_LAYOUT_REGION_TYPE_MAX * reg->current.blocks;
6762bb1753bSLukasz Lasek 	tbe->blk_sz = reg->current.blocks;
6772bb1753bSLukasz Lasek 	rc = ftl_superblock_v5_load_blob_area(&g_dev);
6782bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(rc, 0);
6792bb1753bSLukasz Lasek 
6802bb1753bSLukasz Lasek 	/* load succeeded, prev (upgrade, i.e. no current) version discovery: */
6812bb1753bSLukasz Lasek 	tbe->type = reg->type;
6822bb1753bSLukasz Lasek 	tbe->ver = reg->current.version - 1;
6832bb1753bSLukasz Lasek 	tbe->blk_offs = reg->current.offset + FTL_LAYOUT_REGION_TYPE_MAX * reg->current.blocks;
6842bb1753bSLukasz Lasek 	tbe->blk_sz = reg->current.blocks;
6852bb1753bSLukasz Lasek 	rc = ftl_superblock_v5_load_blob_area(&g_dev);
6862bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(rc, 0);
6872bb1753bSLukasz Lasek 	reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_latest_region, NULL);
6882bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(reg_props, NULL);
6892bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg_props->ver, reg->current.version);
6902bb1753bSLukasz Lasek 	reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_oldest_region, NULL);
6912bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(reg_props, NULL);
6922bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg_props->ver, reg->current.version - 1);
6932bb1753bSLukasz Lasek 
6942bb1753bSLukasz Lasek 	/* load succeeded, newer version found: */
6952bb1753bSLukasz Lasek 	tbe->ver = reg->current.version + 1;
6962bb1753bSLukasz Lasek 	rc = ftl_superblock_v5_load_blob_area(&g_dev);
6972bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(rc, 0);
6982bb1753bSLukasz Lasek 	reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_latest_region, NULL);
6992bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(reg_props, NULL);
7002bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg_props->ver, reg->current.version + 1);
7012bb1753bSLukasz Lasek 	reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_oldest_region, NULL);
7022bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(reg_props, NULL);
7032bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg_props->ver, reg->current.version);
7042bb1753bSLukasz Lasek 
7052bb1753bSLukasz Lasek 	/* load failed, invalid type in layout properties: */
7062bb1753bSLukasz Lasek 	lbe = blob_regs;
7072bb1753bSLukasz Lasek 	lbe += FTL_LAYOUT_REGION_TYPE_BAND_MD;
7082bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(lbe->type, FTL_LAYOUT_REGION_TYPE_BAND_MD);
7092bb1753bSLukasz Lasek 	lbe->type = FTL_LAYOUT_REGION_TYPE_MAX;
7102bb1753bSLukasz Lasek 	rc = ftl_superblock_v5_load_blob_area(&g_dev);
7112bb1753bSLukasz Lasek 	CU_ASSERT_NOT_EQUAL(rc, 0);
7122bb1753bSLukasz Lasek 	lbe->type = FTL_LAYOUT_REGION_TYPE_BAND_MD;
7132bb1753bSLukasz Lasek 
7142bb1753bSLukasz Lasek 	/* load succeeded, restore layout properties: */
7152bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg->num_entries, 0);
7162bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg->entry_size, 0);
7172bb1753bSLukasz Lasek 	lbe->num_entries = 0x1984;
7182bb1753bSLukasz Lasek 	lbe->entry_size = 0x1405;
7192bb1753bSLukasz Lasek 	rc = ftl_superblock_v5_load_blob_area(&g_dev);
7202bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(rc, 0);
7212bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg->num_entries, 0x1984);
7222bb1753bSLukasz Lasek 	CU_ASSERT_EQUAL(reg->entry_size, 0x1405);
7232bb1753bSLukasz Lasek 
7242bb1753bSLukasz Lasek 	/* restore the sb: */
7252bb1753bSLukasz Lasek 	sb->v5.md_layout_nvc.blob_sz -= sizeof(*tbe);
726c8ab874dSKozlowski Mateusz }
727c8ab874dSKozlowski Mateusz 
728c8ab874dSKozlowski Mateusz int
729c8ab874dSKozlowski Mateusz main(int argc, char **argv)
730c8ab874dSKozlowski Mateusz {
731c8ab874dSKozlowski Mateusz 	CU_pSuite suite = NULL;
7322bb1753bSLukasz Lasek 	unsigned int num_failures = 0;
733c8ab874dSKozlowski Mateusz 
7342bb1753bSLukasz Lasek 	CU_set_error_action(CUEA_ABORT);
735c8ab874dSKozlowski Mateusz 	CU_initialize_registry();
736c8ab874dSKozlowski Mateusz 
7372bb1753bSLukasz Lasek 	suite = CU_add_suite("ftl_sb", test_setup, test_teardown);
738c8ab874dSKozlowski Mateusz 
739c8ab874dSKozlowski Mateusz 	CU_ADD_TEST(suite, test_sb_crc_v2);
740c8ab874dSKozlowski Mateusz 	CU_ADD_TEST(suite, test_sb_crc_v3);
741c8ab874dSKozlowski Mateusz 	CU_ADD_TEST(suite, test_sb_v3_md_layout);
7422bb1753bSLukasz Lasek 	CU_ADD_TEST(suite, test_sb_v5_md_layout);
743c8ab874dSKozlowski Mateusz 
7442bb1753bSLukasz Lasek 	CU_basic_set_mode(CU_BRM_VERBOSE);
7452bb1753bSLukasz Lasek 	CU_basic_run_tests();
7462bb1753bSLukasz Lasek 	num_failures = CU_get_number_of_failures();
747c8ab874dSKozlowski Mateusz 	CU_cleanup_registry();
748c8ab874dSKozlowski Mateusz 
749c8ab874dSKozlowski Mateusz 	return num_failures;
750c8ab874dSKozlowski Mateusz }
751