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