xref: /spdk/test/unit/lib/ftl/ftl_sb/ftl_sb_ut.c (revision 12fbe739a31b09aff0d05f354d4f3bbef99afc55)
1  /*   SPDX-License-Identifier: BSD-3-Clause
2   *   Copyright (C) 2022 Intel Corporation.
3   *   All rights reserved.
4   */
5  
6  #include <sys/queue.h>
7  
8  #include "spdk/stdinc.h"
9  
10  #include "spdk_internal/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_initialize_registry();
308  
309  	suite = CU_add_suite("ftl_sb", test_setup, NULL);
310  
311  	CU_ADD_TEST(suite, test_sb_crc_v2);
312  	CU_ADD_TEST(suite, test_sb_crc_v3);
313  	CU_ADD_TEST(suite, test_sb_v3_md_layout);
314  
315  	num_failures = spdk_ut_run_tests(argc, argv, NULL);
316  	CU_cleanup_registry();
317  
318  	return num_failures;
319  }
320