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