1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2023 Solidigm All Rights Reserved 3 * All rights reserved. 4 */ 5 6 #include "spdk/string.h" 7 8 #include "ftl_sb_v5.h" 9 #include "ftl_core.h" 10 #include "ftl_layout.h" 11 #include "ftl_band.h" 12 #include "upgrade/ftl_sb_prev.h" 13 #include "upgrade/ftl_sb_upgrade.h" 14 #include "upgrade/ftl_layout_upgrade.h" 15 #include "utils/ftl_layout_tracker_bdev.h" 16 17 typedef size_t (*blob_store_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz); 18 typedef int (*blob_load_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz); 19 20 bool 21 ftl_superblock_v5_is_blob_area_empty(union ftl_superblock_ver *sb_ver) 22 { 23 return sb_ver->v5.blob_area_end == 0; 24 } 25 26 static bool 27 validate_blob_area(struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr, 28 ftl_df_obj_id sb_blob_area_end) 29 { 30 return sb_blob_hdr->df_id <= sb_blob_area_end && 31 (sb_blob_hdr->df_id + sb_blob_hdr->blob_sz) <= sb_blob_area_end; 32 } 33 34 bool 35 ftl_superblock_v5_validate_blob_area(struct spdk_ftl_dev *dev) 36 { 37 union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)dev->sb; 38 39 return validate_blob_area(&sb_ver->v5.md_layout_nvc, sb_ver->v5.blob_area_end) && 40 validate_blob_area(&sb_ver->v5.md_layout_base, sb_ver->v5.blob_area_end) && 41 validate_blob_area(&sb_ver->v5.layout_params, sb_ver->v5.blob_area_end); 42 } 43 44 static size_t 45 sb_blob_store(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr, 46 blob_store_fn blob_store, void *sb_blob_area) 47 { 48 struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 49 uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE; 50 size_t blob_sz = sb_end - (uintptr_t)sb_blob_area; 51 52 /* Test SB blob area overflow */ 53 if ((uintptr_t)sb_blob_area < (uintptr_t)sb->blob_area) { 54 ftl_bug(true); 55 return 0; 56 } 57 if ((uintptr_t)sb_blob_area >= sb_end) { 58 ftl_bug(true); 59 return 0; 60 } 61 62 blob_sz = blob_store(dev, sb_blob_area, blob_sz); 63 sb_blob_hdr->blob_sz = blob_sz; 64 sb_blob_hdr->df_id = ftl_df_get_obj_id(sb->blob_area, sb_blob_area); 65 return blob_sz; 66 } 67 68 static size_t 69 base_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz) 70 { 71 return ftl_layout_tracker_bdev_blob_store(dev->base_layout_tracker, blob_buf, blob_buf_sz); 72 } 73 74 static size_t 75 nvc_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz) 76 { 77 return ftl_layout_tracker_bdev_blob_store(dev->nvc_layout_tracker, blob_buf, blob_buf_sz); 78 } 79 80 int 81 ftl_superblock_v5_store_blob_area(struct spdk_ftl_dev *dev) 82 { 83 struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 84 void *sb_blob_area; 85 size_t blob_sz; 86 87 /* Store the NVC-backed FTL MD layout info */ 88 sb_blob_area = ftl_df_get_obj_ptr(sb->blob_area, 0); 89 spdk_strcpy_pad(sb->nvc_dev_name, dev->nv_cache.nvc_type->name, 90 SPDK_COUNTOF(sb->nvc_dev_name), '\0'); 91 blob_sz = sb_blob_store(dev, &sb->md_layout_nvc, nvc_blob_store, sb_blob_area); 92 FTL_NOTICELOG(dev, "nvc layout blob store 0x%"PRIx64" bytes\n", blob_sz); 93 if (!blob_sz) { 94 return -1; 95 } 96 97 /* Store the base dev-backed FTL MD layout info */ 98 sb_blob_area += blob_sz; 99 spdk_strcpy_pad(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name), '\0'); 100 blob_sz = sb_blob_store(dev, &sb->md_layout_base, base_blob_store, sb_blob_area); 101 FTL_NOTICELOG(dev, "base layout blob store 0x%"PRIx64" bytes\n", blob_sz); 102 if (!blob_sz) { 103 return -1; 104 } 105 106 /* Store the region props */ 107 sb_blob_area += blob_sz; 108 blob_sz = sb_blob_store(dev, &sb->layout_params, ftl_layout_blob_store, sb_blob_area); 109 FTL_NOTICELOG(dev, "layout blob store 0x%"PRIx64" bytes\n", blob_sz); 110 if (!blob_sz) { 111 return -1; 112 } 113 114 /* Update the blob area end */ 115 sb_blob_area += blob_sz; 116 sb->blob_area_end = ftl_df_get_obj_id(sb->blob_area, sb_blob_area); 117 118 return 0; 119 } 120 121 static const struct ftl_layout_tracker_bdev_region_props * 122 sb_md_layout_find_oldest_region(struct spdk_ftl_dev *dev, 123 struct ftl_layout_tracker_bdev *layout_tracker, 124 enum ftl_layout_region_type reg_type, void *find_filter) 125 { 126 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 127 const struct ftl_layout_tracker_bdev_region_props *reg_oldest = NULL; 128 uint32_t ver_oldest; 129 130 while (true) { 131 ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 132 if (!reg_search_ctx) { 133 break; 134 } 135 136 if (!reg_oldest) { 137 reg_oldest = reg_search_ctx; 138 ver_oldest = reg_search_ctx->ver; 139 continue; 140 } 141 142 ftl_bug(ver_oldest == reg_search_ctx->ver); 143 if (ver_oldest > reg_search_ctx->ver) { 144 reg_oldest = reg_search_ctx; 145 ver_oldest = reg_search_ctx->ver; 146 } 147 } 148 149 return reg_oldest; 150 } 151 152 static const struct ftl_layout_tracker_bdev_region_props * 153 sb_md_layout_find_latest_region(struct spdk_ftl_dev *dev, 154 struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type, 155 void *find_filter) 156 { 157 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 158 const struct ftl_layout_tracker_bdev_region_props *reg_latest = NULL; 159 uint32_t ver_latest; 160 161 while (true) { 162 ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 163 if (!reg_search_ctx) { 164 break; 165 } 166 167 if (!reg_latest) { 168 reg_latest = reg_search_ctx; 169 ver_latest = reg_search_ctx->ver; 170 continue; 171 } 172 173 ftl_bug(ver_latest == reg_search_ctx->ver); 174 if (ver_latest < reg_search_ctx->ver) { 175 reg_latest = reg_search_ctx; 176 ver_latest = reg_search_ctx->ver; 177 } 178 } 179 180 return reg_latest; 181 } 182 183 static const struct ftl_layout_tracker_bdev_region_props * 184 sb_md_layout_find_region_version(struct spdk_ftl_dev *dev, 185 struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type, 186 void *find_filter) 187 { 188 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 189 uint32_t *reg_ver = find_filter; 190 191 assert(reg_ver); 192 193 while (true) { 194 ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 195 if (!reg_search_ctx) { 196 break; 197 } 198 199 if (reg_search_ctx->ver == *reg_ver) { 200 break; 201 } 202 } 203 204 return reg_search_ctx; 205 } 206 207 typedef const struct ftl_layout_tracker_bdev_region_props *(*sb_md_layout_find_fn)( 208 struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker, 209 enum ftl_layout_region_type reg_type, void *find_filter); 210 211 static const struct ftl_layout_tracker_bdev_region_props * 212 sb_md_layout_find_region(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 213 sb_md_layout_find_fn find_fn, void *find_filter) 214 { 215 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx; 216 struct ftl_layout_tracker_bdev *nvc_layout_tracker = dev->nvc_layout_tracker; 217 struct ftl_layout_tracker_bdev *base_layout_tracker = dev->base_layout_tracker; 218 219 reg_search_ctx = find_fn(dev, nvc_layout_tracker, reg_type, find_filter); 220 if (reg_search_ctx) { 221 assert(find_fn(dev, base_layout_tracker, reg_type, find_filter) == NULL); 222 return reg_search_ctx; 223 } 224 225 reg_search_ctx = find_fn(dev, base_layout_tracker, reg_type, find_filter); 226 return reg_search_ctx; 227 } 228 229 static int 230 sb_blob_load(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr, 231 blob_load_fn blob_load) 232 { 233 struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 234 uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE; 235 void *blob_area; 236 237 if (sb_blob_hdr->df_id == FTL_DF_OBJ_ID_INVALID) { 238 /* Uninitialized blob */ 239 return -1; 240 } 241 242 blob_area = ftl_df_get_obj_ptr(sb->blob_area, sb_blob_hdr->df_id); 243 244 /* Test SB blob area overflow */ 245 if ((uintptr_t)blob_area < (uintptr_t)sb->blob_area) { 246 ftl_bug(true); 247 return -1; 248 } 249 if ((uintptr_t)blob_area + sb_blob_hdr->blob_sz >= sb_end) { 250 ftl_bug(true); 251 return -1; 252 } 253 254 return blob_load(dev, blob_area, sb_blob_hdr->blob_sz); 255 } 256 257 static int 258 base_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz) 259 { 260 return ftl_layout_tracker_bdev_blob_load(dev->base_layout_tracker, blob_buf, blob_sz); 261 } 262 263 static int 264 nvc_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz) 265 { 266 return ftl_layout_tracker_bdev_blob_load(dev->nvc_layout_tracker, blob_buf, blob_sz); 267 } 268 269 int 270 ftl_superblock_v5_load_blob_area(struct spdk_ftl_dev *dev) 271 { 272 struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 273 274 /* Load the NVC-backed FTL MD layout info */ 275 if (strncmp(sb->nvc_dev_name, dev->nv_cache.nvc_type->name, SPDK_COUNTOF(sb->nvc_dev_name))) { 276 return -1; 277 } 278 FTL_NOTICELOG(dev, "nvc layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->md_layout_nvc.blob_sz); 279 if (sb_blob_load(dev, &sb->md_layout_nvc, nvc_blob_load)) { 280 return -1; 281 } 282 283 /* Load the base dev-backed FTL MD layout info */ 284 if (strncmp(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name))) { 285 return -1; 286 } 287 FTL_NOTICELOG(dev, "base layout blob load 0x%"PRIx64" bytes\n", 288 (uint64_t)sb->md_layout_base.blob_sz); 289 if (sb_blob_load(dev, &sb->md_layout_base, base_blob_load)) { 290 return -1; 291 } 292 293 /* Load the region props */ 294 FTL_NOTICELOG(dev, "layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->layout_params.blob_sz); 295 if (sb_blob_load(dev, &sb->layout_params, ftl_layout_blob_load)) { 296 return -1; 297 } 298 299 return 0; 300 } 301 302 static struct ftl_layout_tracker_bdev * 303 sb_get_md_layout_tracker(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg) 304 { 305 return (reg->bdev_desc == dev->base_bdev_desc) ? dev->base_layout_tracker : dev->nvc_layout_tracker; 306 } 307 308 static void 309 sb_md_layout_delete_prev_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg) 310 { 311 int rc; 312 struct ftl_layout_tracker_bdev *layout_tracker = sb_get_md_layout_tracker(dev, reg); 313 314 rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg->type, reg->current.version); 315 /* Version 0 indicates a placeholder for creation of a new region */ 316 ftl_bug(reg->current.version != 0 && rc != 0); 317 } 318 319 static void 320 sb_md_layout_update_prev_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg, 321 uint32_t new_version) 322 { 323 int rc; 324 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 325 struct ftl_layout_tracker_bdev *layout_tracker = sb_get_md_layout_tracker(dev, reg); 326 struct ftl_layout_tracker_bdev_region_props reg_props; 327 328 /* Get region properties */ 329 ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg->type, ®_search_ctx); 330 ftl_bug(reg_search_ctx == NULL); 331 reg_props = *reg_search_ctx; 332 333 /* Delete the region */ 334 rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg_props.type, reg_props.ver); 335 ftl_bug(rc != 0); 336 337 /* Insert the same region with new version */ 338 reg_search_ctx = ftl_layout_tracker_bdev_insert_region(layout_tracker, reg_props.type, new_version, 339 reg_props.blk_offs, reg_props.blk_sz); 340 ftl_bug(reg_search_ctx == NULL); 341 342 /* Verify the oldest region version stored in the SB is the new_version */ 343 reg_search_ctx = sb_md_layout_find_region(dev, reg_props.type, sb_md_layout_find_oldest_region, 344 NULL); 345 ftl_bug(reg_search_ctx == NULL); 346 ftl_bug(reg_search_ctx->ver != new_version); 347 } 348 349 int 350 ftl_superblock_v5_md_layout_upgrade_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg, 351 uint32_t new_version) 352 { 353 const struct ftl_layout_tracker_bdev_region_props *reg_next = NULL; 354 uint64_t latest_ver; 355 356 ftl_bug(reg->current.version >= new_version); 357 358 reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_region_version, &new_version); 359 if (reg_next) { 360 /** 361 * Major upgrade. 362 * Found a new MD region allocated for upgrade to the next version. 363 * Destroy the previous version now that the upgrade is completed. 364 */ 365 ftl_bug(reg_next->ver != new_version); 366 ftl_bug(reg_next->type != reg->type); 367 sb_md_layout_delete_prev_region(dev, reg); 368 reg->current.offset = reg_next->blk_offs; 369 reg->current.blocks = reg_next->blk_sz; 370 } else { 371 /** 372 * Minor upgrade. 373 * Upgraded the MD region in place. 374 * Update the version in place. 375 */ 376 sb_md_layout_update_prev_region(dev, reg, new_version); 377 } 378 379 reg->current.version = new_version; 380 latest_ver = ftl_layout_upgrade_region_get_latest_version(reg->type); 381 if (new_version == latest_ver) { 382 /* Audit the only region version stored in the SB */ 383 reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_latest_region, NULL); 384 ftl_bug(reg_next == NULL); 385 ftl_bug(reg_next->ver != new_version); 386 387 reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_oldest_region, NULL); 388 ftl_bug(reg_next == NULL); 389 ftl_bug(reg_next->ver != new_version); 390 391 reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_region_version, &new_version); 392 ftl_bug(reg->type != reg_next->type); 393 ftl_bug(reg->current.version != reg_next->ver); 394 ftl_bug(reg->current.offset != reg_next->blk_offs); 395 ftl_bug(reg->current.blocks != reg_next->blk_sz); 396 } 397 398 return 0; 399 } 400 401 void 402 ftl_superblock_v5_md_layout_dump(struct spdk_ftl_dev *dev) 403 { 404 struct ftl_layout_tracker_bdev *nvc_layout_tracker = dev->nvc_layout_tracker; 405 struct ftl_layout_tracker_bdev *base_layout_tracker = dev->base_layout_tracker; 406 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 407 408 FTL_NOTICELOG(dev, "SB metadata layout - nvc:\n"); 409 while (true) { 410 ftl_layout_tracker_bdev_find_next_region(nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID, 411 ®_search_ctx); 412 if (!reg_search_ctx) { 413 break; 414 } 415 416 FTL_NOTICELOG(dev, 417 "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n", 418 reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz); 419 } 420 421 reg_search_ctx = NULL; 422 FTL_NOTICELOG(dev, "SB metadata layout - base dev:\n"); 423 while (true) { 424 ftl_layout_tracker_bdev_find_next_region(base_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID, 425 ®_search_ctx); 426 if (!reg_search_ctx) { 427 break; 428 } 429 430 FTL_NOTICELOG(dev, 431 "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n", 432 reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz); 433 } 434 } 435 436 static int 437 layout_apply_from_sb_blob(struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker, 438 int (*filter_region_type_fn)(enum ftl_layout_region_type)) 439 { 440 struct ftl_layout_region *reg; 441 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 442 443 while (true) { 444 ftl_layout_tracker_bdev_find_next_region(layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID, 445 ®_search_ctx); 446 if (!reg_search_ctx) { 447 break; 448 } 449 if (reg_search_ctx->type == FTL_LAYOUT_REGION_TYPE_FREE) { 450 continue; 451 } 452 if (filter_region_type_fn(reg_search_ctx->type)) { 453 FTL_ERRLOG(dev, "Unknown region found in layout blob: type 0x%"PRIx32"\n", reg_search_ctx->type); 454 return -1; 455 } 456 457 reg = &dev->layout.region[reg_search_ctx->type]; 458 459 /* First region of a given type found */ 460 if (reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) { 461 reg->type = reg_search_ctx->type; 462 reg->current.version = reg_search_ctx->ver; 463 reg->current.offset = reg_search_ctx->blk_offs; 464 reg->current.blocks = reg_search_ctx->blk_sz; 465 continue; 466 } 467 468 /* Update to the oldest region version found */ 469 if (reg_search_ctx->ver < reg->current.version) { 470 reg->current.version = reg_search_ctx->ver; 471 reg->current.offset = reg_search_ctx->blk_offs; 472 reg->current.blocks = reg_search_ctx->blk_sz; 473 continue; 474 } 475 476 /* Skip newer region versions */ 477 if (reg_search_ctx->ver > reg->current.version) { 478 continue; 479 } 480 481 /* Current region version already found */ 482 assert(reg_search_ctx->ver == reg->current.version); 483 if (reg->current.offset != reg_search_ctx->blk_offs || 484 reg->current.blocks != reg_search_ctx->blk_sz) { 485 FTL_ERRLOG(dev, "Corrupted layout blob: reg type 0x%"PRIx32"\n", reg_search_ctx->type); 486 return -1; 487 } 488 } 489 return 0; 490 } 491 492 static int 493 layout_region_verify(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type) 494 { 495 struct ftl_layout_region *reg = ftl_layout_region_get(dev, reg_type); 496 if (!reg) { 497 return -ENOENT; 498 } 499 500 /* Unknown version found in the blob */ 501 if (reg->current.version > ftl_layout_upgrade_get_latest_version(reg_type)) { 502 FTL_ERRLOG(dev, "Unknown region version found in layout blob: reg type 0x%"PRIx32"\n", 503 reg_type); 504 return -EINVAL; 505 } 506 507 return 0; 508 } 509 510 static int 511 layout_fixup_reg_data_base(struct spdk_ftl_dev *dev) 512 { 513 const struct ftl_md_layout_ops *base_md_ops = &dev->base_type->ops.md_layout_ops; 514 struct ftl_layout_region *reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_DATA_BASE]; 515 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 516 517 assert(reg->type == FTL_LAYOUT_REGION_TYPE_INVALID); 518 519 FTL_NOTICELOG(dev, "Adding a region\n"); 520 521 /* Add the region */ 522 if (base_md_ops->region_create(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, 523 ftl_layout_base_offset(dev))) { 524 return -1; 525 } 526 if (base_md_ops->region_open(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE, 527 ftl_layout_base_offset(dev), reg)) { 528 return -1; 529 } 530 531 ftl_layout_tracker_bdev_find_next_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 532 ®_search_ctx); 533 assert(reg_search_ctx); 534 return 0; 535 } 536 537 static int 538 layout_fixup_base(struct spdk_ftl_dev *dev) 539 { 540 struct ftl_layout_region_descr { 541 enum ftl_layout_region_type type; 542 uint32_t ver; 543 int (*on_reg_miss)(struct spdk_ftl_dev *dev); 544 }; 545 struct ftl_layout_region_descr *reg_descr; 546 static struct ftl_layout_region_descr nvc_regs[] = { 547 { .type = FTL_LAYOUT_REGION_TYPE_SB_BASE, .ver = FTL_SB_VERSION_CURRENT }, 548 { .type = FTL_LAYOUT_REGION_TYPE_DATA_BASE, .ver = 0, .on_reg_miss = layout_fixup_reg_data_base }, 549 { .type = FTL_LAYOUT_REGION_TYPE_VALID_MAP, .ver = 0 }, 550 { .type = FTL_LAYOUT_REGION_TYPE_INVALID, .ver = 0 }, 551 }; 552 553 for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) { 554 struct ftl_layout_region *region; 555 556 if (layout_region_verify(dev, reg_descr->type) && 557 reg_descr->on_reg_miss && reg_descr->on_reg_miss(dev)) { 558 return -1; 559 } 560 561 region = &dev->layout.region[reg_descr->type]; 562 region->type = reg_descr->type; 563 region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 564 region->name = ftl_md_region_name(reg_descr->type); 565 566 region->bdev_desc = dev->base_bdev_desc; 567 region->ioch = dev->base_ioch; 568 region->vss_blksz = 0; 569 } 570 571 return 0; 572 } 573 574 static int 575 layout_fixup_nvc(struct spdk_ftl_dev *dev) 576 { 577 int rc; 578 struct ftl_layout_region_descr { 579 enum ftl_layout_region_type type; 580 bool deprecated; 581 enum ftl_layout_region_type mirror_type; 582 }; 583 struct ftl_layout_region_descr *reg_descr; 584 static struct ftl_layout_region_descr nvc_regs[] = { 585 { .type = FTL_LAYOUT_REGION_TYPE_SB, .mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE }, 586 { .type = FTL_LAYOUT_REGION_TYPE_L2P }, 587 { .type = FTL_LAYOUT_REGION_TYPE_BAND_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR }, 588 { .type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR }, 589 { .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR }, 590 { .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR }, 591 { .type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG, .mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR }, 592 { .type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR }, 593 { .type = FTL_LAYOUT_REGION_TYPE_NVC_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR }, 594 { .type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR }, 595 { .type = FTL_LAYOUT_REGION_TYPE_DATA_NVC, .deprecated = true }, 596 { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC }, 597 { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT }, 598 { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP }, 599 { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT }, 600 { .type = FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN }, 601 { .type = FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX }, 602 { .type = FTL_LAYOUT_REGION_TYPE_INVALID }, 603 }; 604 605 for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) { 606 struct ftl_layout_region *region; 607 608 rc = layout_region_verify(dev, reg_descr->type); 609 if (rc == -ENOENT) { 610 if (reg_descr->deprecated) { 611 continue; 612 } 613 614 ftl_layout_upgrade_add_region_placeholder(dev, dev->nvc_layout_tracker, reg_descr->type); 615 } else if (rc) { 616 return -1; 617 } 618 619 if (reg_descr->deprecated) { 620 rc = ftl_layout_upgrade_drop_region(dev, dev->nvc_layout_tracker, reg_descr->type, 621 dev->layout.region[reg_descr->type].current.version); 622 if (rc) { 623 return rc; 624 } 625 continue; 626 } 627 628 region = &dev->layout.region[reg_descr->type]; 629 region->type = reg_descr->type; 630 region->mirror_type = (reg_descr->mirror_type) ? reg_descr->mirror_type : 631 FTL_LAYOUT_REGION_TYPE_INVALID; 632 region->name = ftl_md_region_name(reg_descr->type); 633 634 region->bdev_desc = dev->nv_cache.bdev_desc; 635 region->ioch = dev->nv_cache.cache_ioch; 636 region->vss_blksz = dev->nv_cache.md_size; 637 } 638 639 return 0; 640 } 641 642 static int 643 filter_region_type_base(enum ftl_layout_region_type reg_type) 644 { 645 switch (reg_type) { 646 case FTL_LAYOUT_REGION_TYPE_SB_BASE: 647 case FTL_LAYOUT_REGION_TYPE_DATA_BASE: 648 case FTL_LAYOUT_REGION_TYPE_VALID_MAP: 649 return 0; 650 651 default: 652 return 1; 653 } 654 } 655 656 static int 657 filter_region_type_nvc(enum ftl_layout_region_type reg_type) 658 { 659 return filter_region_type_base(reg_type) ? 0 : 1; 660 } 661 662 static int 663 layout_apply_nvc(struct spdk_ftl_dev *dev) 664 { 665 if (layout_apply_from_sb_blob(dev, dev->nvc_layout_tracker, filter_region_type_nvc) || 666 layout_fixup_nvc(dev)) { 667 return -1; 668 } 669 return 0; 670 } 671 672 static int 673 layout_apply_base(struct spdk_ftl_dev *dev) 674 { 675 if (layout_apply_from_sb_blob(dev, dev->base_layout_tracker, filter_region_type_base) || 676 layout_fixup_base(dev)) { 677 return -1; 678 } 679 return 0; 680 } 681 682 int 683 ftl_superblock_v5_md_layout_apply(struct spdk_ftl_dev *dev) 684 { 685 if (layout_apply_nvc(dev) || layout_apply_base(dev)) { 686 return -1; 687 } 688 return 0; 689 } 690