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 364 7.7 %
Date: 2024-07-15 06:45:20 Functions: 3 31 9.7 %

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

Generated by: LCOV version 1.15