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