xref: /spdk/test/unit/lib/ftl/ftl_sb/ftl_sb_ut.c (revision 307b8c112ffd90a26d53dd15fad67bd9038ef526)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include <sys/queue.h>
7 
8 #include "spdk/stdinc.h"
9 
10 #include "spdk_cunit.h"
11 #include "common/lib/test_env.c"
12 
13 #include "ftl/ftl_sb.c"
14 #include "ftl/upgrade/ftl_sb_upgrade.c"
15 #include "ftl/upgrade/ftl_layout_upgrade.c"
16 #include "ftl/mngt/ftl_mngt_md.c"
17 
18 DEFINE_STUB_V(ftl_mngt_fail_step, (struct ftl_mngt_process *mngt));
19 DEFINE_STUB_V(ftl_mngt_next_step, (struct ftl_mngt_process *mngt));
20 DEFINE_STUB_V(ftl_md_persist, (struct ftl_md *md));
21 DEFINE_STUB(ftl_nv_cache_load_state, int, (struct ftl_nv_cache *nv_cache), 0);
22 DEFINE_STUB_V(ftl_valid_map_load_state, (struct spdk_ftl_dev *dev));
23 DEFINE_STUB_V(ftl_bands_load_state, (struct spdk_ftl_dev *dev));
24 DEFINE_STUB(ftl_md_get_region, const struct ftl_layout_region *, (struct ftl_md *md), 0);
25 DEFINE_STUB_V(ftl_md_restore, (struct ftl_md *md));
26 DEFINE_STUB(ftl_nv_cache_save_state, int, (struct ftl_nv_cache *nv_cache), 0);
27 DEFINE_STUB(ftl_mngt_get_step_ctx, void *, (struct ftl_mngt_process *mngt), 0);
28 DEFINE_STUB_V(ftl_mngt_persist_bands_p2l, (struct ftl_mngt_process *mngt));
29 DEFINE_STUB_V(ftl_band_init_gc_iter, (struct spdk_ftl_dev *dev));
30 DEFINE_STUB(ftl_validate_regions, int, (struct spdk_ftl_dev *dev, struct ftl_layout *layout), 0);
31 DEFINE_STUB_V(ftl_layout_dump, (struct spdk_ftl_dev *dev));
32 DEFINE_STUB(ftl_layout_setup, int, (struct spdk_ftl_dev *dev), 0);
33 DEFINE_STUB(ftl_md_create_region_flags, int, (struct spdk_ftl_dev *dev, int region_type), 0);
34 DEFINE_STUB(ftl_md_create, struct ftl_md *, (struct spdk_ftl_dev *dev, uint64_t blocks,
35 		uint64_t vss_blksz, const char *name, int flags, const struct ftl_layout_region *region), NULL);
36 DEFINE_STUB(ftl_md_destroy_region_flags, int, (struct spdk_ftl_dev *dev, int region_type), 0);
37 DEFINE_STUB(ftl_md_destroy_shm_flags, int, (struct spdk_ftl_dev *dev), 0);
38 DEFINE_STUB_V(ftl_md_destroy, (struct ftl_md *md, int flags));
39 DEFINE_STUB_V(ftl_mngt_call_process, (struct ftl_mngt_process *mngt,
40 				      const struct ftl_mngt_process_desc *process));
41 DEFINE_STUB(ftl_md_get_buffer, void *, (struct ftl_md *md), NULL);
42 DEFINE_STUB(ftl_layout_setup_superblock, int, (struct spdk_ftl_dev *dev), 0);
43 
44 struct spdk_ftl_dev g_dev;
45 struct ftl_superblock_shm g_sb_shm = {0};
46 static uint8_t g_sb_buf[FTL_SUPERBLOCK_SIZE] = {0};
47 
48 struct ftl_region_upgrade_desc p2l_upgrade_desc[0];
49 struct ftl_region_upgrade_desc nvc_upgrade_desc[0];
50 struct ftl_region_upgrade_desc band_upgrade_desc[0];
51 
52 #define TEST_OP 0x1984
53 #define TEST_REG_BLKS 0x10000
54 #define TEST_NVC_BLKS 0x1000000;
55 #define TEST_BASE_BLKS 0x1000000000;
56 
57 static int
58 test_setup(void)
59 {
60 	/* setup a dummy dev: */
61 	g_dev.sb = (void *)g_sb_buf;
62 	g_dev.sb_shm = &g_sb_shm;
63 	g_dev.conf.overprovisioning = TEST_OP;
64 	for (uint64_t n = 0; n < sizeof(g_dev.conf.uuid); n++) {
65 		g_dev.conf.uuid.u.raw[n] = n;
66 	}
67 
68 	g_dev.layout.nvc.total_blocks = TEST_NVC_BLKS;
69 	g_dev.layout.base.total_blocks = TEST_BASE_BLKS;
70 
71 	for (int regno = 0; regno < FTL_LAYOUT_REGION_TYPE_MAX; regno++) {
72 		struct ftl_layout_region *reg = &g_dev.layout.region[regno];
73 		reg->current.blocks = TEST_REG_BLKS;
74 		reg->current.offset = regno * TEST_REG_BLKS;
75 		reg->current.version = FTL_SB_VERSION_CURRENT;
76 		reg->prev.version = FTL_SB_VERSION_CURRENT;
77 		reg->type = regno;
78 		reg->name = "region_test";
79 		reg->bdev_desc = 0;
80 		reg->ioch = 0;
81 	}
82 	return 0;
83 }
84 
85 static void
86 test_setup_sb_ver(uint64_t ver, uint64_t clean)
87 {
88 	union ftl_superblock_ver *sb = (void *)g_sb_buf;
89 
90 	memset(&g_sb_buf, 0, sizeof(g_sb_buf));
91 	ftl_mngt_init_default_sb(&g_dev, NULL);
92 	if (ver <= FTL_SB_VERSION_3) {
93 		sb->header.magic = FTL_SUPERBLOCK_MAGIC_V2;
94 	}
95 	sb->header.version = ver;
96 	sb->v2.clean = clean;
97 	sb->v3.md_layout_head.type = 0;
98 	sb->v3.md_layout_head.df_next = 0;
99 	sb->header.crc = get_sb_crc(&sb->v3);
100 }
101 
102 static void
103 test_setup_sb_v2(uint64_t clean)
104 {
105 	test_setup_sb_ver(FTL_SB_VERSION_2, clean);
106 }
107 
108 static void
109 test_setup_sb_v3(uint64_t clean)
110 {
111 	struct ftl_superblock *sb = (void *)g_sb_buf;
112 
113 	memset(&g_sb_buf, 0, sizeof(g_sb_buf));
114 	ftl_mngt_init_default_sb(&g_dev, NULL);
115 	sb->clean = clean;
116 	sb->header.crc = get_sb_crc(sb);
117 }
118 
119 static void
120 test_sb_crc_v2(void)
121 {
122 	union ftl_superblock_ver *sb = (void *)g_sb_buf;
123 	uint64_t crc;
124 
125 	/* v2-specific crc: it's not really working */
126 	test_setup_sb_v2(true);
127 	crc = sb->header.crc;
128 
129 	sb->header.crc++;
130 	sb->header.crc = get_sb_crc(&sb->v3);
131 	CU_ASSERT_EQUAL(crc, sb->header.crc);
132 
133 	g_sb_buf[sizeof(struct ftl_superblock_v2)]++;
134 	sb->header.crc = get_sb_crc(&sb->v3);
135 	CU_ASSERT_EQUAL(crc, sb->header.crc);
136 
137 	g_sb_buf[sizeof(g_sb_buf) - 1]++;
138 	sb->header.crc = get_sb_crc(&sb->v3);
139 	CU_ASSERT_EQUAL(crc, sb->header.crc);
140 
141 	sb->header.version += 0x19840514;
142 	sb->v2.seq_id++;
143 	CU_ASSERT_EQUAL(crc, sb->header.crc);
144 }
145 
146 static void
147 test_sb_crc_v3(void)
148 {
149 	union ftl_superblock_ver *sb = (void *)g_sb_buf;
150 	uint64_t crc;
151 
152 	/* v3 crc: covers the entire buf */
153 	test_setup_sb_v3(true);
154 	crc = sb->header.crc;
155 
156 	sb->header.crc++;
157 	sb->header.crc = get_sb_crc(&sb->v3);
158 	CU_ASSERT_EQUAL(crc, sb->header.crc);
159 	crc = sb->header.crc;
160 
161 	g_sb_buf[sizeof(struct ftl_superblock_v2)]++;
162 	sb->header.crc = get_sb_crc(&sb->v3);
163 	CU_ASSERT_NOT_EQUAL(crc, sb->header.crc);
164 	crc = sb->header.crc;
165 
166 	g_sb_buf[sizeof(g_sb_buf) - 1]++;
167 	sb->header.crc = get_sb_crc(&sb->v3);
168 	CU_ASSERT_NOT_EQUAL(crc, sb->header.crc);
169 	crc = sb->header.crc;
170 
171 	sb->header.version += 500;
172 	sb->v2.seq_id++;
173 	CU_ASSERT_EQUAL(crc, sb->header.crc);
174 	crc = sb->header.crc;
175 }
176 
177 static void
178 test_sb_v3_md_layout(void)
179 {
180 	struct ftl_superblock_md_region *sb_reg, *sb_reg2;
181 	struct ftl_layout_region *reg;
182 	union ftl_superblock_ver *sb = (void *)g_sb_buf;
183 	ftl_df_obj_id df_next;
184 	uint32_t md_type;
185 	int rc;
186 
187 	test_setup_sb_v3(false);
188 	CU_ASSERT_EQUAL(ftl_superblock_md_layout_is_empty(&sb->v3), true);
189 
190 	/* load failed: empty md list: */
191 	rc = ftl_superblock_md_layout_load_all(&g_dev);
192 	CU_ASSERT_NOT_EQUAL(rc, 0);
193 
194 	/* create md layout: */
195 	ftl_superblock_md_layout_build(&g_dev);
196 	CU_ASSERT_EQUAL(ftl_superblock_md_layout_is_empty(&sb->v3), false);
197 
198 	/* buf overflow, sb_reg = 1 byte overflow: */
199 	df_next = sb->v3.md_layout_head.df_next;
200 	sb->v3.md_layout_head.df_next = FTL_SUPERBLOCK_SIZE - sizeof(sb->v3.md_layout_head) + 1;
201 	rc = ftl_superblock_md_layout_load_all(&g_dev);
202 	CU_ASSERT_EQUAL(rc, -EOVERFLOW);
203 
204 	/* buf underflow, sb_reg = -1: */
205 	sb->v3.md_layout_head.df_next = UINTPTR_MAX - (uintptr_t)sb;
206 	rc = ftl_superblock_md_layout_load_all(&g_dev);
207 	CU_ASSERT_EQUAL(rc, -EOVERFLOW);
208 
209 	/* buf underflow, sb_reg = 2 bytes underflow */
210 	sb->v3.md_layout_head.df_next = UINTPTR_MAX - 1;
211 	rc = ftl_superblock_md_layout_load_all(&g_dev);
212 	CU_ASSERT_EQUAL(rc, -EOVERFLOW);
213 
214 	/* looping md layout list: */
215 	sb->v3.md_layout_head.df_next = ftl_df_get_obj_id(sb, &sb->v3.md_layout_head);
216 	rc = ftl_superblock_md_layout_load_all(&g_dev);
217 	CU_ASSERT_NOT_EQUAL(rc, 0);
218 
219 	sb->v3.md_layout_head.df_next = df_next;
220 
221 	/* unsupported/fixed md region: */
222 	md_type = sb->v3.md_layout_head.type;
223 	sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_SB;
224 	rc = ftl_superblock_md_layout_load_all(&g_dev);
225 	CU_ASSERT_NOT_EQUAL(rc, 0);
226 
227 	/* unsupported/invalid md region: */
228 	sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_MAX;
229 	rc = ftl_superblock_md_layout_load_all(&g_dev);
230 	CU_ASSERT_NOT_EQUAL(rc, 0);
231 
232 	/* restore the sb: */
233 	sb->v3.md_layout_head.type = md_type;
234 
235 	/* load succeeded, no prev version found: */
236 	reg = &g_dev.layout.region[md_type];
237 	rc = ftl_superblock_md_layout_load_all(&g_dev);
238 	CU_ASSERT_EQUAL(rc, 0);
239 	CU_ASSERT_EQUAL(reg->current.version, reg->prev.version);
240 	CU_ASSERT_NOT_EQUAL(reg->current.sb_md_reg, NULL);
241 	CU_ASSERT_EQUAL(reg->prev.sb_md_reg, NULL);
242 
243 	/* load succeeded, prev (upgrade, i.e. no current) version discovery: */
244 	reg = &g_dev.layout.region[md_type];
245 	sb->v3.md_layout_head.version--;
246 	rc = ftl_superblock_md_layout_load_all(&g_dev);
247 	sb->v3.md_layout_head.version++;
248 	CU_ASSERT_EQUAL(rc, 0);
249 	CU_ASSERT_NOT_EQUAL(reg->current.version, reg->prev.version);
250 	CU_ASSERT_EQUAL(reg->current.sb_md_reg, NULL);
251 	CU_ASSERT_NOT_EQUAL(reg->prev.sb_md_reg, NULL);
252 
253 	/* load failed, unknown (newer) version found: */
254 	sb->v3.md_layout_head.df_next = FTL_SUPERBLOCK_SIZE - sizeof(sb->v3.md_layout_head);
255 	sb_reg = ftl_df_get_obj_ptr(sb, sb->v3.md_layout_head.df_next);
256 	rc = superblock_md_layout_add(&g_dev, sb_reg, md_type, FTL_SB_VERSION_CURRENT + 1,
257 				      sb->v3.md_layout_head.blk_offs, sb->v3.md_layout_head.blk_sz);
258 	CU_ASSERT_EQUAL(rc, 0);
259 	sb_reg->df_next = df_next;
260 	rc = ftl_superblock_md_layout_load_all(&g_dev);
261 	CU_ASSERT_NOT_EQUAL(rc, 0);
262 
263 	/* load succeeded, prev version discovery: */
264 	sb_reg->version = FTL_SB_VERSION_2;
265 	rc = ftl_superblock_md_layout_load_all(&g_dev);
266 	CU_ASSERT_EQUAL(rc, 0);
267 	CU_ASSERT_NOT_EQUAL(reg->current.version, reg->prev.version);
268 	CU_ASSERT_EQUAL(reg->current.version, FTL_SB_VERSION_CURRENT);
269 	CU_ASSERT_EQUAL(reg->prev.version, FTL_SB_VERSION_2);
270 
271 	/* looping/multiple (same ver) prev regions found: */
272 	sb_reg->df_next = FTL_SUPERBLOCK_SIZE - 2 * sizeof(sb->v3.md_layout_head);
273 	sb_reg2 = ftl_df_get_obj_ptr(sb, sb_reg->df_next);
274 	rc = superblock_md_layout_add(&g_dev, sb_reg2, md_type, FTL_SB_VERSION_2,
275 				      sb->v3.md_layout_head.blk_offs, sb->v3.md_layout_head.blk_sz);
276 	CU_ASSERT_EQUAL(rc, 0);
277 	sb_reg2->df_next = df_next;
278 	rc = ftl_superblock_md_layout_load_all(&g_dev);
279 	CU_ASSERT_NOT_EQUAL(rc, 0);
280 
281 	/* multiple (different ver) prev regions found: */
282 	sb_reg->df_next = FTL_SUPERBLOCK_SIZE - 2 * sizeof(sb->v3.md_layout_head);
283 	sb_reg2 = ftl_df_get_obj_ptr(sb, sb_reg->df_next);
284 	rc = superblock_md_layout_add(&g_dev, sb_reg2, md_type, FTL_SB_VERSION_1,
285 				      sb->v3.md_layout_head.blk_offs, sb->v3.md_layout_head.blk_sz);
286 	CU_ASSERT_EQUAL(rc, 0);
287 	sb_reg2->df_next = df_next;
288 	rc = ftl_superblock_md_layout_load_all(&g_dev);
289 	CU_ASSERT_EQUAL(rc, 0);
290 
291 	/* multiple current regions found: */
292 	sb->v3.md_layout_head.df_next = FTL_SUPERBLOCK_SIZE - sizeof(sb->v3.md_layout_head);
293 	sb_reg2->version = FTL_SB_VERSION_CURRENT;
294 	rc = ftl_superblock_md_layout_load_all(&g_dev);
295 	CU_ASSERT_NOT_EQUAL(rc, 0);
296 
297 	/* restore the sb: */
298 	sb->v3.md_layout_head.df_next = df_next;
299 }
300 
301 int
302 main(int argc, char **argv)
303 {
304 	CU_pSuite suite = NULL;
305 	unsigned int num_failures;
306 
307 	CU_set_error_action(CUEA_ABORT);
308 	CU_initialize_registry();
309 
310 	suite = CU_add_suite("ftl_sb", test_setup, NULL);
311 
312 	CU_ADD_TEST(suite, test_sb_crc_v2);
313 	CU_ADD_TEST(suite, test_sb_crc_v3);
314 	CU_ADD_TEST(suite, test_sb_v3_md_layout);
315 
316 	CU_basic_set_mode(CU_BRM_VERBOSE);
317 	CU_basic_run_tests();
318 	num_failures = CU_get_number_of_failures();
319 	CU_cleanup_registry();
320 
321 	return num_failures;
322 }
323