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 #include "spdk_internal/cunit.h" 10 #include "common/lib/test_env.c" 11 12 #include "ftl/utils/ftl_layout_tracker_bdev.c" 13 #include "ftl/upgrade/ftl_sb_v3.c" 14 #include "ftl/upgrade/ftl_sb_v5.c" 15 #include "ftl/ftl_sb.c" 16 #include "ftl/ftl_layout.c" 17 #include "ftl/upgrade/ftl_sb_upgrade.c" 18 19 static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = { 20 [FTL_LAYOUT_REGION_TYPE_SB] = { 21 .latest_ver = FTL_SB_VERSION_CURRENT, 22 .count = FTL_SB_VERSION_CURRENT, 23 }, 24 [FTL_LAYOUT_REGION_TYPE_SB_BASE] = { 25 .latest_ver = FTL_SB_VERSION_CURRENT, 26 .count = FTL_SB_VERSION_CURRENT, 27 }, 28 [FTL_LAYOUT_REGION_TYPE_L2P] = {}, 29 [FTL_LAYOUT_REGION_TYPE_BAND_MD] = { 30 .latest_ver = FTL_BAND_VERSION_CURRENT, 31 .count = FTL_BAND_VERSION_CURRENT, 32 }, 33 [FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = { 34 .latest_ver = FTL_BAND_VERSION_CURRENT, 35 .count = FTL_BAND_VERSION_CURRENT, 36 }, 37 [FTL_LAYOUT_REGION_TYPE_VALID_MAP] = {}, 38 [FTL_LAYOUT_REGION_TYPE_NVC_MD] = { 39 .latest_ver = FTL_NVC_VERSION_CURRENT, 40 .count = FTL_NVC_VERSION_CURRENT, 41 }, 42 [FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = { 43 .latest_ver = FTL_NVC_VERSION_CURRENT, 44 .count = FTL_NVC_VERSION_CURRENT, 45 }, 46 [FTL_LAYOUT_REGION_TYPE_DATA_NVC] = {}, 47 [FTL_LAYOUT_REGION_TYPE_DATA_BASE] = {}, 48 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = { 49 .latest_ver = FTL_P2L_VERSION_CURRENT, 50 .count = FTL_P2L_VERSION_CURRENT, 51 }, 52 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = { 53 .latest_ver = FTL_P2L_VERSION_CURRENT, 54 .count = FTL_P2L_VERSION_CURRENT, 55 }, 56 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = { 57 .latest_ver = FTL_P2L_VERSION_CURRENT, 58 .count = FTL_P2L_VERSION_CURRENT, 59 }, 60 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = { 61 .latest_ver = FTL_P2L_VERSION_CURRENT, 62 .count = FTL_P2L_VERSION_CURRENT, 63 }, 64 [FTL_LAYOUT_REGION_TYPE_TRIM_MD] = {}, 65 [FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = {}, 66 }; 67 68 #include "ftl/upgrade/ftl_layout_upgrade.c" 69 #include "ftl/mngt/ftl_mngt_md.c" 70 71 DEFINE_STUB_V(ftl_mngt_fail_step, (struct ftl_mngt_process *mngt)); 72 DEFINE_STUB_V(ftl_mngt_next_step, (struct ftl_mngt_process *mngt)); 73 DEFINE_STUB_V(ftl_md_persist, (struct ftl_md *md)); 74 DEFINE_STUB(ftl_nv_cache_load_state, int, (struct ftl_nv_cache *nv_cache), 0); 75 DEFINE_STUB_V(ftl_valid_map_load_state, (struct spdk_ftl_dev *dev)); 76 DEFINE_STUB_V(ftl_bands_load_state, (struct spdk_ftl_dev *dev)); 77 DEFINE_STUB(ftl_md_get_region, const struct ftl_layout_region *, (struct ftl_md *md), 0); 78 DEFINE_STUB_V(ftl_md_restore, (struct ftl_md *md)); 79 DEFINE_STUB(ftl_nv_cache_save_state, int, (struct ftl_nv_cache *nv_cache), 0); 80 DEFINE_STUB(ftl_mngt_get_step_ctx, void *, (struct ftl_mngt_process *mngt), 0); 81 DEFINE_STUB_V(ftl_mngt_persist_bands_p2l, (struct ftl_mngt_process *mngt)); 82 DEFINE_STUB_V(ftl_band_init_gc_iter, (struct spdk_ftl_dev *dev)); 83 DEFINE_STUB(ftl_md_create_region_flags, int, (struct spdk_ftl_dev *dev, int region_type), 0); 84 DEFINE_STUB(ftl_md_create, struct ftl_md *, (struct spdk_ftl_dev *dev, uint64_t blocks, 85 uint64_t vss_blksz, const char *name, int flags, const struct ftl_layout_region *region), NULL); 86 DEFINE_STUB(ftl_md_destroy_region_flags, int, (struct spdk_ftl_dev *dev, int region_type), 0); 87 DEFINE_STUB(ftl_md_destroy_shm_flags, int, (struct spdk_ftl_dev *dev), 0); 88 DEFINE_STUB_V(ftl_md_destroy, (struct ftl_md *md, int flags)); 89 DEFINE_STUB_V(ftl_mngt_call_process, (struct ftl_mngt_process *mngt, 90 const struct ftl_mngt_process_desc *process)); 91 DEFINE_STUB(ftl_md_get_buffer, void *, (struct ftl_md *md), NULL); 92 DEFINE_STUB(spdk_bdev_desc_get_bdev, struct spdk_bdev *, (struct spdk_bdev_desc *desc), NULL); 93 DEFINE_STUB(spdk_bdev_get_write_unit_size, uint32_t, (const struct spdk_bdev *bdev), 0); 94 DEFINE_STUB(spdk_bdev_get_num_blocks, uint64_t, (const struct spdk_bdev *bdev), 0); 95 DEFINE_STUB(ftl_nv_cache_chunk_tail_md_num_blocks, size_t, (const struct ftl_nv_cache *nv_cache), 96 0); 97 DEFINE_STUB(ftl_band_user_blocks, size_t, (const struct ftl_band *band), 0); 98 99 struct spdk_bdev_desc { 100 int dummy; 101 }; 102 103 struct spdk_ftl_dev g_dev; 104 struct ftl_superblock_shm g_sb_shm = {0}; 105 struct ftl_base_device_type g_base_type = { .name = "base_dev" }; 106 struct ftl_nv_cache_device_desc g_nvc_desc = { .name = "nvc_dev" }; 107 struct spdk_bdev_desc g_base_bdev_desc = {0}; 108 struct spdk_bdev_desc g_nvc_bdev_desc = {0}; 109 static uint8_t g_sb_buf[FTL_SUPERBLOCK_SIZE] = {0}; 110 111 struct ftl_region_upgrade_desc p2l_upgrade_desc[0]; 112 struct ftl_region_upgrade_desc nvc_upgrade_desc[0]; 113 struct ftl_region_upgrade_desc band_upgrade_desc[0]; 114 115 #define TEST_OP 0x1984 116 #define TEST_REG_BLKS 0x10000 117 #define TEST_NVC_BLKS 0x1000000; 118 #define TEST_BASE_BLKS 0x1000000000; 119 120 static int 121 test_setup(void) 122 { 123 int regno_nvc = 0, regno_base = 0, *regno_dev; 124 125 /* setup a dummy dev: */ 126 g_dev.sb = (void *)g_sb_buf; 127 g_dev.sb_shm = &g_sb_shm; 128 g_dev.conf.overprovisioning = TEST_OP; 129 for (uint64_t n = 0; n < sizeof(g_dev.conf.uuid); n++) { 130 g_dev.conf.uuid.u.raw[n] = n; 131 } 132 133 g_dev.layout.nvc.total_blocks = TEST_NVC_BLKS; 134 g_dev.layout.base.total_blocks = TEST_BASE_BLKS; 135 g_dev.base_type = &g_base_type; 136 g_dev.nv_cache.nvc_desc = &g_nvc_desc; 137 g_dev.base_layout_tracker = ftl_layout_tracker_bdev_init(UINT32_MAX); 138 g_dev.nvc_layout_tracker = ftl_layout_tracker_bdev_init(UINT32_MAX); 139 g_dev.base_bdev_desc = &g_base_bdev_desc; 140 g_dev.nv_cache.bdev_desc = &g_nvc_bdev_desc; 141 142 for (int regno = 0; regno < FTL_LAYOUT_REGION_TYPE_MAX; regno++) { 143 struct ftl_layout_region *reg = &g_dev.layout.region[regno]; 144 145 reg->current.blocks = TEST_REG_BLKS; 146 regno_dev = sb_v3_md_region_is_nvc(regno) ? ®no_nvc : ®no_base; 147 reg->current.offset = *regno_dev * TEST_REG_BLKS; 148 (*regno_dev)++; 149 reg->current.version = ftl_layout_upgrade_region_get_latest_version(regno); 150 reg->type = regno; 151 reg->name = "region_test"; 152 reg->bdev_desc = sb_v3_md_region_is_nvc(regno) ? &g_nvc_bdev_desc : &g_base_bdev_desc; 153 reg->ioch = 0; 154 } 155 return 0; 156 } 157 158 static int 159 test_teardown(void) 160 { 161 if (g_dev.base_layout_tracker) { 162 ftl_layout_tracker_bdev_fini(g_dev.base_layout_tracker); 163 g_dev.base_layout_tracker = NULL; 164 } 165 if (g_dev.nvc_layout_tracker) { 166 ftl_layout_tracker_bdev_fini(g_dev.nvc_layout_tracker); 167 g_dev.nvc_layout_tracker = NULL; 168 } 169 return 0; 170 } 171 172 static void 173 test_setup_sb_ver(uint64_t ver, uint64_t clean) 174 { 175 union ftl_superblock_ver *sb = (void *)g_sb_buf; 176 uint64_t zero_offs; 177 178 memset(&g_sb_buf, 0, sizeof(g_sb_buf)); 179 ftl_mngt_init_default_sb(&g_dev, NULL); 180 if (ver <= FTL_SB_VERSION_3) { 181 sb->header.magic = FTL_SUPERBLOCK_MAGIC_V2; 182 } 183 sb->header.version = ver; 184 185 switch (ver) { 186 case FTL_SB_VERSION_0: 187 case FTL_SB_VERSION_1: 188 case FTL_SB_VERSION_2: 189 zero_offs = sizeof(struct ftl_superblock_v2); 190 memset(g_sb_buf + zero_offs, 0, sizeof(g_sb_buf) - zero_offs); 191 sb->v2.clean = clean; 192 break; 193 194 case FTL_SB_VERSION_3: 195 case FTL_SB_VERSION_4: 196 zero_offs = sizeof(struct ftl_superblock_v3); 197 memset(g_sb_buf + zero_offs, 0, sizeof(g_sb_buf) - zero_offs); 198 sb->v3.clean = clean; 199 sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_INVALID; 200 break; 201 202 case FTL_SB_VERSION_5: 203 zero_offs = sizeof(struct ftl_superblock_v5); 204 memset(g_sb_buf + zero_offs, 0, sizeof(g_sb_buf) - zero_offs); 205 sb->v5.clean = clean; 206 break; 207 } 208 209 sb->header.crc = get_sb_crc(&sb->current); 210 } 211 212 static void 213 test_setup_sb_v2(uint64_t clean) 214 { 215 test_setup_sb_ver(FTL_SB_VERSION_2, clean); 216 } 217 218 static void 219 test_setup_sb_v3(uint64_t clean) 220 { 221 test_setup_sb_ver(FTL_SB_VERSION_3, clean); 222 } 223 224 static void 225 test_setup_sb_v5(uint64_t clean) 226 { 227 test_setup_sb_ver(FTL_SB_VERSION_5, clean); 228 } 229 230 static void 231 test_sb_crc_v2(void) 232 { 233 union ftl_superblock_ver *sb = (void *)g_sb_buf; 234 uint64_t crc; 235 236 /* v2-specific crc: it's not really working */ 237 test_setup_sb_v2(true); 238 crc = sb->header.crc; 239 240 sb->header.crc++; 241 sb->header.crc = get_sb_crc(&sb->current); 242 CU_ASSERT_EQUAL(crc, sb->header.crc); 243 244 g_sb_buf[sizeof(struct ftl_superblock_v2)]++; 245 sb->header.crc = get_sb_crc(&sb->current); 246 CU_ASSERT_EQUAL(crc, sb->header.crc); 247 248 g_sb_buf[sizeof(g_sb_buf) - 1]++; 249 sb->header.crc = get_sb_crc(&sb->current); 250 CU_ASSERT_EQUAL(crc, sb->header.crc); 251 } 252 253 static void 254 test_sb_crc_v3(void) 255 { 256 union ftl_superblock_ver *sb = (void *)g_sb_buf; 257 uint64_t crc; 258 259 /* v3 crc: covers the entire buf */ 260 test_setup_sb_v3(true); 261 crc = sb->header.crc; 262 263 sb->header.crc++; 264 sb->header.crc = get_sb_crc(&sb->current); 265 CU_ASSERT_EQUAL(crc, sb->header.crc); 266 crc = sb->header.crc; 267 268 g_sb_buf[sizeof(struct ftl_superblock_v2)]++; 269 sb->header.crc = get_sb_crc(&sb->current); 270 CU_ASSERT_NOT_EQUAL(crc, sb->header.crc); 271 crc = sb->header.crc; 272 273 g_sb_buf[sizeof(g_sb_buf) - 1]++; 274 sb->header.crc = get_sb_crc(&sb->current); 275 CU_ASSERT_NOT_EQUAL(crc, sb->header.crc); 276 crc = sb->header.crc; 277 278 CU_ASSERT_EQUAL(crc, sb->header.crc); 279 } 280 281 static int 282 test_superblock_v3_md_layout_add(struct spdk_ftl_dev *dev, 283 struct ftl_superblock_v3_md_region *sb_reg, 284 uint32_t reg_type, uint32_t reg_version, uint64_t blk_offs, uint64_t blk_sz) 285 { 286 if (ftl_superblock_v3_md_region_overflow(dev, sb_reg)) { 287 return -EOVERFLOW; 288 } 289 290 sb_reg->type = reg_type; 291 sb_reg->version = reg_version; 292 sb_reg->blk_offs = blk_offs; 293 sb_reg->blk_sz = blk_sz; 294 return 0; 295 } 296 297 static int 298 test_superblock_v3_md_layout_add_free(struct spdk_ftl_dev *dev, 299 struct ftl_superblock_v3_md_region **sb_reg, 300 uint32_t reg_type, uint32_t free_type, uint64_t total_blocks) 301 { 302 struct ftl_layout *layout = &dev->layout; 303 struct ftl_layout_region *reg = &layout->region[reg_type]; 304 uint64_t blks_left = total_blocks - reg->current.offset - reg->current.blocks; 305 306 if (blks_left == 0) { 307 return 0; 308 } 309 310 (*sb_reg)->df_next = ftl_df_get_obj_id(dev->sb, (*sb_reg) + 1); 311 (*sb_reg) = (*sb_reg) + 1; 312 313 if (test_superblock_v3_md_layout_add(dev, *sb_reg, free_type, 0, 314 reg->current.offset + reg->current.blocks, blks_left)) { 315 return -1; 316 } 317 318 (*sb_reg)->df_next = FTL_DF_OBJ_ID_INVALID; 319 320 return 0; 321 } 322 323 static int 324 test_ftl_superblock_v3_md_layout_build(struct spdk_ftl_dev *dev) 325 { 326 union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)dev->sb; 327 struct ftl_layout *layout = &dev->layout; 328 struct ftl_layout_region *reg; 329 int n = 0; 330 bool is_empty = ftl_superblock_v3_md_layout_is_empty(sb_ver); 331 struct ftl_superblock_v3_md_region *sb_reg = &sb_ver->v3.md_layout_head; 332 333 /* TODO: major upgrades: add all free regions being tracked 334 * For now SB MD layout must be empty - otherwise md free regions may be lost */ 335 assert(is_empty); 336 337 for (; n < FTL_LAYOUT_REGION_TYPE_MAX_V3;) { 338 reg = ftl_layout_region_get(dev, n); 339 assert(reg); 340 if (md_region_is_fixed(reg->type)) { 341 n++; 342 343 if (n >= FTL_LAYOUT_REGION_TYPE_MAX_V3) { 344 /* 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 */ 345 sb_reg--; 346 break; 347 } 348 continue; 349 } 350 351 if (test_superblock_v3_md_layout_add(dev, sb_reg, reg->type, reg->current.version, 352 reg->current.offset, reg->current.blocks)) { 353 return -1; 354 } 355 356 n++; 357 if (n < FTL_LAYOUT_REGION_TYPE_MAX_V3) { 358 /* next region */ 359 sb_reg->df_next = ftl_df_get_obj_id(sb_ver, sb_reg + 1); 360 sb_reg++; 361 } 362 } 363 364 /* terminate the list */ 365 sb_reg->df_next = FTL_DF_OBJ_ID_INVALID; 366 367 /* create free_nvc/free_base regions on the first run */ 368 if (is_empty) { 369 test_superblock_v3_md_layout_add_free(dev, &sb_reg, FTL_LAYOUT_REGION_LAST_NVC, 370 FTL_LAYOUT_REGION_TYPE_FREE_NVC, layout->nvc.total_blocks); 371 372 test_superblock_v3_md_layout_add_free(dev, &sb_reg, FTL_LAYOUT_REGION_LAST_BASE, 373 FTL_LAYOUT_REGION_TYPE_FREE_BASE, layout->base.total_blocks); 374 } 375 376 return 0; 377 } 378 379 static void 380 test_sb_v3_region_reinit(void) 381 { 382 uint32_t reg_type; 383 384 for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) { 385 g_dev.layout.region[reg_type].type = reg_type; 386 } 387 } 388 389 static struct ftl_superblock_v3_md_region * 390 test_sb_v3_find_region_ver(enum ftl_layout_region_type reg_type, uint32_t reg_ver) 391 { 392 union ftl_superblock_ver *sb = (void *)g_sb_buf; 393 struct ftl_superblock_v3_md_region *sb_reg = &sb->v3.md_layout_head; 394 395 while (sb_reg->type != FTL_LAYOUT_REGION_TYPE_INVALID) { 396 if (sb_reg->type == reg_type && sb_reg->version == reg_ver) { 397 return sb_reg; 398 } 399 400 if (sb_reg->df_next == FTL_DF_OBJ_ID_INVALID) { 401 break; 402 } 403 404 if (UINT64_MAX - (uintptr_t)sb <= sb_reg->df_next) { 405 return NULL; 406 } 407 408 sb_reg = ftl_df_get_obj_ptr(sb, sb_reg->df_next); 409 if (ftl_superblock_v3_md_region_overflow(&g_dev, sb_reg)) { 410 return NULL; 411 } 412 } 413 414 return NULL; 415 } 416 417 static struct ftl_superblock_v3_md_region * 418 test_sb_v3_find_region_latest(enum ftl_layout_region_type reg_type) 419 { 420 return test_sb_v3_find_region_ver(reg_type, ftl_layout_upgrade_region_get_latest_version(reg_type)); 421 } 422 423 static void 424 test_sb_v3_md_layout(void) 425 { 426 struct ftl_superblock_v3_md_region *sb_reg, *sb_reg_next, *sb_reg_next2; 427 struct ftl_layout_region *reg_head, *reg; 428 union ftl_superblock_ver *sb = (void *)g_sb_buf; 429 ftl_df_obj_id df_next_head, df_next_reg; 430 uint32_t md_type_head; 431 int rc; 432 433 test_setup_sb_v3(false); 434 CU_ASSERT_EQUAL(ftl_superblock_is_blob_area_empty(&sb->current), true); 435 436 /* load failed: empty md list: */ 437 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 438 CU_ASSERT_NOT_EQUAL(rc, 0); 439 test_sb_v3_region_reinit(); 440 441 /* create md layout: */ 442 test_ftl_superblock_v3_md_layout_build(&g_dev); 443 CU_ASSERT_EQUAL(ftl_superblock_is_blob_area_empty(&sb->current), false); 444 445 /* buf overflow, sb_reg = 1 byte overflow: */ 446 df_next_head = sb->v3.md_layout_head.df_next; 447 sb->v3.md_layout_head.df_next = FTL_SUPERBLOCK_SIZE - sizeof(sb->v3.md_layout_head) + 1; 448 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 449 CU_ASSERT_EQUAL(rc, -EOVERFLOW); 450 test_sb_v3_region_reinit(); 451 452 /* buf underflow, sb_reg = -1: */ 453 sb->v3.md_layout_head.df_next = UINTPTR_MAX - (uintptr_t)sb; 454 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 455 CU_ASSERT_EQUAL(rc, -EOVERFLOW); 456 test_sb_v3_region_reinit(); 457 458 /* buf underflow, sb_reg = 2 bytes underflow */ 459 sb->v3.md_layout_head.df_next = UINTPTR_MAX - 1; 460 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 461 CU_ASSERT_EQUAL(rc, -EOVERFLOW); 462 test_sb_v3_region_reinit(); 463 464 /* looping md layout list: */ 465 sb->v3.md_layout_head.df_next = ftl_df_get_obj_id(sb, &sb->v3.md_layout_head); 466 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 467 CU_ASSERT_NOT_EQUAL(rc, 0); 468 test_sb_v3_region_reinit(); 469 470 sb->v3.md_layout_head.df_next = df_next_head; 471 472 /* unsupported/fixed md region: */ 473 md_type_head = sb->v3.md_layout_head.type; 474 sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_SB; 475 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 476 CU_ASSERT_NOT_EQUAL(rc, 0); 477 test_sb_v3_region_reinit(); 478 479 /* unsupported/invalid md region: */ 480 sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_MAX; 481 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 482 CU_ASSERT_NOT_EQUAL(rc, 0); 483 test_sb_v3_region_reinit(); 484 485 /* unsupported/invalid md region: */ 486 sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_MAX_V3; 487 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 488 CU_ASSERT_NOT_EQUAL(rc, 0); 489 test_sb_v3_region_reinit(); 490 491 /* restore the sb: */ 492 sb->v3.md_layout_head.type = md_type_head; 493 494 /* load succeeded, no prev version found: */ 495 reg_head = &g_dev.layout.region[md_type_head]; 496 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 497 CU_ASSERT_EQUAL(rc, 0); 498 CU_ASSERT_EQUAL(reg_head->current.version, 499 ftl_layout_upgrade_region_get_latest_version(md_type_head)); 500 test_sb_v3_region_reinit(); 501 502 /* load succeeded, prev (upgrade, i.e. no current) version discovery: */ 503 reg = &g_dev.layout.region[FTL_LAYOUT_REGION_TYPE_BAND_MD]; 504 sb_reg = test_sb_v3_find_region_latest(FTL_LAYOUT_REGION_TYPE_BAND_MD); 505 CU_ASSERT_NOT_EQUAL(sb_reg, NULL); 506 CU_ASSERT_EQUAL(reg->type, sb_reg->type); 507 df_next_reg = sb_reg->df_next; 508 509 sb_reg->version--; 510 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 511 CU_ASSERT_EQUAL(rc, 0); 512 CU_ASSERT_EQUAL(reg->current.version, sb_reg->version); 513 sb_reg->version++; 514 test_sb_v3_region_reinit(); 515 516 /* load succeeded, newer version found: */ 517 sb_reg->df_next = FTL_SUPERBLOCK_SIZE - sizeof(*sb_reg_next); 518 sb_reg_next = ftl_df_get_obj_ptr(sb, sb_reg->df_next); 519 rc = test_superblock_v3_md_layout_add(&g_dev, sb_reg_next, sb_reg->type, sb_reg->version + 1, 520 sb_reg->blk_offs, sb_reg->blk_sz); 521 CU_ASSERT_EQUAL(rc, 0); 522 sb_reg_next->df_next = df_next_reg; 523 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 524 CU_ASSERT_EQUAL(rc, 0); 525 CU_ASSERT_EQUAL(reg->current.version, sb_reg->version); 526 test_sb_v3_region_reinit(); 527 528 /* load succeeded, prev version discovery: */ 529 sb_reg_next->version = sb_reg->version - 1; 530 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 531 CU_ASSERT_EQUAL(rc, 0); 532 CU_ASSERT_EQUAL(reg->current.version, sb_reg_next->version); 533 test_sb_v3_region_reinit(); 534 535 /* looping regions found: */ 536 sb_reg_next->df_next = FTL_SUPERBLOCK_SIZE - 2 * sizeof(*sb_reg_next); 537 sb_reg_next2 = ftl_df_get_obj_ptr(sb, sb_reg_next->df_next); 538 rc = test_superblock_v3_md_layout_add(&g_dev, sb_reg_next2, sb_reg_next->type, 539 sb_reg_next->version + 2, 540 sb_reg_next->blk_offs, sb_reg_next->blk_sz); 541 CU_ASSERT_EQUAL(rc, 0); 542 sb_reg_next2->df_next = FTL_SUPERBLOCK_SIZE - 2 * sizeof(*sb_reg_next); 543 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 544 CU_ASSERT_EQUAL(rc, -ELOOP); 545 test_sb_v3_region_reinit(); 546 547 /* multiple (same ver) regions found: */ 548 sb_reg_next2->version = sb_reg_next->version; 549 sb_reg_next2->df_next = df_next_reg; 550 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 551 CU_ASSERT_EQUAL(rc, -EAGAIN); 552 test_sb_v3_region_reinit(); 553 554 /* multiple current regions found: */ 555 sb_reg_next->version = sb_reg->version; 556 sb_reg_next->df_next = df_next_reg; 557 rc = ftl_superblock_v3_md_layout_load_all(&g_dev); 558 CU_ASSERT_EQUAL(rc, -EAGAIN); 559 560 /* restore the sb: */ 561 sb->v3.md_layout_head.df_next = df_next_head; 562 test_sb_v3_region_reinit(); 563 } 564 565 static void 566 test_sb_v5_md_layout(void) 567 { 568 struct layout_tracker_blob_entry *tbe; 569 struct layout_blob_entry *lbe; 570 struct ftl_layout_region *reg; 571 union ftl_superblock_ver *sb = (void *)g_sb_buf; 572 int rc; 573 const struct ftl_layout_tracker_bdev_region_props *reg_props; 574 void *blob_nvc, *blob_base, *blob_regs; 575 576 test_setup_sb_v5(false); 577 CU_ASSERT_EQUAL(ftl_superblock_is_blob_area_empty(&sb->current), true); 578 579 /* load failed: empty md list: */ 580 rc = ftl_superblock_v5_load_blob_area(&g_dev); 581 CU_ASSERT_NOT_EQUAL(rc, 0); 582 583 /* create md layout: */ 584 for (enum ftl_layout_region_type regno = 0; regno < FTL_LAYOUT_REGION_TYPE_MAX; regno++) { 585 struct ftl_layout_region *reg = &g_dev.layout.region[regno]; 586 CU_ASSERT_EQUAL(regno, reg->type); 587 struct ftl_layout_tracker_bdev *tracker = sb_v3_md_region_is_nvc(regno) ? g_dev.nvc_layout_tracker : 588 g_dev.base_layout_tracker; 589 const struct ftl_layout_tracker_bdev_region_props *reg_props = ftl_layout_tracker_bdev_add_region( 590 tracker, reg->type, reg->current.version, reg->current.blocks, TEST_REG_BLKS); 591 592 CU_ASSERT_EQUAL(reg->type, reg_props->type); 593 CU_ASSERT_EQUAL(reg->current.version, reg_props->ver); 594 CU_ASSERT_EQUAL(reg->current.offset, reg_props->blk_offs); 595 CU_ASSERT_EQUAL(reg->current.blocks, reg_props->blk_sz); 596 } 597 ftl_superblock_v5_store_blob_area(&g_dev); 598 CU_ASSERT_EQUAL(ftl_superblock_is_blob_area_empty(&sb->current), false); 599 600 blob_nvc = ftl_df_get_obj_ptr(sb->v5.blob_area, sb->v5.md_layout_nvc.df_id); 601 blob_base = ftl_df_get_obj_ptr(sb->v5.blob_area, sb->v5.md_layout_base.df_id); 602 blob_regs = ftl_df_get_obj_ptr(sb->v5.blob_area, sb->v5.layout_params.df_id); 603 604 /* unsupported nvc md region type: */ 605 tbe = blob_nvc; 606 tbe->type += FTL_LAYOUT_REGION_TYPE_MAX; 607 sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_SB; 608 rc = ftl_superblock_v5_load_blob_area(&g_dev); 609 CU_ASSERT_NOT_EQUAL(rc, 0); 610 tbe->type -= FTL_LAYOUT_REGION_TYPE_MAX; 611 612 /* unsupported base md region type: */ 613 tbe = blob_base; 614 tbe->type += FTL_LAYOUT_REGION_TYPE_MAX; 615 sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_SB; 616 rc = ftl_superblock_v5_load_blob_area(&g_dev); 617 CU_ASSERT_NOT_EQUAL(rc, 0); 618 tbe->type -= FTL_LAYOUT_REGION_TYPE_MAX; 619 620 /* load succeeded, no prev version found: */ 621 reg = &g_dev.layout.region[FTL_LAYOUT_REGION_TYPE_BAND_MD]; 622 rc = ftl_superblock_v5_load_blob_area(&g_dev); 623 CU_ASSERT_EQUAL(rc, 0); 624 reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_latest_region, NULL); 625 CU_ASSERT_NOT_EQUAL(reg_props, NULL); 626 CU_ASSERT_EQUAL(reg_props->ver, reg->current.version); 627 reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_oldest_region, NULL); 628 CU_ASSERT_NOT_EQUAL(reg_props, NULL); 629 CU_ASSERT_EQUAL(reg_props->ver, reg->current.version); 630 631 /* move the sb-stored blobs around: */ 632 CU_ASSERT(blob_nvc < blob_base); 633 CU_ASSERT(blob_base < blob_regs); 634 blob_regs = memmove(blob_regs + 8192, blob_regs, sb->v5.layout_params.blob_sz); 635 sb->v5.layout_params.df_id += 8192; 636 blob_base = memmove(blob_base + 4096, blob_base, sb->v5.md_layout_base.blob_sz); 637 sb->v5.md_layout_base.df_id += 4096; 638 639 /* load succeeded again, no prev version found: */ 640 rc = ftl_superblock_v5_load_blob_area(&g_dev); 641 CU_ASSERT_EQUAL(rc, 0); 642 reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_latest_region, NULL); 643 CU_ASSERT_NOT_EQUAL(reg_props, NULL); 644 CU_ASSERT_EQUAL(reg_props->ver, reg->current.version); 645 reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_oldest_region, NULL); 646 CU_ASSERT_NOT_EQUAL(reg_props, NULL); 647 CU_ASSERT_EQUAL(reg_props->ver, reg->current.version); 648 649 /* load failed, regs overlap: */ 650 tbe = blob_nvc; 651 tbe++; 652 tbe->blk_offs -= tbe->blk_sz; 653 rc = ftl_superblock_v5_load_blob_area(&g_dev); 654 CU_ASSERT_NOT_EQUAL(rc, 0); 655 tbe->blk_offs += tbe->blk_sz; 656 657 /* load failed, the same region version found twice: */ 658 tbe = (blob_nvc + sb->v5.md_layout_nvc.blob_sz); 659 sb->v5.md_layout_nvc.blob_sz += sizeof(*tbe); 660 tbe->type = reg->type; 661 tbe->ver = reg->current.version; 662 tbe->blk_offs = reg->current.offset + FTL_LAYOUT_REGION_TYPE_MAX * reg->current.blocks; 663 tbe->blk_sz = reg->current.blocks; 664 rc = ftl_superblock_v5_load_blob_area(&g_dev); 665 CU_ASSERT_NOT_EQUAL(rc, 0); 666 667 /* load succeeded, prev (upgrade, i.e. no current) version discovery: */ 668 tbe->type = reg->type; 669 tbe->ver = reg->current.version - 1; 670 tbe->blk_offs = reg->current.offset + FTL_LAYOUT_REGION_TYPE_MAX * reg->current.blocks; 671 tbe->blk_sz = reg->current.blocks; 672 rc = ftl_superblock_v5_load_blob_area(&g_dev); 673 CU_ASSERT_EQUAL(rc, 0); 674 reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_latest_region, NULL); 675 CU_ASSERT_NOT_EQUAL(reg_props, NULL); 676 CU_ASSERT_EQUAL(reg_props->ver, reg->current.version); 677 reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_oldest_region, NULL); 678 CU_ASSERT_NOT_EQUAL(reg_props, NULL); 679 CU_ASSERT_EQUAL(reg_props->ver, reg->current.version - 1); 680 681 /* load succeeded, newer version found: */ 682 tbe->ver = reg->current.version + 1; 683 rc = ftl_superblock_v5_load_blob_area(&g_dev); 684 CU_ASSERT_EQUAL(rc, 0); 685 reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_latest_region, NULL); 686 CU_ASSERT_NOT_EQUAL(reg_props, NULL); 687 CU_ASSERT_EQUAL(reg_props->ver, reg->current.version + 1); 688 reg_props = sb_md_layout_find_region(&g_dev, reg->type, sb_md_layout_find_oldest_region, NULL); 689 CU_ASSERT_NOT_EQUAL(reg_props, NULL); 690 CU_ASSERT_EQUAL(reg_props->ver, reg->current.version); 691 692 /* load failed, invalid type in layout properties: */ 693 lbe = blob_regs; 694 lbe += FTL_LAYOUT_REGION_TYPE_BAND_MD; 695 CU_ASSERT_EQUAL(lbe->type, FTL_LAYOUT_REGION_TYPE_BAND_MD); 696 lbe->type = FTL_LAYOUT_REGION_TYPE_MAX; 697 rc = ftl_superblock_v5_load_blob_area(&g_dev); 698 CU_ASSERT_NOT_EQUAL(rc, 0); 699 lbe->type = FTL_LAYOUT_REGION_TYPE_BAND_MD; 700 701 /* load succeeded, restore layout properties: */ 702 CU_ASSERT_EQUAL(reg->num_entries, 0); 703 CU_ASSERT_EQUAL(reg->entry_size, 0); 704 lbe->num_entries = 0x1984; 705 lbe->entry_size = 0x1405; 706 rc = ftl_superblock_v5_load_blob_area(&g_dev); 707 CU_ASSERT_EQUAL(rc, 0); 708 CU_ASSERT_EQUAL(reg->num_entries, 0x1984); 709 CU_ASSERT_EQUAL(reg->entry_size, 0x1405); 710 711 /* restore the sb: */ 712 sb->v5.md_layout_nvc.blob_sz -= sizeof(*tbe); 713 } 714 715 int 716 main(int argc, char **argv) 717 { 718 CU_pSuite suite = NULL; 719 unsigned int num_failures = 0; 720 721 CU_set_error_action(CUEA_ABORT); 722 CU_initialize_registry(); 723 724 suite = CU_add_suite("ftl_sb", test_setup, test_teardown); 725 726 CU_ADD_TEST(suite, test_sb_crc_v2); 727 CU_ADD_TEST(suite, test_sb_crc_v3); 728 CU_ADD_TEST(suite, test_sb_v3_md_layout); 729 CU_ADD_TEST(suite, test_sb_v5_md_layout); 730 731 CU_basic_set_mode(CU_BRM_VERBOSE); 732 CU_basic_run_tests(); 733 num_failures = CU_get_number_of_failures(); 734 CU_cleanup_registry(); 735 736 return num_failures; 737 } 738