LCOV - code coverage report
Current view: top level - lib/ftl/upgrade - ftl_sb_v5.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 158 300 52.7 %
Date: 2024-07-12 14:55:14 Functions: 17 30 56.7 %

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

Generated by: LCOV version 1.15