LCOV - code coverage report
Current view: top level - lib/ftl/upgrade - ftl_layout_upgrade.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 57 108 52.8 %
Date: 2024-07-14 18:22:36 Functions: 6 11 54.5 %

          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 "ftl_layout_upgrade.h"
       8             : #include "ftl_layout.h"
       9             : #include "ftl_sb_current.h"
      10             : #include "ftl_sb_prev.h"
      11             : #include "ftl_core.h"
      12             : #include "ftl_band.h"
      13             : 
      14             : int
      15           0 : ftl_region_upgrade_disabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
      16             : {
      17           0 :         return -1;
      18             : }
      19             : 
      20             : int
      21           3 : ftl_region_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
      22             : {
      23           3 :         if (!(dev->sb->clean == 1 && dev->sb_shm->shm_clean == 0)) {
      24           0 :                 FTL_ERRLOG(dev, "FTL region upgrade: SB dirty\n");
      25           0 :                 return -1;
      26             :         }
      27           3 :         return 0;
      28             : }
      29             : 
      30             : #ifndef UTEST
      31             : extern struct ftl_region_upgrade_desc sb_upgrade_desc[];
      32             : extern struct ftl_region_upgrade_desc p2l_upgrade_desc[];
      33             : extern struct ftl_region_upgrade_desc nvc_upgrade_desc[];
      34             : extern struct ftl_region_upgrade_desc band_upgrade_desc[];
      35             : 
      36             : static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = {
      37             :         [FTL_LAYOUT_REGION_TYPE_SB] = {
      38             :                 .latest_ver = FTL_SB_VERSION_CURRENT,
      39             :                 .count = FTL_SB_VERSION_CURRENT,
      40             :                 .desc = sb_upgrade_desc,
      41             :         },
      42             :         [FTL_LAYOUT_REGION_TYPE_SB_BASE] = {
      43             :                 .latest_ver = FTL_SB_VERSION_CURRENT,
      44             :                 .count = FTL_SB_VERSION_CURRENT,
      45             :                 .desc = sb_upgrade_desc,
      46             :         },
      47             :         [FTL_LAYOUT_REGION_TYPE_L2P] = {},
      48             :         [FTL_LAYOUT_REGION_TYPE_BAND_MD] = {
      49             :                 .latest_ver = FTL_BAND_VERSION_CURRENT,
      50             :                 .count = FTL_BAND_VERSION_CURRENT,
      51             :                 .desc = band_upgrade_desc,
      52             :         },
      53             :         [FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = {
      54             :                 .latest_ver = FTL_BAND_VERSION_CURRENT,
      55             :                 .count = FTL_BAND_VERSION_CURRENT,
      56             :                 .desc = band_upgrade_desc,
      57             :         },
      58             :         [FTL_LAYOUT_REGION_TYPE_VALID_MAP] = {},
      59             :         [FTL_LAYOUT_REGION_TYPE_NVC_MD] = {
      60             :                 .latest_ver = FTL_NVC_VERSION_CURRENT,
      61             :                 .count = FTL_NVC_VERSION_CURRENT,
      62             :                 .desc = nvc_upgrade_desc,
      63             :         },
      64             :         [FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = {
      65             :                 .latest_ver = FTL_NVC_VERSION_CURRENT,
      66             :                 .count = FTL_NVC_VERSION_CURRENT,
      67             :                 .desc = nvc_upgrade_desc,
      68             :         },
      69             :         [FTL_LAYOUT_REGION_TYPE_DATA_NVC] = {},
      70             :         [FTL_LAYOUT_REGION_TYPE_DATA_BASE] = {},
      71             :         [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = {
      72             :                 .latest_ver = FTL_P2L_VERSION_CURRENT,
      73             :                 .count = FTL_P2L_VERSION_CURRENT,
      74             :                 .desc = p2l_upgrade_desc,
      75             :         },
      76             :         [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = {
      77             :                 .latest_ver = FTL_P2L_VERSION_CURRENT,
      78             :                 .count = FTL_P2L_VERSION_CURRENT,
      79             :                 .desc = p2l_upgrade_desc,
      80             :         },
      81             :         [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = {
      82             :                 .latest_ver = FTL_P2L_VERSION_CURRENT,
      83             :                 .count = FTL_P2L_VERSION_CURRENT,
      84             :                 .desc = p2l_upgrade_desc,
      85             :         },
      86             :         [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = {
      87             :                 .latest_ver = FTL_P2L_VERSION_CURRENT,
      88             :                 .count = FTL_P2L_VERSION_CURRENT,
      89             :                 .desc = p2l_upgrade_desc,
      90             :         },
      91             :         [FTL_LAYOUT_REGION_TYPE_TRIM_MD] = {},
      92             :         [FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = {},
      93             : };
      94             : 
      95             : SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) ==
      96             :                    FTL_LAYOUT_REGION_TYPE_MAX,
      97             :                    "Missing layout upgrade descriptors");
      98             : #endif
      99             : 
     100             : static int
     101          16 : region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
     102             : {
     103             :         uint64_t ver;
     104             : 
     105          16 :         assert(ctx->reg);
     106          16 :         ver = ctx->reg->current.version;
     107          16 :         if (ver > ctx->upgrade->latest_ver) {
     108           0 :                 FTL_ERRLOG(dev, "Unknown region version\n");
     109           0 :                 return -1;
     110             :         }
     111             : 
     112          19 :         while (ver < ctx->upgrade->latest_ver) {
     113           3 :                 int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg);
     114           3 :                 if (rc) {
     115           0 :                         return rc;
     116             :                 }
     117           3 :                 ftl_bug(ver > ctx->upgrade->desc[ver].new_version);
     118           3 :                 ftl_bug(ctx->upgrade->desc[ver].new_version > ctx->upgrade->latest_ver);
     119           3 :                 ver = ctx->upgrade->desc[ver].new_version;
     120             :         }
     121          16 :         return 0;
     122             : }
     123             : 
     124             : int
     125           3 : ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
     126             : {
     127           3 :         int rc = 0;
     128             :         uint64_t ver;
     129             : 
     130           3 :         assert(ctx->reg);
     131           3 :         assert(ctx->reg->current.version <= ctx->upgrade->latest_ver);
     132           3 :         ver = ctx->reg->current.version;
     133           3 :         if (ver < ctx->upgrade->latest_ver) {
     134           3 :                 ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version;
     135           3 :                 rc = ctx->upgrade->desc[ver].upgrade(dev, ctx);
     136             :         }
     137           3 :         return rc;
     138             : }
     139             : 
     140             : void
     141           3 : ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx,
     142             :                              uint64_t entry_size, uint64_t num_entries, int status)
     143             : {
     144             :         int rc;
     145             : 
     146           3 :         assert(ctx->reg);
     147           3 :         assert(ctx->reg->current.version < ctx->next_reg_ver);
     148           3 :         assert(ctx->next_reg_ver <= ctx->upgrade->latest_ver);
     149             : 
     150           3 :         if (!status) {
     151           3 :                 if (ctx->reg->type != FTL_LAYOUT_REGION_TYPE_SB) {
     152             :                         /* Superblock region is always default-created in the latest version - see ftl_layout_setup_superblock() */
     153           3 :                         rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg, ctx->next_reg_ver);
     154           3 :                         if (entry_size && num_entries) {
     155           1 :                                 dev->layout.region[ctx->reg->type].entry_size = entry_size;
     156           1 :                                 dev->layout.region[ctx->reg->type].num_entries = num_entries;
     157             :                         }
     158             : 
     159           3 :                         ftl_bug(rc != 0);
     160             :                 }
     161             : 
     162           3 :                 ctx->reg->current.version = ctx->next_reg_ver;
     163             :         }
     164             : 
     165           3 :         if (ctx->cb) {
     166           0 :                 ctx->cb(dev, ctx->cb_ctx, status);
     167             :         }
     168           3 : }
     169             : 
     170             : int
     171           0 : ftl_layout_verify(struct spdk_ftl_dev *dev)
     172             : {
     173           0 :         struct ftl_layout *layout = &dev->layout;
     174           0 :         struct ftl_layout_upgrade_ctx ctx = {0};
     175             :         enum ftl_layout_region_type reg_type;
     176             : 
     177             :         /**
     178             :          * Upon SB upgrade some MD regions may be missing in the MD layout blob - e.g. v3 to v5, FTL_LAYOUT_REGION_TYPE_DATA_BASE.
     179             :          * The regions couldn't have be added in the SB upgrade path, as the FTL layout wasn't initialized at that point.
     180             :          * Now that the FTL layout is initialized, add the missing regions and store the MD layout blob again.
     181             :          */
     182             : 
     183           0 :         if (ftl_validate_regions(dev, layout)) {
     184           0 :                 return -1;
     185             :         }
     186             : 
     187           0 :         for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) {
     188           0 :                 ctx.reg = ftl_layout_region_get(dev, reg_type);
     189           0 :                 ctx.upgrade = &layout_upgrade_desc[reg_type];
     190           0 :                 if (!ctx.reg) {
     191           0 :                         continue;
     192             :                 }
     193             : 
     194           0 :                 if (region_verify(dev, &ctx)) {
     195           0 :                         return -1;
     196             :                 }
     197             :         }
     198             : 
     199           0 :         return 0;
     200             : }
     201             : 
     202             : int
     203           0 : ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev)
     204             : {
     205           0 :         if (ftl_validate_regions(dev, &dev->layout)) {
     206           0 :                 return -1;
     207             :         }
     208             : 
     209           0 :         ftl_layout_dump(dev);
     210           0 :         ftl_superblock_md_layout_dump(dev);
     211           0 :         return 0;
     212             : }
     213             : 
     214             : int
     215           0 : ftl_superblock_upgrade(struct spdk_ftl_dev *dev)
     216             : {
     217           0 :         struct ftl_layout_upgrade_ctx ctx = {0};
     218           0 :         struct ftl_layout_region *reg = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_SB);
     219             :         int rc;
     220             : 
     221           0 :         ctx.reg = reg;
     222           0 :         ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB];
     223           0 :         reg->current.version = dev->sb->header.version;
     224             : 
     225           0 :         rc = region_verify(dev, &ctx);
     226           0 :         if (rc) {
     227           0 :                 return rc;
     228             :         }
     229             : 
     230           0 :         while (reg->current.version < ctx.upgrade->latest_ver) {
     231           0 :                 rc = ftl_region_upgrade(dev, &ctx);
     232           0 :                 if (rc) {
     233           0 :                         return rc;
     234             :                 }
     235             :                 /* SB upgrades are all synchronous */
     236           0 :                 ftl_region_upgrade_completed(dev, &ctx, 0, 0, rc);
     237             :         }
     238             : 
     239             :         /* The mirror shares the same DMA buf, so it is automatically updated upon SB store */
     240           0 :         dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.version = reg->current.version;
     241           0 :         return 0;
     242             : }
     243             : 
     244             : static int
     245           5 : layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
     246             : {
     247             :         struct ftl_layout_region *reg;
     248             :         uint64_t reg_ver, reg_latest_ver;
     249           5 :         uint32_t reg_type = ctx->reg->type;
     250             : 
     251          35 :         while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) {
     252          35 :                 assert(ctx->reg);
     253          35 :                 assert(ctx->upgrade);
     254          35 :                 reg = ctx->reg;
     255          35 :                 reg_latest_ver = ctx->upgrade->latest_ver;
     256          35 :                 reg_ver = reg->current.version;
     257             : 
     258          35 :                 if (reg_ver == reg_latest_ver || reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) {
     259             :                         /* select the next region to upgrade */
     260          32 :                         reg_type++;
     261          32 :                         if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) {
     262           2 :                                 break;
     263             :                         }
     264          30 :                         ctx->reg++;
     265          30 :                         ctx->upgrade++;
     266           3 :                 } else if (reg_ver < reg_latest_ver) {
     267             :                         /* qualify region version to upgrade */
     268           3 :                         return FTL_LAYOUT_UPGRADE_CONTINUE;
     269             :                 } else {
     270             :                         /* unknown version */
     271           0 :                         assert(reg_ver <= reg_latest_ver);
     272           0 :                         FTL_ERRLOG(dev, "Region %d upgrade fault: version %"PRIu64"/%"PRIu64"\n", reg_type, reg_ver,
     273             :                                    reg_latest_ver);
     274           0 :                         return FTL_LAYOUT_UPGRADE_FAULT;
     275             :                 }
     276             :         }
     277             : 
     278           2 :         return FTL_LAYOUT_UPGRADE_DONE;
     279             : }
     280             : 
     281             : int
     282           0 : ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
     283             : {
     284           0 :         if (!ctx->reg) {
     285           0 :                 ctx->reg = ftl_layout_region_get(dev, 0);
     286           0 :                 ctx->upgrade = &layout_upgrade_desc[0];
     287             :                 static_assert(FTL_LAYOUT_REGION_TYPE_SB == 0, "Invalid SB region type");
     288             :         }
     289             : 
     290           0 :         return layout_upgrade_select_next_region(dev, ctx);
     291             : }
     292             : 
     293             : uint64_t
     294          37 : ftl_layout_upgrade_region_get_latest_version(enum ftl_layout_region_type reg_type)
     295             : {
     296          37 :         assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
     297          37 :         return layout_upgrade_desc[reg_type].latest_ver;
     298             : }

Generated by: LCOV version 1.15