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