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

Generated by: LCOV version 1.15