LCOV - code coverage report
Current view: top level - lib/ftl - ftl_layout.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 28 366 7.7 %
Date: 2024-07-15 10:46:00 Functions: 3 32 9.4 %

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

Generated by: LCOV version 1.15