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