1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2023 Solidigm All Rights Reserved 3 * Copyright (C) 2022 Intel Corporation. 4 * All rights reserved. 5 */ 6 7 #include "spdk/bdev.h" 8 9 #include "ftl_core.h" 10 #include "ftl_utils.h" 11 #include "ftl_band.h" 12 #include "ftl_layout.h" 13 #include "ftl_nv_cache.h" 14 #include "ftl_sb.h" 15 #include "nvc/ftl_nvc_dev.h" 16 #include "utils/ftl_layout_tracker_bdev.h" 17 #include "upgrade/ftl_layout_upgrade.h" 18 19 enum ftl_layout_setup_mode { 20 FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT = 0, 21 FTL_LAYOUT_SETUP_MODE_NO_RESTRICT, 22 FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT, 23 }; 24 25 static inline float 26 blocks2mib(uint64_t blocks) 27 { 28 float result; 29 30 result = blocks; 31 result *= FTL_BLOCK_SIZE; 32 result /= 1024UL; 33 result /= 1024UL; 34 35 return result; 36 } 37 38 static uint64_t 39 superblock_region_size(struct spdk_ftl_dev *dev) 40 { 41 const struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 42 uint64_t wus = spdk_bdev_get_write_unit_size(bdev) * FTL_BLOCK_SIZE; 43 44 if (wus > FTL_SUPERBLOCK_SIZE) { 45 return wus; 46 } else { 47 return wus * spdk_divide_round_up(FTL_SUPERBLOCK_SIZE, wus); 48 } 49 } 50 51 static uint64_t 52 superblock_region_blocks(struct spdk_ftl_dev *dev) 53 { 54 return superblock_region_size(dev) / FTL_BLOCK_SIZE; 55 } 56 57 uint64_t 58 ftl_md_region_blocks(struct spdk_ftl_dev *dev, uint64_t bytes) 59 { 60 const uint64_t alignment = superblock_region_size(dev); 61 uint64_t result; 62 63 result = spdk_divide_round_up(bytes, alignment); 64 result *= alignment; 65 result /= FTL_BLOCK_SIZE; 66 67 return result; 68 } 69 70 uint64_t 71 ftl_md_region_align_blocks(struct spdk_ftl_dev *dev, uint64_t blocks) 72 { 73 const uint64_t alignment = superblock_region_blocks(dev); 74 uint64_t result; 75 76 result = spdk_divide_round_up(blocks, alignment); 77 result *= alignment; 78 79 return result; 80 } 81 82 const char * 83 ftl_md_region_name(enum ftl_layout_region_type reg_type) 84 { 85 static const char *md_region_name[FTL_LAYOUT_REGION_TYPE_MAX] = { 86 [FTL_LAYOUT_REGION_TYPE_SB] = "sb", 87 [FTL_LAYOUT_REGION_TYPE_SB_BASE] = "sb_mirror", 88 [FTL_LAYOUT_REGION_TYPE_L2P] = "l2p", 89 [FTL_LAYOUT_REGION_TYPE_BAND_MD] = "band_md", 90 [FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = "band_md_mirror", 91 [FTL_LAYOUT_REGION_TYPE_VALID_MAP] = "vmap", 92 [FTL_LAYOUT_REGION_TYPE_NVC_MD] = "nvc_md", 93 [FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = "nvc_md_mirror", 94 [FTL_LAYOUT_REGION_TYPE_DATA_NVC] = "data_nvc", 95 [FTL_LAYOUT_REGION_TYPE_DATA_BASE] = "data_btm", 96 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = "p2l0", 97 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = "p2l1", 98 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = "p2l2", 99 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = "p2l3", 100 [FTL_LAYOUT_REGION_TYPE_TRIM_MD] = "trim_md", 101 [FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = "trim_md_mirror", 102 }; 103 const char *reg_name = md_region_name[reg_type]; 104 105 assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX); 106 assert(reg_name != NULL); 107 return reg_name; 108 } 109 110 static void 111 dump_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *region) 112 { 113 assert(!(region->current.offset % superblock_region_blocks(dev))); 114 assert(!(region->current.blocks % superblock_region_blocks(dev))); 115 116 FTL_NOTICELOG(dev, "Region %s\n", region->name); 117 FTL_NOTICELOG(dev, " offset: %.2f MiB\n", 118 blocks2mib(region->current.offset)); 119 FTL_NOTICELOG(dev, " blocks: %.2f MiB\n", 120 blocks2mib(region->current.blocks)); 121 } 122 123 int 124 ftl_validate_regions(struct spdk_ftl_dev *dev, struct ftl_layout *layout) 125 { 126 enum ftl_layout_region_type i, j; 127 128 /* Validate if regions doesn't overlap each other */ 129 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) { 130 struct ftl_layout_region *r1 = ftl_layout_region_get(dev, i); 131 132 if (!r1) { 133 continue; 134 } 135 136 for (j = 0; j < FTL_LAYOUT_REGION_TYPE_MAX; j++) { 137 struct ftl_layout_region *r2 = ftl_layout_region_get(dev, j); 138 139 if (!r2) { 140 continue; 141 } 142 143 if (r1->bdev_desc != r2->bdev_desc) { 144 continue; 145 } 146 147 if (i == j) { 148 continue; 149 } 150 151 uint64_t r1_begin = r1->current.offset; 152 uint64_t r1_end = r1->current.offset + r1->current.blocks - 1; 153 uint64_t r2_begin = r2->current.offset; 154 uint64_t r2_end = r2->current.offset + r2->current.blocks - 1; 155 156 if (spdk_max(r1_begin, r2_begin) <= spdk_min(r1_end, r2_end)) { 157 FTL_ERRLOG(dev, "Layout initialization ERROR, two regions overlap, " 158 "%s and %s\n", r1->name, r2->name); 159 return -1; 160 } 161 } 162 } 163 164 return 0; 165 } 166 167 static uint64_t 168 get_num_user_lbas(struct spdk_ftl_dev *dev) 169 { 170 uint64_t blocks; 171 172 blocks = dev->num_bands * ftl_get_num_blocks_in_band(dev); 173 blocks = (blocks * (100 - dev->conf.overprovisioning)) / 100; 174 175 return blocks; 176 } 177 178 struct ftl_layout_region * 179 ftl_layout_region_get(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type) 180 { 181 struct ftl_layout_region *reg = &dev->layout.region[reg_type]; 182 183 assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX); 184 return reg->type == reg_type ? reg : NULL; 185 } 186 187 uint64_t 188 ftl_layout_base_offset(struct spdk_ftl_dev *dev) 189 { 190 return dev->num_bands * ftl_get_num_blocks_in_band(dev); 191 } 192 193 static int 194 layout_region_create_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 195 uint32_t reg_version, size_t entry_size, size_t entry_count) 196 { 197 const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops; 198 size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size); 199 200 if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) { 201 return -1; 202 } 203 if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, 204 &dev->layout.region[reg_type])) { 205 return -1; 206 } 207 return 0; 208 } 209 210 static int 211 layout_region_create_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 212 uint32_t reg_version, size_t entry_size, size_t entry_count) 213 { 214 const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops; 215 size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size); 216 217 if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) { 218 return -1; 219 } 220 if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, 221 &dev->layout.region[reg_type])) { 222 return -1; 223 } 224 return 0; 225 } 226 227 static void 228 legacy_layout_verify_region(struct ftl_layout_tracker_bdev *layout_tracker, 229 enum ftl_layout_region_type reg_type, uint32_t reg_version) 230 { 231 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 232 const struct ftl_layout_tracker_bdev_region_props *reg_found = NULL; 233 234 while (true) { 235 ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 236 if (!reg_search_ctx) { 237 break; 238 } 239 240 /* Only a single region version is present in upgrade from the legacy layout */ 241 ftl_bug(reg_search_ctx->ver != reg_version); 242 ftl_bug(reg_found != NULL); 243 244 reg_found = reg_search_ctx; 245 } 246 } 247 248 static int 249 legacy_layout_region_open_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 250 uint32_t reg_version, size_t entry_size, size_t entry_count) 251 { 252 struct ftl_layout_region *reg = &dev->layout.region[reg_type]; 253 const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops; 254 255 legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version); 256 return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg); 257 } 258 259 static int 260 legacy_layout_region_open_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 261 uint32_t reg_version, size_t entry_size, size_t entry_count) 262 { 263 struct ftl_layout_region *reg = &dev->layout.region[reg_type]; 264 const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops; 265 266 legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version); 267 return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg); 268 } 269 270 static int 271 layout_setup_legacy_default_nvc(struct spdk_ftl_dev *dev) 272 { 273 int region_type; 274 uint64_t blocks, chunk_count; 275 struct ftl_layout *layout = &dev->layout; 276 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 277 278 /* Initialize L2P region */ 279 blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas); 280 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE, 281 blocks)) { 282 goto error; 283 } 284 285 /* Initialize band info metadata */ 286 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_1, 287 sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 288 goto error; 289 } 290 291 /* Initialize band info metadata mirror */ 292 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_1, 293 sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 294 goto error; 295 } 296 layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR; 297 298 /* 299 * Initialize P2L checkpointing regions 300 */ 301 for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN; 302 region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX; 303 region_type++) { 304 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 305 306 /* Get legacy number of blocks */ 307 ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, region_type, ®_search_ctx); 308 if (!reg_search_ctx || reg_search_ctx->ver != FTL_P2L_VERSION_1) { 309 goto error; 310 } 311 blocks = reg_search_ctx->blk_sz; 312 313 if (legacy_layout_region_open_nvc(dev, region_type, FTL_P2L_VERSION_1, FTL_BLOCK_SIZE, blocks)) { 314 goto error; 315 } 316 } 317 318 /* 319 * Initialize trim metadata region 320 */ 321 blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks; 322 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, sizeof(uint64_t), 323 blocks)) { 324 goto error; 325 } 326 327 /* Initialize trim metadata mirror region */ 328 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, sizeof(uint64_t), 329 blocks)) { 330 goto error; 331 } 332 layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR; 333 334 /* Restore chunk count */ 335 ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_DATA_NVC, 336 ®_search_ctx); 337 if (!reg_search_ctx || reg_search_ctx->ver != 0) { 338 goto error; 339 } 340 blocks = reg_search_ctx->blk_sz; 341 chunk_count = blocks / ftl_get_num_blocks_in_band(dev); 342 if (0 == chunk_count) { 343 goto error; 344 } 345 346 /* 347 * Initialize NV Cache metadata 348 */ 349 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_1, 350 sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) { 351 goto error; 352 } 353 354 /* 355 * Initialize NV Cache metadata mirror 356 */ 357 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_1, 358 sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) { 359 goto error; 360 } 361 layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR; 362 363 /* 364 * Initialize data region on NV cache 365 */ 366 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_DATA_NVC, 0, 367 layout->nvc.chunk_data_blocks * FTL_BLOCK_SIZE, chunk_count)) { 368 goto error; 369 } 370 371 return 0; 372 373 error: 374 FTL_ERRLOG(dev, "Invalid legacy NV Cache metadata layout\n"); 375 return -1; 376 } 377 378 static int 379 layout_setup_legacy_default_base(struct spdk_ftl_dev *dev) 380 { 381 struct ftl_layout *layout = &dev->layout; 382 383 /* Base device layout is as follows: 384 * - superblock 385 * - data 386 * - valid map 387 */ 388 if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE, 389 ftl_layout_base_offset(dev))) { 390 return -1; 391 } 392 393 if (legacy_layout_region_open_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE, 394 ftl_md_region_blocks(dev, spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks, 395 8)))) { 396 return -1; 397 } 398 399 return 0; 400 } 401 402 static int 403 layout_setup_legacy_default(struct spdk_ftl_dev *dev) 404 { 405 if (layout_setup_legacy_default_nvc(dev) || layout_setup_legacy_default_base(dev)) { 406 return -1; 407 } 408 return 0; 409 } 410 411 static int 412 layout_setup_default_nvc(struct spdk_ftl_dev *dev) 413 { 414 int region_type; 415 uint64_t l2p_blocks; 416 struct ftl_layout *layout = &dev->layout; 417 418 /* Initialize L2P region */ 419 l2p_blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas); 420 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE, l2p_blocks)) { 421 goto error; 422 } 423 424 /* Initialize band info metadata */ 425 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_CURRENT, 426 sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 427 goto error; 428 } 429 430 /* Initialize band info metadata mirror */ 431 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_CURRENT, 432 sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 433 goto error; 434 } 435 layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR; 436 437 /* 438 * Initialize P2L checkpointing regions 439 */ 440 for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN; 441 region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX; 442 region_type++) { 443 if (layout_region_create_nvc(dev, region_type, FTL_P2L_VERSION_CURRENT, FTL_BLOCK_SIZE, 444 layout->p2l.ckpt_pages)) { 445 goto error; 446 } 447 } 448 449 /* 450 * Initialize trim metadata region 451 */ 452 l2p_blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks; 453 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, sizeof(uint64_t), 454 l2p_blocks)) { 455 goto error; 456 } 457 458 /* Initialize trim metadata mirror region */ 459 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, sizeof(uint64_t), 460 l2p_blocks)) { 461 goto error; 462 } 463 layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR; 464 465 /* 466 * Initialize NV Cache metadata 467 */ 468 if (0 == layout->nvc.chunk_count) { 469 goto error; 470 } 471 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_CURRENT, 472 sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) { 473 goto error; 474 } 475 476 /* 477 * Initialize NV Cache metadata mirror 478 */ 479 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_CURRENT, 480 sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) { 481 goto error; 482 } 483 layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR; 484 485 return 0; 486 487 error: 488 FTL_ERRLOG(dev, "Insufficient NV Cache capacity to preserve metadata\n"); 489 return -1; 490 } 491 492 static int 493 layout_setup_default_base(struct spdk_ftl_dev *dev) 494 { 495 struct ftl_layout *layout = &dev->layout; 496 uint64_t valid_map_size; 497 498 /* Base device layout is as follows: 499 * - superblock 500 * - data 501 * - valid map 502 */ 503 if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE, 504 ftl_layout_base_offset(dev))) { 505 return -1; 506 } 507 508 valid_map_size = spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks, 8); 509 if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE, 510 ftl_md_region_blocks(dev, valid_map_size))) { 511 return -1; 512 } 513 514 return 0; 515 } 516 517 static int 518 layout_setup_default(struct spdk_ftl_dev *dev) 519 { 520 if (layout_setup_default_nvc(dev) || layout_setup_default_base(dev)) { 521 return -1; 522 } 523 return 0; 524 } 525 526 static int 527 layout_load(struct spdk_ftl_dev *dev) 528 { 529 if (ftl_superblock_load_blob_area(dev)) { 530 return -1; 531 } 532 if (ftl_superblock_md_layout_apply(dev)) { 533 return -1; 534 } 535 return 0; 536 } 537 538 int 539 ftl_layout_setup(struct spdk_ftl_dev *dev) 540 { 541 struct ftl_layout *layout = &dev->layout; 542 uint64_t i; 543 uint64_t num_lbas; 544 enum ftl_layout_setup_mode setup_mode; 545 int rc; 546 547 /* 548 * SB v5 adds the ability to create MD regions dynamically, i.e. depending on the underlying device type. 549 * For compatibility reasons: 550 * 1. When upgrading from pre-v5 SB, only the legacy default layout is created. 551 * Pre-v5: some regions were static and not stored in the SB layout. These must be created to match 552 * the legacy default layout. 553 * v5: all regions are stored in the SB layout. Upon the SB upgrade, the legacy default layout 554 * is updated with pre-v5 layout stored in the SB. The whole layout is then stored in v5 SB. 555 * 556 * 2. When SB v5 or later was loaded, the layout is instantiated from the nvc and base layout blobs. 557 * No default layout is created. 558 * 559 * 3. When the FTL layout is being created for the first time, there are no restrictions. 560 * 561 * Any new regions to be created in cases (1) and (2) can only be placed in the unallocated area 562 * of the underlying device. 563 */ 564 565 if (dev->conf.mode & SPDK_FTL_MODE_CREATE) { 566 setup_mode = FTL_LAYOUT_SETUP_MODE_NO_RESTRICT; 567 } else if (ftl_superblock_is_blob_area_empty(dev->sb)) { 568 setup_mode = FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT; 569 } else { 570 setup_mode = FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT; 571 } 572 FTL_NOTICELOG(dev, "FTL layout setup mode %d\n", (int)setup_mode); 573 574 /* Invalidate all regions */ 575 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 576 if (i == FTL_LAYOUT_REGION_TYPE_SB || i == FTL_LAYOUT_REGION_TYPE_SB_BASE) { 577 /* Super block has been already initialized */ 578 continue; 579 } 580 581 layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 582 /* Mark the region inactive */ 583 layout->region[i].type = FTL_LAYOUT_REGION_TYPE_INVALID; 584 } 585 586 /* 587 * Initialize L2P information 588 */ 589 num_lbas = get_num_user_lbas(dev); 590 if (dev->num_lbas == 0) { 591 assert(dev->conf.mode & SPDK_FTL_MODE_CREATE); 592 dev->num_lbas = num_lbas; 593 dev->sb->lba_cnt = num_lbas; 594 } else if (dev->num_lbas != num_lbas) { 595 FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n"); 596 return -EINVAL; 597 } 598 layout->l2p.addr_length = spdk_u64log2(layout->base.total_blocks + layout->nvc.total_blocks) + 1; 599 layout->l2p.addr_size = layout->l2p.addr_length > 32 ? 8 : 4; 600 layout->l2p.lbas_in_page = FTL_BLOCK_SIZE / layout->l2p.addr_size; 601 602 /* Setup P2L ckpt */ 603 layout->p2l.pages_per_xfer = spdk_divide_round_up(dev->xfer_size, FTL_NUM_P2L_ENTRIES_NO_VSS); 604 layout->p2l.ckpt_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev), 605 dev->xfer_size) * layout->p2l.pages_per_xfer; 606 607 layout->nvc.chunk_data_blocks = ftl_get_num_blocks_in_band(dev); 608 layout->nvc.chunk_count = layout->nvc.total_blocks / ftl_get_num_blocks_in_band(dev); 609 layout->nvc.chunk_tail_md_num_blocks = ftl_nv_cache_chunk_tail_md_num_blocks(&dev->nv_cache); 610 611 layout->base.num_usable_blocks = ftl_get_num_blocks_in_band(dev); 612 layout->base.user_blocks = ftl_band_user_blocks(dev->bands); 613 614 switch (setup_mode) { 615 case FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT: 616 if (layout_setup_legacy_default(dev)) { 617 return -EINVAL; 618 } 619 break; 620 621 case FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT: 622 if (layout_load(dev)) { 623 return -EINVAL; 624 } 625 break; 626 627 case FTL_LAYOUT_SETUP_MODE_NO_RESTRICT: 628 if (layout_setup_default(dev)) { 629 return -EINVAL; 630 } 631 break; 632 633 default: 634 ftl_abort(); 635 break; 636 } 637 638 if (ftl_validate_regions(dev, layout)) { 639 return -EINVAL; 640 } 641 642 /* Now drop the unused regions in preparation for the layout upgrade */ 643 if (ftl_layout_upgrade_drop_regions(dev)) { 644 return -EINVAL; 645 } 646 647 rc = ftl_superblock_store_blob_area(dev); 648 649 FTL_NOTICELOG(dev, "Base device capacity: %.2f MiB\n", 650 blocks2mib(layout->base.total_blocks)); 651 FTL_NOTICELOG(dev, "NV cache device capacity: %.2f MiB\n", 652 blocks2mib(layout->nvc.total_blocks)); 653 FTL_NOTICELOG(dev, "L2P entries: %"PRIu64"\n", dev->num_lbas); 654 FTL_NOTICELOG(dev, "L2P address size: %"PRIu64"\n", layout->l2p.addr_size); 655 FTL_NOTICELOG(dev, "P2L checkpoint pages: %"PRIu64"\n", layout->p2l.ckpt_pages); 656 FTL_NOTICELOG(dev, "NV cache chunk count %"PRIu64"\n", dev->layout.nvc.chunk_count); 657 658 return rc; 659 } 660 661 int 662 ftl_layout_setup_superblock(struct spdk_ftl_dev *dev) 663 { 664 const struct spdk_bdev *bdev; 665 struct ftl_layout *layout = &dev->layout; 666 struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB]; 667 uint64_t total_blocks, offset, left; 668 669 assert(layout->md[FTL_LAYOUT_REGION_TYPE_SB] == NULL); 670 671 bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 672 layout->base.total_blocks = spdk_bdev_get_num_blocks(bdev); 673 674 bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc); 675 layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev); 676 677 /* Initialize superblock region */ 678 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_SB, FTL_SB_VERSION_CURRENT, 679 superblock_region_size(dev), 1)) { 680 FTL_ERRLOG(dev, "Error when setting up primary super block\n"); 681 return -1; 682 } 683 684 assert(region->bdev_desc != NULL); 685 assert(region->ioch != NULL); 686 assert(region->current.offset == 0); 687 688 if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_SB_BASE, FTL_SB_VERSION_CURRENT, 689 superblock_region_size(dev), 1)) { 690 FTL_ERRLOG(dev, "Error when setting up secondary super block\n"); 691 return -1; 692 } 693 layout->region[FTL_LAYOUT_REGION_TYPE_SB].mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE; 694 695 region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE]; 696 assert(region->current.offset == 0); 697 698 /* Check if SB can be stored at the end of base device */ 699 total_blocks = spdk_bdev_get_num_blocks( 700 spdk_bdev_desc_get_bdev(dev->base_bdev_desc)); 701 offset = region->current.offset + region->current.blocks; 702 left = total_blocks - offset; 703 if ((left > total_blocks) || (offset > total_blocks)) { 704 FTL_ERRLOG(dev, "Error when setup base device super block\n"); 705 return -1; 706 } 707 708 return 0; 709 } 710 711 int 712 ftl_layout_clear_superblock(struct spdk_ftl_dev *dev) 713 { 714 int rc; 715 716 rc = ftl_layout_tracker_bdev_rm_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB, 717 FTL_SB_VERSION_CURRENT); 718 if (rc) { 719 return rc; 720 } 721 722 return ftl_layout_tracker_bdev_rm_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB_BASE, 723 FTL_SB_VERSION_CURRENT); 724 } 725 726 void 727 ftl_layout_dump(struct spdk_ftl_dev *dev) 728 { 729 struct ftl_layout_region *reg; 730 enum ftl_layout_region_type i; 731 732 FTL_NOTICELOG(dev, "NV cache layout:\n"); 733 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 734 reg = ftl_layout_region_get(dev, i); 735 if (reg && reg->bdev_desc == dev->nv_cache.bdev_desc) { 736 dump_region(dev, reg); 737 } 738 } 739 FTL_NOTICELOG(dev, "Base device layout:\n"); 740 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 741 reg = ftl_layout_region_get(dev, i); 742 if (reg && reg->bdev_desc == dev->base_bdev_desc) { 743 dump_region(dev, reg); 744 } 745 } 746 } 747 748 uint64_t 749 ftl_layout_base_md_blocks(struct spdk_ftl_dev *dev) 750 { 751 const struct spdk_bdev *bdev; 752 uint64_t md_blocks = 0, total_blocks = 0; 753 754 bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 755 total_blocks += spdk_bdev_get_num_blocks(bdev); 756 757 bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc); 758 total_blocks += spdk_bdev_get_num_blocks(bdev); 759 760 /* Count space needed for validity map */ 761 md_blocks += ftl_md_region_blocks(dev, spdk_divide_round_up(total_blocks, 8)); 762 763 /* Count space needed for superblock */ 764 md_blocks += superblock_region_blocks(dev); 765 return md_blocks; 766 } 767 768 struct layout_blob_entry { 769 uint32_t type; 770 uint64_t entry_size; 771 uint64_t num_entries; 772 } __attribute__((packed)); 773 774 size_t 775 ftl_layout_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz) 776 { 777 struct layout_blob_entry *blob_entry = blob_buf; 778 struct ftl_layout_region *reg; 779 enum ftl_layout_region_type reg_type; 780 size_t blob_sz = 0; 781 782 for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) { 783 if (blob_sz + sizeof(*blob_entry) > blob_buf_sz) { 784 return 0; 785 } 786 787 reg = &dev->layout.region[reg_type]; 788 blob_entry->type = reg_type; 789 blob_entry->entry_size = reg->entry_size; 790 blob_entry->num_entries = reg->num_entries; 791 792 blob_entry++; 793 blob_sz += sizeof(*blob_entry); 794 } 795 796 return blob_sz; 797 } 798 799 int 800 ftl_layout_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz) 801 { 802 struct layout_blob_entry *blob_entry = blob_buf; 803 size_t blob_entry_num = blob_sz / sizeof(*blob_entry); 804 struct layout_blob_entry *blob_entry_end = blob_entry + blob_entry_num; 805 struct ftl_layout_region *reg; 806 807 if (blob_sz % sizeof(*blob_entry) != 0) { 808 /* Invalid blob size */ 809 return -1; 810 } 811 812 for (; blob_entry < blob_entry_end; blob_entry++) { 813 /* Verify the type */ 814 if (blob_entry->type >= FTL_LAYOUT_REGION_TYPE_MAX) { 815 return -1; 816 } 817 818 /* Load the entry */ 819 reg = &dev->layout.region[blob_entry->type]; 820 reg->entry_size = blob_entry->entry_size; 821 reg->num_entries = blob_entry->num_entries; 822 } 823 824 return 0; 825 } 826