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