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 127 44.9 %
Date: 2024-07-11 01:33:07 Functions: 6 14 42.9 %

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

Generated by: LCOV version 1.15