1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2022 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/bdev.h" 7 8 #include "ftl_core.h" 9 #include "ftl_utils.h" 10 #include "ftl_band.h" 11 #include "ftl_layout.h" 12 #include "ftl_nv_cache.h" 13 #include "ftl_sb.h" 14 15 #define FTL_NV_CACHE_CHUNK_DATA_SIZE(blocks) ((uint64_t)blocks * FTL_BLOCK_SIZE) 16 #define FTL_NV_CACHE_CHUNK_SIZE(blocks) \ 17 (FTL_NV_CACHE_CHUNK_DATA_SIZE(blocks) + (2 * FTL_NV_CACHE_CHUNK_MD_SIZE)) 18 19 static inline float 20 blocks2mib(uint64_t blocks) 21 { 22 float result; 23 24 result = blocks; 25 result *= FTL_BLOCK_SIZE; 26 result /= 1024UL; 27 result /= 1024UL; 28 29 return result; 30 } 31 32 static uint64_t 33 superblock_region_size(struct spdk_ftl_dev *dev) 34 { 35 const struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 36 uint64_t wus = spdk_bdev_get_write_unit_size(bdev) * FTL_BLOCK_SIZE; 37 38 if (wus > FTL_SUPERBLOCK_SIZE) { 39 return wus; 40 } else { 41 return wus * spdk_divide_round_up(FTL_SUPERBLOCK_SIZE, wus); 42 } 43 } 44 45 static uint64_t 46 superblock_region_blocks(struct spdk_ftl_dev *dev) 47 { 48 return superblock_region_size(dev) / FTL_BLOCK_SIZE; 49 } 50 51 static inline uint64_t 52 blocks_region(struct spdk_ftl_dev *dev, uint64_t bytes) 53 { 54 const uint64_t alignment = superblock_region_size(dev); 55 uint64_t result; 56 57 result = spdk_divide_round_up(bytes, alignment); 58 result *= alignment; 59 result /= FTL_BLOCK_SIZE; 60 61 return result; 62 } 63 64 static void 65 dump_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *region) 66 { 67 assert(!(region->current.offset % superblock_region_blocks(dev))); 68 assert(!(region->current.blocks % superblock_region_blocks(dev))); 69 70 FTL_NOTICELOG(dev, "Region %s\n", region->name); 71 FTL_NOTICELOG(dev, " offset: %.2f MiB\n", 72 blocks2mib(region->current.offset)); 73 FTL_NOTICELOG(dev, " blocks: %.2f MiB\n", 74 blocks2mib(region->current.blocks)); 75 } 76 77 int 78 ftl_validate_regions(struct spdk_ftl_dev *dev, struct ftl_layout *layout) 79 { 80 uint64_t i, j; 81 82 /* Validate if regions doesn't overlap each other */ 83 /* TODO: major upgrades: keep track of and validate free_nvc/free_btm regions */ 84 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) { 85 struct ftl_layout_region *r1 = &layout->region[i]; 86 87 for (j = 0; j < FTL_LAYOUT_REGION_TYPE_MAX; j++) { 88 struct ftl_layout_region *r2 = &layout->region[j]; 89 90 if (r1->bdev_desc != r2->bdev_desc) { 91 continue; 92 } 93 94 if (i == j) { 95 continue; 96 } 97 98 uint64_t r1_begin = r1->current.offset; 99 uint64_t r1_end = r1->current.offset + r1->current.blocks - 1; 100 uint64_t r2_begin = r2->current.offset; 101 uint64_t r2_end = r2->current.offset + r2->current.blocks - 1; 102 103 if (spdk_max(r1_begin, r2_begin) <= spdk_min(r1_end, r2_end)) { 104 FTL_ERRLOG(dev, "Layout initialization ERROR, two regions overlap, " 105 "%s and %s\n", r1->name, r2->name); 106 return -1; 107 } 108 } 109 } 110 111 return 0; 112 } 113 114 static uint64_t 115 get_num_user_lbas(struct spdk_ftl_dev *dev) 116 { 117 uint64_t blocks; 118 119 blocks = dev->num_bands * ftl_get_num_blocks_in_band(dev); 120 blocks = (blocks * (100 - dev->conf.overprovisioning)) / 100; 121 122 return blocks; 123 } 124 125 static void 126 set_region_bdev_nvc(struct ftl_layout_region *reg, struct spdk_ftl_dev *dev) 127 { 128 reg->bdev_desc = dev->nv_cache.bdev_desc; 129 reg->ioch = dev->nv_cache.cache_ioch; 130 reg->vss_blksz = dev->nv_cache.md_size; 131 } 132 133 static void 134 set_region_bdev_btm(struct ftl_layout_region *reg, struct spdk_ftl_dev *dev) 135 { 136 reg->bdev_desc = dev->base_bdev_desc; 137 reg->ioch = dev->base_ioch; 138 reg->vss_blksz = 0; 139 } 140 141 static int 142 setup_layout_nvc(struct spdk_ftl_dev *dev) 143 { 144 int region_type; 145 uint64_t left, offset = 0, l2p_blocks; 146 struct ftl_layout *layout = &dev->layout; 147 struct ftl_layout_region *region, *mirror; 148 static const char *p2l_region_name[] = { 149 "p2l0", 150 "p2l1", 151 "p2l2", 152 "p2l3" 153 }; 154 155 #ifdef SPDK_FTL_VSS_EMU 156 /* Skip the already init`d VSS region */ 157 region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS]; 158 offset += region->current.blocks; 159 160 if (offset >= layout->nvc.total_blocks) { 161 goto error; 162 } 163 #endif 164 165 /* Skip the superblock region. Already init`d in ftl_layout_setup_superblock */ 166 region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB]; 167 offset += region->current.blocks; 168 169 /* Initialize L2P region */ 170 if (offset >= layout->nvc.total_blocks) { 171 goto error; 172 } 173 region = &layout->region[FTL_LAYOUT_REGION_TYPE_L2P]; 174 region->type = FTL_LAYOUT_REGION_TYPE_L2P; 175 region->name = "l2p"; 176 region->current.version = 0; 177 region->prev.version = 0; 178 region->current.offset = offset; 179 region->current.blocks = blocks_region(dev, layout->l2p.addr_size * dev->num_lbas); 180 set_region_bdev_nvc(region, dev); 181 offset += region->current.blocks; 182 183 /* Initialize band info metadata */ 184 if (offset >= layout->nvc.total_blocks) { 185 goto error; 186 } 187 region = &layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD]; 188 region->type = FTL_LAYOUT_REGION_TYPE_BAND_MD; 189 region->mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR; 190 region->name = "band_md"; 191 region->current.version = region->prev.version = FTL_BAND_VERSION_CURRENT; 192 region->current.offset = offset; 193 region->current.blocks = blocks_region(dev, ftl_get_num_bands(dev) * sizeof(struct ftl_band_md)); 194 region->entry_size = sizeof(struct ftl_band_md) / FTL_BLOCK_SIZE; 195 region->num_entries = ftl_get_num_bands(dev); 196 set_region_bdev_nvc(region, dev); 197 offset += region->current.blocks; 198 199 /* Initialize band info metadata mirror */ 200 if (offset >= layout->nvc.total_blocks) { 201 goto error; 202 } 203 mirror = &layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR]; 204 *mirror = *region; 205 mirror->type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR; 206 mirror->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 207 mirror->name = "band_md_mirror"; 208 mirror->current.offset += region->current.blocks; 209 offset += mirror->current.blocks; 210 211 if (offset >= layout->nvc.total_blocks) { 212 goto error; 213 } 214 215 /* 216 * Initialize P2L checkpointing regions 217 */ 218 SPDK_STATIC_ASSERT(SPDK_COUNTOF(p2l_region_name) == FTL_LAYOUT_REGION_TYPE_P2L_COUNT, 219 "Incorrect # of P2L region names"); 220 for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN; 221 region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX; 222 region_type++) { 223 if (offset >= layout->nvc.total_blocks) { 224 goto error; 225 } 226 region = &layout->region[region_type]; 227 region->type = region_type; 228 region->name = p2l_region_name[region_type - FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN]; 229 region->current.version = FTL_P2L_VERSION_CURRENT; 230 region->prev.version = FTL_P2L_VERSION_CURRENT; 231 region->current.offset = offset; 232 region->current.blocks = blocks_region(dev, layout->p2l.ckpt_pages * FTL_BLOCK_SIZE); 233 region->entry_size = 1; 234 region->num_entries = region->current.blocks; 235 set_region_bdev_nvc(region, dev); 236 offset += region->current.blocks; 237 } 238 239 /* 240 * Initialize trim metadata region 241 */ 242 if (offset >= layout->nvc.total_blocks) { 243 goto error; 244 } 245 l2p_blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks; 246 region = &layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD]; 247 region->type = FTL_LAYOUT_REGION_TYPE_TRIM_MD; 248 region->mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR; 249 region->name = "trim_md"; 250 region->current.version = 0; 251 region->prev.version = 0; 252 region->current.offset = offset; 253 region->current.blocks = blocks_region(dev, l2p_blocks * sizeof(uint64_t)); 254 region->entry_size = 1; 255 region->num_entries = region->current.blocks; 256 set_region_bdev_nvc(region, dev); 257 offset += region->current.blocks; 258 259 /* Initialize trim metadata mirror region */ 260 if (offset >= layout->nvc.total_blocks) { 261 goto error; 262 } 263 mirror = &layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR]; 264 *mirror = *region; 265 mirror->type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR; 266 mirror->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 267 mirror->name = "trim_md_mirror"; 268 mirror->current.offset += region->current.blocks; 269 offset += mirror->current.blocks; 270 271 /* 272 * Initialize NV Cache metadata 273 */ 274 if (offset >= layout->nvc.total_blocks) { 275 goto error; 276 } 277 278 left = layout->nvc.total_blocks - offset; 279 layout->nvc.chunk_data_blocks = 280 FTL_NV_CACHE_CHUNK_DATA_SIZE(ftl_get_num_blocks_in_band(dev)) / FTL_BLOCK_SIZE; 281 layout->nvc.chunk_meta_size = FTL_NV_CACHE_CHUNK_MD_SIZE; 282 layout->nvc.chunk_count = (left * FTL_BLOCK_SIZE) / 283 FTL_NV_CACHE_CHUNK_SIZE(ftl_get_num_blocks_in_band(dev)); 284 layout->nvc.chunk_tail_md_num_blocks = ftl_nv_cache_chunk_tail_md_num_blocks(&dev->nv_cache); 285 286 if (0 == layout->nvc.chunk_count) { 287 goto error; 288 } 289 region = &layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD]; 290 region->type = FTL_LAYOUT_REGION_TYPE_NVC_MD; 291 region->mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR; 292 region->name = "nvc_md"; 293 region->current.version = region->prev.version = FTL_NVC_VERSION_CURRENT; 294 region->current.offset = offset; 295 region->current.blocks = blocks_region(dev, layout->nvc.chunk_count * 296 sizeof(struct ftl_nv_cache_chunk_md)); 297 region->entry_size = sizeof(struct ftl_nv_cache_chunk_md) / FTL_BLOCK_SIZE; 298 region->num_entries = layout->nvc.chunk_count; 299 set_region_bdev_nvc(region, dev); 300 offset += region->current.blocks; 301 302 /* 303 * Initialize NV Cache metadata mirror 304 */ 305 mirror = &layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR]; 306 *mirror = *region; 307 mirror->type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR; 308 mirror->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 309 mirror->name = "nvc_md_mirror"; 310 mirror->current.offset += region->current.blocks; 311 offset += mirror->current.blocks; 312 313 /* 314 * Initialize data region on NV cache 315 */ 316 if (offset >= layout->nvc.total_blocks) { 317 goto error; 318 } 319 region = &layout->region[FTL_LAYOUT_REGION_TYPE_DATA_NVC]; 320 region->type = FTL_LAYOUT_REGION_TYPE_DATA_NVC; 321 region->name = "data_nvc"; 322 region->current.version = region->prev.version = 0; 323 region->current.offset = offset; 324 region->current.blocks = layout->nvc.chunk_count * layout->nvc.chunk_data_blocks; 325 set_region_bdev_nvc(region, dev); 326 offset += region->current.blocks; 327 328 left = layout->nvc.total_blocks - offset; 329 if (left > layout->nvc.chunk_data_blocks) { 330 FTL_ERRLOG(dev, "Error when setup NV cache layout\n"); 331 return -1; 332 } 333 334 if (offset > layout->nvc.total_blocks) { 335 FTL_ERRLOG(dev, "Error when setup NV cache layout\n"); 336 goto error; 337 } 338 339 return 0; 340 341 error: 342 FTL_ERRLOG(dev, "Insufficient NV Cache capacity to preserve metadata\n"); 343 return -1; 344 } 345 346 static ftl_addr 347 layout_base_offset(struct spdk_ftl_dev *dev) 348 { 349 ftl_addr addr; 350 351 addr = dev->num_bands * ftl_get_num_blocks_in_band(dev); 352 return addr; 353 } 354 355 static int 356 setup_layout_base(struct spdk_ftl_dev *dev) 357 { 358 uint64_t left, offset; 359 struct ftl_layout *layout = &dev->layout; 360 struct ftl_layout_region *region; 361 uint64_t data_base_alignment = 8 * ftl_bitmap_buffer_alignment; 362 /* Allocating a ftl_bitmap requires a 8B input buffer alignment, since we're reusing the global valid map md buffer 363 * this means that each band starting address needs to be aligned too - each device sector takes 1b in the valid map, 364 * so 64 sectors (8*8) is the needed alignment 365 */ 366 367 layout->base.num_usable_blocks = ftl_get_num_blocks_in_band(dev); 368 layout->base.user_blocks = ftl_band_user_blocks(dev->bands); 369 370 /* Base device layout is following: 371 * - superblock 372 * - data 373 * - valid map 374 */ 375 offset = layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.blocks; 376 offset = SPDK_ALIGN_CEIL(offset, data_base_alignment); 377 378 /* Setup data region on base device */ 379 region = &layout->region[FTL_LAYOUT_REGION_TYPE_DATA_BASE]; 380 region->type = FTL_LAYOUT_REGION_TYPE_DATA_BASE; 381 region->name = "data_btm"; 382 region->current.version = region->prev.version = 0; 383 region->current.offset = offset; 384 region->current.blocks = layout_base_offset(dev); 385 set_region_bdev_btm(region, dev); 386 387 offset += region->current.blocks; 388 389 /* Setup validity map */ 390 region = &layout->region[FTL_LAYOUT_REGION_TYPE_VALID_MAP]; 391 region->type = FTL_LAYOUT_REGION_TYPE_VALID_MAP; 392 region->name = "vmap"; 393 region->current.version = region->prev.version = 0; 394 region->current.offset = offset; 395 region->current.blocks = blocks_region(dev, spdk_divide_round_up( 396 layout->base.total_blocks + layout->nvc.total_blocks, 8)); 397 set_region_bdev_btm(region, dev); 398 offset += region->current.blocks; 399 400 /* Checking for underflow */ 401 left = layout->base.total_blocks - offset; 402 if (left > layout->base.total_blocks) { 403 FTL_ERRLOG(dev, "Error when setup base device layout\n"); 404 return -1; 405 } 406 407 if (offset > layout->base.total_blocks) { 408 FTL_ERRLOG(dev, "Error when setup base device layout\n"); 409 return -1; 410 } 411 412 return 0; 413 } 414 415 int 416 ftl_layout_setup(struct spdk_ftl_dev *dev) 417 { 418 const struct spdk_bdev *bdev; 419 struct ftl_layout *layout = &dev->layout; 420 uint64_t i; 421 uint64_t num_lbas; 422 423 bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 424 layout->base.total_blocks = spdk_bdev_get_num_blocks(bdev); 425 426 bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc); 427 layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev); 428 429 /* Initialize mirrors types */ 430 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 431 if (i == FTL_LAYOUT_REGION_TYPE_SB) { 432 /* Super block has been already initialized */ 433 continue; 434 } 435 436 layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 437 } 438 439 /* 440 * Initialize L2P information 441 */ 442 num_lbas = get_num_user_lbas(dev); 443 if (dev->num_lbas == 0) { 444 assert(dev->conf.mode & SPDK_FTL_MODE_CREATE); 445 dev->num_lbas = num_lbas; 446 dev->sb->lba_cnt = num_lbas; 447 } else if (dev->num_lbas != num_lbas) { 448 FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n"); 449 return -EINVAL; 450 } 451 layout->l2p.addr_length = spdk_u64log2(layout->base.total_blocks + layout->nvc.total_blocks) + 1; 452 layout->l2p.addr_size = layout->l2p.addr_length > 32 ? 8 : 4; 453 layout->l2p.lbas_in_page = FTL_BLOCK_SIZE / layout->l2p.addr_size; 454 455 /* Setup P2L ckpt */ 456 layout->p2l.ckpt_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev), dev->xfer_size); 457 458 if (setup_layout_nvc(dev)) { 459 return -EINVAL; 460 } 461 462 if (setup_layout_base(dev)) { 463 return -EINVAL; 464 } 465 466 if (ftl_validate_regions(dev, layout)) { 467 return -EINVAL; 468 } 469 470 FTL_NOTICELOG(dev, "Base device capacity: %.2f MiB\n", 471 blocks2mib(layout->base.total_blocks)); 472 FTL_NOTICELOG(dev, "NV cache device capacity: %.2f MiB\n", 473 blocks2mib(layout->nvc.total_blocks)); 474 FTL_NOTICELOG(dev, "L2P entries: %"PRIu64"\n", dev->num_lbas); 475 FTL_NOTICELOG(dev, "L2P address size: %"PRIu64"\n", layout->l2p.addr_size); 476 FTL_NOTICELOG(dev, "P2L checkpoint pages: %"PRIu64"\n", layout->p2l.ckpt_pages); 477 478 return 0; 479 } 480 481 #ifdef SPDK_FTL_VSS_EMU 482 void 483 ftl_layout_setup_vss_emu(struct spdk_ftl_dev *dev) 484 { 485 const struct spdk_bdev *bdev; 486 struct ftl_layout *layout = &dev->layout; 487 struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS]; 488 489 assert(layout->md[FTL_LAYOUT_REGION_TYPE_VSS] == NULL); 490 491 region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS]; 492 region->type = FTL_LAYOUT_REGION_TYPE_VSS; 493 region->name = "vss"; 494 region->current.version = region->prev.version = 0; 495 region->current.offset = 0; 496 497 bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc); 498 layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev); 499 region->current.blocks = blocks_region(dev, dev->nv_cache.md_size * layout->nvc.total_blocks); 500 501 region->vss_blksz = 0; 502 region->bdev_desc = dev->nv_cache.bdev_desc; 503 region->ioch = dev->nv_cache.cache_ioch; 504 505 assert(region->bdev_desc != NULL); 506 assert(region->ioch != NULL); 507 } 508 #endif 509 510 int 511 ftl_layout_setup_superblock(struct spdk_ftl_dev *dev) 512 { 513 struct ftl_layout *layout = &dev->layout; 514 struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB]; 515 uint64_t total_blocks, offset, left; 516 517 assert(layout->md[FTL_LAYOUT_REGION_TYPE_SB] == NULL); 518 519 /* Initialize superblock region */ 520 region->type = FTL_LAYOUT_REGION_TYPE_SB; 521 region->mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE; 522 region->name = "sb"; 523 region->current.version = FTL_SB_VERSION_CURRENT; 524 region->prev.version = FTL_SB_VERSION_CURRENT; 525 region->current.offset = 0; 526 527 /* 528 * VSS region must go first in case SB to make calculating its relative size easier 529 */ 530 #ifdef SPDK_FTL_VSS_EMU 531 region->current.offset = layout->region[FTL_LAYOUT_REGION_TYPE_VSS].current.offset + 532 layout->region[FTL_LAYOUT_REGION_TYPE_VSS].current.blocks; 533 #endif 534 535 region->current.blocks = superblock_region_blocks(dev); 536 region->vss_blksz = 0; 537 region->bdev_desc = dev->nv_cache.bdev_desc; 538 region->ioch = dev->nv_cache.cache_ioch; 539 540 assert(region->bdev_desc != NULL); 541 assert(region->ioch != NULL); 542 543 region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE]; 544 region->type = FTL_LAYOUT_REGION_TYPE_SB_BASE; 545 region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 546 region->name = "sb_mirror"; 547 region->current.version = FTL_SB_VERSION_CURRENT; 548 region->prev.version = FTL_SB_VERSION_CURRENT; 549 region->current.offset = 0; 550 region->current.blocks = superblock_region_blocks(dev); 551 set_region_bdev_btm(region, dev); 552 553 /* Check if SB can be stored at the end of base device */ 554 total_blocks = spdk_bdev_get_num_blocks( 555 spdk_bdev_desc_get_bdev(dev->base_bdev_desc)); 556 offset = region->current.offset + region->current.blocks; 557 left = total_blocks - offset; 558 if ((left > total_blocks) || (offset > total_blocks)) { 559 FTL_ERRLOG(dev, "Error when setup base device super block\n"); 560 return -1; 561 } 562 563 return 0; 564 } 565 566 void 567 ftl_layout_dump(struct spdk_ftl_dev *dev) 568 { 569 struct ftl_layout *layout = &dev->layout; 570 int i; 571 572 FTL_NOTICELOG(dev, "NV cache layout:\n"); 573 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 574 if (layout->region[i].bdev_desc == dev->nv_cache.bdev_desc) { 575 dump_region(dev, &layout->region[i]); 576 } 577 } 578 FTL_NOTICELOG(dev, "Base device layout:\n"); 579 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 580 if (layout->region[i].bdev_desc == dev->base_bdev_desc) { 581 dump_region(dev, &layout->region[i]); 582 } 583 } 584 } 585 586 uint64_t 587 ftl_layout_base_md_blocks(struct spdk_ftl_dev *dev) 588 { 589 const struct spdk_bdev *bdev; 590 uint64_t md_blocks = 0, total_blocks = 0; 591 592 bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 593 total_blocks += spdk_bdev_get_num_blocks(bdev); 594 595 bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc); 596 total_blocks += spdk_bdev_get_num_blocks(bdev); 597 598 /* Count space needed for validity map */ 599 md_blocks += blocks_region(dev, spdk_divide_round_up(total_blocks, 8)); 600 601 /* Count space needed for superblock */ 602 md_blocks += superblock_region_blocks(dev); 603 return md_blocks; 604 } 605