LCOV - code coverage report
Current view: top level - spdk/lib/ftl - ftl_layout.c (source / functions) Hit Total Coverage
Test: Combined Lines: 235 368 63.9 %
Date: 2024-07-11 15:05:21 Functions: 24 31 77.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 104 242 43.0 %

           Branch data     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                 :        748 : blocks2mib(uint64_t blocks)
      26                 :            : {
      27                 :            :         float result;
      28                 :            : 
      29                 :        748 :         result = blocks;
      30                 :        748 :         result *= FTL_BLOCK_SIZE;
      31                 :        748 :         result /= 1024UL;
      32                 :        748 :         result /= 1024UL;
      33                 :            : 
      34                 :        748 :         return result;
      35                 :            : }
      36                 :            : 
      37                 :            : static uint64_t
      38                 :       1144 : superblock_region_size(struct spdk_ftl_dev *dev)
      39                 :            : {
      40                 :       1144 :         const struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
      41                 :       1144 :         uint64_t wus = spdk_bdev_get_write_unit_size(bdev) * FTL_BLOCK_SIZE;
      42                 :            : 
      43         [ -  + ]:       1144 :         if (wus > FTL_SUPERBLOCK_SIZE) {
      44                 :          0 :                 return wus;
      45                 :            :         } else {
      46                 :       1144 :                 return wus * spdk_divide_round_up(FTL_SUPERBLOCK_SIZE, wus);
      47                 :            :         }
      48                 :            : }
      49                 :            : 
      50                 :            : static uint64_t
      51                 :        840 : superblock_region_blocks(struct spdk_ftl_dev *dev)
      52                 :            : {
      53                 :        840 :         return superblock_region_size(dev) / FTL_BLOCK_SIZE;
      54                 :            : }
      55                 :            : 
      56                 :            : uint64_t
      57                 :        260 : ftl_md_region_blocks(struct spdk_ftl_dev *dev, uint64_t bytes)
      58                 :            : {
      59                 :        260 :         const uint64_t alignment = superblock_region_size(dev);
      60                 :            :         uint64_t result;
      61                 :            : 
      62                 :        260 :         result = spdk_divide_round_up(bytes, alignment);
      63                 :        260 :         result *= alignment;
      64                 :        260 :         result /= FTL_BLOCK_SIZE;
      65                 :            : 
      66                 :        260 :         return result;
      67                 :            : }
      68                 :            : 
      69                 :            : uint64_t
      70                 :        114 : ftl_md_region_align_blocks(struct spdk_ftl_dev *dev, uint64_t blocks)
      71                 :            : {
      72                 :        114 :         const uint64_t alignment = superblock_region_blocks(dev);
      73                 :            :         uint64_t result;
      74                 :            : 
      75                 :        114 :         result = spdk_divide_round_up(blocks, alignment);
      76                 :        114 :         result *= alignment;
      77                 :            : 
      78                 :        114 :         return result;
      79                 :            : }
      80                 :            : 
      81                 :            : const char *
      82                 :        386 : 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                 :        386 :         const char *reg_name = md_region_name[reg_type];
     103                 :            : 
     104         [ -  + ]:        386 :         assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
     105         [ -  + ]:        386 :         assert(reg_name != NULL);
     106                 :        386 :         return reg_name;
     107                 :            : }
     108                 :            : 
     109                 :            : static void
     110                 :        352 : dump_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
     111                 :            : {
     112   [ -  +  -  + ]:        352 :         assert(!(region->current.offset % superblock_region_blocks(dev)));
     113   [ -  +  -  + ]:        352 :         assert(!(region->current.blocks % superblock_region_blocks(dev)));
     114                 :            : 
     115         [ +  - ]:        352 :         FTL_NOTICELOG(dev, "Region %s\n", region->name);
     116         [ +  - ]:        352 :         FTL_NOTICELOG(dev, "       offset:                      %.2f MiB\n",
     117                 :            :                       blocks2mib(region->current.offset));
     118         [ +  - ]:        352 :         FTL_NOTICELOG(dev, "       blocks:                      %.2f MiB\n",
     119                 :            :                       blocks2mib(region->current.blocks));
     120                 :        352 : }
     121                 :            : 
     122                 :            : int
     123                 :         66 : 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         [ +  + ]:       1122 :         for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
     129                 :       1056 :                 struct ftl_layout_region *r1 = ftl_layout_region_get(dev, i);
     130                 :            : 
     131         [ -  + ]:       1056 :                 if (!r1) {
     132                 :          0 :                         continue;
     133                 :            :                 }
     134                 :            : 
     135         [ +  + ]:      17952 :                 for (j = 0; j < FTL_LAYOUT_REGION_TYPE_MAX; j++) {
     136                 :      16896 :                         struct ftl_layout_region *r2 = ftl_layout_region_get(dev, j);
     137                 :            : 
     138         [ -  + ]:      16896 :                         if (!r2) {
     139                 :          0 :                                 continue;
     140                 :            :                         }
     141                 :            : 
     142         [ +  + ]:      16896 :                         if (r1->bdev_desc != r2->bdev_desc) {
     143                 :       5148 :                                 continue;
     144                 :            :                         }
     145                 :            : 
     146         [ +  + ]:      11748 :                         if (i == j) {
     147                 :       1056 :                                 continue;
     148                 :            :                         }
     149                 :            : 
     150                 :      10692 :                         uint64_t r1_begin = r1->current.offset;
     151                 :      10692 :                         uint64_t r1_end = r1->current.offset + r1->current.blocks - 1;
     152                 :      10692 :                         uint64_t r2_begin = r2->current.offset;
     153                 :      10692 :                         uint64_t r2_end = r2->current.offset + r2->current.blocks - 1;
     154                 :            : 
     155         [ -  + ]:      10692 :                         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                 :         66 :         return 0;
     164                 :            : }
     165                 :            : 
     166                 :            : static uint64_t
     167                 :         22 : get_num_user_lbas(struct spdk_ftl_dev *dev)
     168                 :            : {
     169                 :            :         uint64_t blocks;
     170                 :            : 
     171                 :         22 :         blocks = dev->num_bands * ftl_get_num_blocks_in_band(dev);
     172                 :         22 :         blocks = (blocks * (100 - dev->conf.overprovisioning)) / 100;
     173                 :            : 
     174                 :         22 :         return blocks;
     175                 :            : }
     176                 :            : 
     177                 :            : static uint64_t
     178                 :          5 : layout_blocks_left(struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker)
     179                 :            : {
     180                 :          5 :         uint64_t max_reg_size = 0;
     181                 :          5 :         const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
     182                 :            : 
     183                 :            :         while (true) {
     184                 :         10 :                 ftl_layout_tracker_bdev_find_next_region(layout_tracker, FTL_LAYOUT_REGION_TYPE_FREE,
     185                 :            :                                 &reg_search_ctx);
     186         [ +  + ]:         10 :                 if (!reg_search_ctx) {
     187                 :          5 :                         break;
     188                 :            :                 }
     189                 :          5 :                 max_reg_size = spdk_max(max_reg_size, reg_search_ctx->blk_sz);
     190                 :            :         }
     191                 :          5 :         return max_reg_size;
     192                 :            : }
     193                 :            : 
     194                 :            : struct ftl_layout_region *
     195                 :   14536013 : ftl_layout_region_get(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type)
     196                 :            : {
     197                 :   14536013 :         struct ftl_layout_region *reg = &dev->layout.region[reg_type];
     198                 :            : 
     199         [ -  + ]:   14536013 :         assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
     200         [ +  - ]:   14536013 :         return reg->type == reg_type ? reg : NULL;
     201                 :            : }
     202                 :            : 
     203                 :            : uint64_t
     204                 :          5 : ftl_layout_base_offset(struct spdk_ftl_dev *dev)
     205                 :            : {
     206                 :          5 :         return dev->num_bands * ftl_get_num_blocks_in_band(dev);
     207                 :            : }
     208                 :            : 
     209                 :            : static int
     210                 :         82 : 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                 :         82 :         const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_desc->ops.md_layout_ops;
     214                 :         82 :         size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size);
     215                 :            : 
     216         [ -  + ]:         82 :         if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) {
     217                 :          0 :                 return -1;
     218                 :            :         }
     219         [ -  + ]:        164 :         if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count,
     220                 :         82 :                                 &dev->layout.region[reg_type])) {
     221                 :          0 :                 return -1;
     222                 :            :         }
     223                 :         82 :         return 0;
     224                 :            : }
     225                 :            : 
     226                 :            : static int
     227                 :         32 : 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                 :         32 :         const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops;
     231                 :         32 :         size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size);
     232                 :            : 
     233         [ -  + ]:         32 :         if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) {
     234                 :          0 :                 return -1;
     235                 :            :         }
     236         [ -  + ]:         64 :         if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count,
     237                 :         32 :                                 &dev->layout.region[reg_type])) {
     238                 :          0 :                 return -1;
     239                 :            :         }
     240                 :         32 :         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         [ #  # ]:          0 :              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                 :          5 : layout_setup_default_nvc(struct spdk_ftl_dev *dev)
     434                 :            : {
     435                 :            :         int region_type;
     436                 :            :         uint64_t left, l2p_blocks;
     437                 :          5 :         struct ftl_layout *layout = &dev->layout;
     438                 :            : 
     439                 :            :         /* Initialize L2P region */
     440                 :          5 :         l2p_blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas);
     441         [ -  + ]:          5 :         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         [ -  + ]:          5 :         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         [ -  + ]:          5 :         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                 :          5 :         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         [ #  # ]:          5 :         for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
     462         [ +  + ]:         25 :              region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX;
     463                 :         20 :              region_type++) {
     464         [ -  + ]:         20 :                 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                 :          5 :         l2p_blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks;
     474         [ -  + ]:          5 :         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         [ -  + ]:          5 :         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                 :          5 :         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                 :          5 :         left = layout_blocks_left(dev, dev->nvc_layout_tracker);
     490                 :          5 :         layout->nvc.chunk_count = (left * FTL_BLOCK_SIZE) /
     491         [ -  + ]:          5 :                                   FTL_NV_CACHE_CHUNK_SIZE(ftl_get_num_blocks_in_band(dev));
     492         [ -  + ]:          5 :         if (0 == layout->nvc.chunk_count) {
     493                 :          0 :                 goto error;
     494                 :            :         }
     495         [ -  + ]:          5 :         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         [ -  + ]:          5 :         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                 :          5 :         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         [ -  + ]:         10 :         if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_DATA_NVC, 0,
     513                 :          5 :                                      layout->nvc.chunk_data_blocks * FTL_BLOCK_SIZE, layout->nvc.chunk_count)) {
     514                 :          0 :                 goto error;
     515                 :            :         }
     516                 :            : 
     517                 :          5 :         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                 :          5 : layout_setup_default_base(struct spdk_ftl_dev *dev)
     526                 :            : {
     527                 :          5 :         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         [ -  + ]:          5 :         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                 :          5 :         valid_map_size = spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks, 8);
     541         [ -  + ]:          5 :         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                 :          5 :         return 0;
     547                 :            : }
     548                 :            : 
     549                 :            : static int
     550                 :          5 : layout_setup_default(struct spdk_ftl_dev *dev)
     551                 :            : {
     552   [ +  -  -  + ]:          5 :         if (layout_setup_default_nvc(dev) || layout_setup_default_base(dev)) {
     553                 :          0 :                 return -1;
     554                 :            :         }
     555                 :          5 :         return 0;
     556                 :            : }
     557                 :            : 
     558                 :            : static int
     559                 :         17 : layout_load(struct spdk_ftl_dev *dev)
     560                 :            : {
     561         [ -  + ]:         17 :         if (ftl_superblock_load_blob_area(dev)) {
     562                 :          0 :                 return -1;
     563                 :            :         }
     564                 :         17 :         dev->layout.nvc.chunk_count = dev->layout.region[FTL_LAYOUT_REGION_TYPE_DATA_NVC].num_entries;
     565         [ -  + ]:         17 :         if (ftl_superblock_md_layout_apply(dev)) {
     566                 :          0 :                 return -1;
     567                 :            :         }
     568                 :         17 :         return 0;
     569                 :            : }
     570                 :            : 
     571                 :            : int
     572                 :         22 : ftl_layout_setup(struct spdk_ftl_dev *dev)
     573                 :            : {
     574                 :         22 :         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         [ +  + ]:         22 :         if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
     599                 :          5 :                 setup_mode = FTL_LAYOUT_SETUP_MODE_NO_RESTRICT;
     600         [ -  + ]:         17 :         } else if (ftl_superblock_is_blob_area_empty(dev->sb)) {
     601                 :          0 :                 setup_mode = FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT;
     602                 :            :         } else {
     603                 :         17 :                 setup_mode = FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT;
     604                 :            :         }
     605         [ +  - ]:         22 :         FTL_NOTICELOG(dev, "FTL layout setup mode %d\n", (int)setup_mode);
     606                 :            : 
     607                 :            :         /* Invalidate all regions */
     608         [ +  + ]:        374 :         for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
     609   [ +  +  +  + ]:        352 :                 if (i == FTL_LAYOUT_REGION_TYPE_SB || i == FTL_LAYOUT_REGION_TYPE_SB_BASE) {
     610                 :            :                         /* Super block has been already initialized */
     611                 :         44 :                         continue;
     612                 :            :                 }
     613                 :            : 
     614                 :        308 :                 layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
     615                 :            :                 /* Mark the region inactive */
     616                 :        308 :                 layout->region[i].type = FTL_LAYOUT_REGION_TYPE_INVALID;
     617                 :            :         }
     618                 :            : 
     619                 :            :         /*
     620                 :            :          * Initialize L2P information
     621                 :            :          */
     622                 :         22 :         num_lbas = get_num_user_lbas(dev);
     623         [ +  + ]:         22 :         if (dev->num_lbas == 0) {
     624         [ -  + ]:          5 :                 assert(dev->conf.mode & SPDK_FTL_MODE_CREATE);
     625                 :          5 :                 dev->num_lbas = num_lbas;
     626                 :          5 :                 dev->sb->lba_cnt = num_lbas;
     627         [ -  + ]:         17 :         } else if (dev->num_lbas != num_lbas) {
     628         [ #  # ]:          0 :                 FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n");
     629                 :          0 :                 return -EINVAL;
     630                 :            :         }
     631                 :         22 :         layout->l2p.addr_length = spdk_u64log2(layout->base.total_blocks + layout->nvc.total_blocks) + 1;
     632         [ -  + ]:         22 :         layout->l2p.addr_size = layout->l2p.addr_length > 32 ? 8 : 4;
     633         [ -  + ]:         22 :         layout->l2p.lbas_in_page = FTL_BLOCK_SIZE / layout->l2p.addr_size;
     634                 :            : 
     635                 :            :         /* Setup P2L ckpt */
     636                 :         22 :         layout->p2l.ckpt_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev), dev->xfer_size);
     637                 :            : 
     638                 :         22 :         layout->nvc.chunk_data_blocks =
     639                 :         22 :                 FTL_NV_CACHE_CHUNK_DATA_SIZE(ftl_get_num_blocks_in_band(dev)) / FTL_BLOCK_SIZE;
     640                 :         22 :         layout->nvc.chunk_meta_size = FTL_NV_CACHE_CHUNK_MD_SIZE;
     641                 :         22 :         layout->nvc.chunk_tail_md_num_blocks = ftl_nv_cache_chunk_tail_md_num_blocks(&dev->nv_cache);
     642                 :            : 
     643                 :         22 :         layout->base.num_usable_blocks = ftl_get_num_blocks_in_band(dev);
     644                 :         22 :         layout->base.user_blocks = ftl_band_user_blocks(dev->bands);
     645                 :            : 
     646   [ -  +  +  - ]:         22 :         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                 :         17 :         case FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT:
     654         [ -  + ]:         17 :                 if (layout_load(dev)) {
     655                 :          0 :                         return -EINVAL;
     656                 :            :                 }
     657                 :         17 :                 break;
     658                 :            : 
     659                 :          5 :         case FTL_LAYOUT_SETUP_MODE_NO_RESTRICT:
     660         [ -  + ]:          5 :                 if (layout_setup_default(dev)) {
     661                 :          0 :                         return -EINVAL;
     662                 :            :                 }
     663                 :          5 :                 break;
     664                 :            : 
     665                 :          0 :         default:
     666                 :          0 :                 ftl_abort();
     667                 :            :                 break;
     668                 :            :         }
     669                 :            : 
     670         [ -  + ]:         22 :         if (ftl_validate_regions(dev, layout)) {
     671                 :          0 :                 return -EINVAL;
     672                 :            :         }
     673                 :            : 
     674                 :         22 :         rc = ftl_superblock_store_blob_area(dev);
     675                 :            : 
     676         [ +  - ]:         22 :         FTL_NOTICELOG(dev, "Base device capacity:         %.2f MiB\n",
     677                 :            :                       blocks2mib(layout->base.total_blocks));
     678         [ +  - ]:         22 :         FTL_NOTICELOG(dev, "NV cache device capacity:       %.2f MiB\n",
     679                 :            :                       blocks2mib(layout->nvc.total_blocks));
     680         [ +  - ]:         22 :         FTL_NOTICELOG(dev, "L2P entries:                    %"PRIu64"\n", dev->num_lbas);
     681         [ +  - ]:         22 :         FTL_NOTICELOG(dev, "L2P address size:               %"PRIu64"\n", layout->l2p.addr_size);
     682         [ +  - ]:         22 :         FTL_NOTICELOG(dev, "P2L checkpoint pages:           %"PRIu64"\n", layout->p2l.ckpt_pages);
     683         [ +  - ]:         22 :         FTL_NOTICELOG(dev, "NV cache chunk count            %"PRIu64"\n", dev->layout.nvc.chunk_count);
     684                 :            : 
     685                 :         22 :         return rc;
     686                 :            : }
     687                 :            : 
     688                 :            : int
     689                 :         22 : ftl_layout_setup_superblock(struct spdk_ftl_dev *dev)
     690                 :            : {
     691                 :            :         const struct spdk_bdev *bdev;
     692                 :         22 :         struct ftl_layout *layout = &dev->layout;
     693                 :         22 :         struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
     694                 :            :         uint64_t total_blocks, offset, left;
     695                 :            : 
     696         [ -  + ]:         22 :         assert(layout->md[FTL_LAYOUT_REGION_TYPE_SB] == NULL);
     697                 :            : 
     698                 :         22 :         bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
     699                 :         22 :         layout->base.total_blocks = spdk_bdev_get_num_blocks(bdev);
     700                 :            : 
     701                 :         22 :         bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
     702                 :         22 :         layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev);
     703                 :            : 
     704                 :            :         /* Initialize superblock region */
     705         [ -  + ]:         22 :         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         [ -  + ]:         22 :         assert(region->bdev_desc != NULL);
     712         [ -  + ]:         22 :         assert(region->ioch != NULL);
     713         [ -  + ]:         22 :         assert(region->current.offset == 0);
     714                 :            : 
     715         [ -  + ]:         22 :         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                 :         22 :         layout->region[FTL_LAYOUT_REGION_TYPE_SB].mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE;
     721                 :            : 
     722                 :         22 :         region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
     723         [ -  + ]:         22 :         assert(region->current.offset == 0);
     724                 :            : 
     725                 :            :         /* Check if SB can be stored at the end of base device */
     726                 :         22 :         total_blocks = spdk_bdev_get_num_blocks(
     727                 :         22 :                                spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
     728                 :         22 :         offset = region->current.offset + region->current.blocks;
     729                 :         22 :         left = total_blocks - offset;
     730   [ +  -  -  + ]:         22 :         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                 :         22 :         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                 :         22 : ftl_layout_dump(struct spdk_ftl_dev *dev)
     755                 :            : {
     756                 :            :         struct ftl_layout_region *reg;
     757                 :            :         enum ftl_layout_region_type i;
     758                 :            : 
     759         [ +  - ]:         22 :         FTL_NOTICELOG(dev, "NV cache layout:\n");
     760         [ +  + ]:        374 :         for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
     761                 :        352 :                 reg = ftl_layout_region_get(dev, i);
     762   [ +  -  +  + ]:        352 :                 if (reg && reg->bdev_desc == dev->nv_cache.bdev_desc) {
     763                 :        286 :                         dump_region(dev, reg);
     764                 :            :                 }
     765                 :            :         }
     766         [ +  - ]:         22 :         FTL_NOTICELOG(dev, "Base device layout:\n");
     767         [ +  + ]:        374 :         for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
     768                 :        352 :                 reg = ftl_layout_region_get(dev, i);
     769   [ +  -  +  + ]:        352 :                 if (reg && reg->bdev_desc == dev->base_bdev_desc) {
     770                 :         66 :                         dump_region(dev, reg);
     771                 :            :                 }
     772                 :            :         }
     773                 :         22 : }
     774                 :            : 
     775                 :            : uint64_t
     776                 :         22 : ftl_layout_base_md_blocks(struct spdk_ftl_dev *dev)
     777                 :            : {
     778                 :            :         const struct spdk_bdev *bdev;
     779                 :         22 :         uint64_t md_blocks = 0, total_blocks = 0;
     780                 :            : 
     781                 :         22 :         bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
     782                 :         22 :         total_blocks += spdk_bdev_get_num_blocks(bdev);
     783                 :            : 
     784                 :         22 :         bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
     785                 :         22 :         total_blocks += spdk_bdev_get_num_blocks(bdev);
     786                 :            : 
     787                 :            :         /* Count space needed for validity map */
     788                 :         22 :         md_blocks += ftl_md_region_blocks(dev, spdk_divide_round_up(total_blocks, 8));
     789                 :            : 
     790                 :            :         /* Count space needed for superblock */
     791                 :         22 :         md_blocks += superblock_region_blocks(dev);
     792                 :         22 :         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                 :         30 : ftl_layout_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz)
     803                 :            : {
     804                 :         30 :         struct layout_blob_entry *blob_entry = blob_buf;
     805                 :            :         struct ftl_layout_region *reg;
     806                 :            :         enum ftl_layout_region_type reg_type;
     807                 :         30 :         size_t blob_sz = 0;
     808                 :            : 
     809         [ +  + ]:        510 :         for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) {
     810         [ -  + ]:        480 :                 if (blob_sz + sizeof(*blob_entry) > blob_buf_sz) {
     811                 :          0 :                         return 0;
     812                 :            :                 }
     813                 :            : 
     814                 :        480 :                 reg = &dev->layout.region[reg_type];
     815                 :        480 :                 blob_entry->type = reg_type;
     816                 :        480 :                 blob_entry->entry_size = reg->entry_size;
     817                 :        480 :                 blob_entry->num_entries = reg->num_entries;
     818                 :            : 
     819                 :        480 :                 blob_entry++;
     820                 :        480 :                 blob_sz += sizeof(*blob_entry);
     821                 :            :         }
     822                 :            : 
     823                 :         30 :         return blob_sz;
     824                 :            : }
     825                 :            : 
     826                 :            : int
     827                 :         45 : ftl_layout_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz)
     828                 :            : {
     829                 :         45 :         struct layout_blob_entry *blob_entry = blob_buf;
     830                 :         45 :         size_t blob_entry_num = blob_sz / sizeof(*blob_entry);
     831                 :         45 :         struct layout_blob_entry *blob_entry_end = blob_entry + blob_entry_num;
     832                 :            :         struct ftl_layout_region *reg;
     833                 :            : 
     834         [ -  + ]:         45 :         if (blob_sz % sizeof(*blob_entry) != 0) {
     835                 :            :                 /* Invalid blob size */
     836                 :          0 :                 return -1;
     837                 :            :         }
     838                 :            : 
     839         [ +  + ]:        713 :         for (; blob_entry < blob_entry_end; blob_entry++) {
     840                 :            :                 /* Verify the type */
     841         [ +  + ]:        672 :                 if (blob_entry->type >= FTL_LAYOUT_REGION_TYPE_MAX) {
     842                 :          4 :                         return -1;
     843                 :            :                 }
     844                 :            : 
     845                 :            :                 /* Load the entry */
     846                 :        668 :                 reg = &dev->layout.region[blob_entry->type];
     847                 :        668 :                 reg->entry_size = blob_entry->entry_size;
     848                 :        668 :                 reg->num_entries = blob_entry->num_entries;
     849                 :            :         }
     850                 :            : 
     851                 :         41 :         return 0;
     852                 :            : }

Generated by: LCOV version 1.14