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-12-16 18:21:06 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             :         [FTL_LAYOUT_REGION_TYPE_TRIM_LOG] = {
     113             :                 .latest_ver = FTL_TRIM_LOG_VERSION_CURRENT,
     114             :                 .count = FTL_TRIM_LOG_VERSION_CURRENT,
     115             :                 .desc = trim_log_upgrade_desc,
     116             :         },
     117             :         [FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR] = {
     118             :                 .latest_ver = FTL_TRIM_LOG_VERSION_CURRENT,
     119             :                 .count = FTL_TRIM_LOG_VERSION_CURRENT,
     120             :                 .desc = trim_log_upgrade_desc,
     121             :         },
     122             :         [FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN] = {},
     123             :         [FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX] = {},
     124             : };
     125             : 
     126             : SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) ==
     127             :                    FTL_LAYOUT_REGION_TYPE_MAX,
     128             :                    "Missing layout upgrade descriptors");
     129             : #endif
     130             : 
     131             : uint64_t
     132           0 : ftl_layout_upgrade_get_latest_version(enum ftl_layout_region_type reg_type)
     133             : {
     134           0 :         assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
     135           0 :         return layout_upgrade_desc[reg_type].latest_ver;
     136             : }
     137             : 
     138             : static int
     139          20 : region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
     140             : {
     141             :         uint64_t ver;
     142             : 
     143          20 :         assert(ctx->reg);
     144          20 :         ver = ctx->reg->current.version;
     145          20 :         if (ver > ctx->upgrade->latest_ver) {
     146           0 :                 FTL_ERRLOG(dev, "Unknown region version\n");
     147           0 :                 return -1;
     148             :         }
     149             : 
     150          23 :         while (ver < ctx->upgrade->latest_ver) {
     151           3 :                 int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg);
     152           3 :                 if (rc) {
     153           0 :                         return rc;
     154             :                 }
     155           3 :                 ftl_bug(ver > ctx->upgrade->desc[ver].new_version);
     156           3 :                 ftl_bug(ctx->upgrade->desc[ver].new_version > ctx->upgrade->latest_ver);
     157           3 :                 ver = ctx->upgrade->desc[ver].new_version;
     158             :         }
     159          20 :         return 0;
     160             : }
     161             : 
     162             : int
     163           3 : ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
     164             : {
     165           3 :         int rc = 0;
     166             :         uint64_t ver;
     167             : 
     168           3 :         assert(ctx->reg);
     169           3 :         assert(ctx->reg->current.version <= ctx->upgrade->latest_ver);
     170           3 :         ver = ctx->reg->current.version;
     171           3 :         if (ver < ctx->upgrade->latest_ver) {
     172           3 :                 ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version;
     173           3 :                 rc = ctx->upgrade->desc[ver].upgrade(dev, ctx);
     174             :         }
     175           3 :         return rc;
     176             : }
     177             : 
     178             : void
     179           3 : ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx,
     180             :                              uint64_t entry_size, uint64_t num_entries, int status)
     181             : {
     182             :         int rc;
     183             : 
     184           3 :         assert(ctx->reg);
     185           3 :         assert(ctx->reg->current.version < ctx->next_reg_ver);
     186           3 :         assert(ctx->next_reg_ver <= ctx->upgrade->latest_ver);
     187             : 
     188           3 :         if (!status) {
     189           3 :                 if (ctx->reg->type != FTL_LAYOUT_REGION_TYPE_SB) {
     190             :                         /* Superblock region is always default-created in the latest version - see ftl_layout_setup_superblock() */
     191           3 :                         rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg, ctx->next_reg_ver);
     192           3 :                         if (entry_size && num_entries) {
     193           1 :                                 dev->layout.region[ctx->reg->type].entry_size = entry_size;
     194           1 :                                 dev->layout.region[ctx->reg->type].num_entries = num_entries;
     195             :                         }
     196             : 
     197           3 :                         ftl_bug(rc != 0);
     198             :                 }
     199             : 
     200           3 :                 ctx->reg->current.version = ctx->next_reg_ver;
     201             :         }
     202             : 
     203           3 :         if (ctx->cb) {
     204           0 :                 ctx->cb(dev, ctx->cb_ctx, status);
     205             :         }
     206           3 : }
     207             : 
     208             : int
     209           0 : ftl_layout_verify(struct spdk_ftl_dev *dev)
     210             : {
     211           0 :         struct ftl_layout *layout = &dev->layout;
     212           0 :         struct ftl_layout_upgrade_ctx ctx = {0};
     213             :         enum ftl_layout_region_type reg_type;
     214             : 
     215             :         /**
     216             :          * 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.
     217             :          * The regions couldn't have be added in the SB upgrade path, as the FTL layout wasn't initialized at that point.
     218             :          * Now that the FTL layout is initialized, add the missing regions and store the MD layout blob again.
     219             :          */
     220             : 
     221           0 :         if (ftl_validate_regions(dev, layout)) {
     222           0 :                 return -1;
     223             :         }
     224             : 
     225           0 :         for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) {
     226           0 :                 ctx.reg = ftl_layout_region_get(dev, reg_type);
     227           0 :                 ctx.upgrade = &layout_upgrade_desc[reg_type];
     228           0 :                 if (!ctx.reg) {
     229           0 :                         continue;
     230             :                 }
     231             : 
     232           0 :                 if (region_verify(dev, &ctx)) {
     233           0 :                         return -1;
     234             :                 }
     235             :         }
     236             : 
     237           0 :         return 0;
     238             : }
     239             : 
     240             : int
     241           0 : ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev)
     242             : {
     243           0 :         if (ftl_validate_regions(dev, &dev->layout)) {
     244           0 :                 return -1;
     245             :         }
     246             : 
     247           0 :         ftl_layout_dump(dev);
     248           0 :         ftl_superblock_md_layout_dump(dev);
     249           0 :         return 0;
     250             : }
     251             : 
     252             : int
     253           0 : ftl_superblock_upgrade(struct spdk_ftl_dev *dev)
     254             : {
     255           0 :         struct ftl_layout_upgrade_ctx ctx = {0};
     256           0 :         struct ftl_layout_region *reg = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_SB);
     257             :         int rc;
     258             : 
     259           0 :         ctx.reg = reg;
     260           0 :         ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB];
     261           0 :         reg->current.version = dev->sb->header.version;
     262             : 
     263           0 :         rc = region_verify(dev, &ctx);
     264           0 :         if (rc) {
     265           0 :                 return rc;
     266             :         }
     267             : 
     268           0 :         while (reg->current.version < ctx.upgrade->latest_ver) {
     269           0 :                 rc = ftl_region_upgrade(dev, &ctx);
     270           0 :                 if (rc) {
     271           0 :                         return rc;
     272             :                 }
     273             :                 /* SB upgrades are all synchronous */
     274           0 :                 ftl_region_upgrade_completed(dev, &ctx, 0, 0, rc);
     275             :         }
     276             : 
     277             :         /* The mirror shares the same DMA buf, so it is automatically updated upon SB store */
     278           0 :         dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.version = reg->current.version;
     279           0 :         return 0;
     280             : }
     281             : 
     282             : static int
     283           5 : layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
     284             : {
     285             :         struct ftl_layout_region *reg;
     286             :         uint64_t reg_ver, reg_latest_ver;
     287           5 :         uint32_t reg_type = ctx->reg->type;
     288             : 
     289          43 :         while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) {
     290          43 :                 assert(ctx->reg);
     291          43 :                 assert(ctx->upgrade);
     292          43 :                 reg = ctx->reg;
     293          43 :                 reg_latest_ver = ctx->upgrade->latest_ver;
     294          43 :                 reg_ver = reg->current.version;
     295             : 
     296          43 :                 if (reg_ver == reg_latest_ver || reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) {
     297             :                         /* select the next region to upgrade */
     298          40 :                         reg_type++;
     299          40 :                         if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) {
     300           2 :                                 break;
     301             :                         }
     302          38 :                         ctx->reg++;
     303          38 :                         ctx->upgrade++;
     304           3 :                 } else if (reg_ver < reg_latest_ver) {
     305             :                         /* qualify region version to upgrade */
     306           3 :                         return FTL_LAYOUT_UPGRADE_CONTINUE;
     307             :                 } else {
     308             :                         /* unknown version */
     309           0 :                         assert(reg_ver <= reg_latest_ver);
     310           0 :                         FTL_ERRLOG(dev, "Region %d upgrade fault: version %"PRIu64"/%"PRIu64"\n", reg_type, reg_ver,
     311             :                                    reg_latest_ver);
     312           0 :                         return FTL_LAYOUT_UPGRADE_FAULT;
     313             :                 }
     314             :         }
     315             : 
     316           2 :         return FTL_LAYOUT_UPGRADE_DONE;
     317             : }
     318             : 
     319             : int
     320           0 : ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
     321             : {
     322           0 :         if (!ctx->reg) {
     323           0 :                 ctx->reg = ftl_layout_region_get(dev, 0);
     324           0 :                 ctx->upgrade = &layout_upgrade_desc[0];
     325             :                 SPDK_STATIC_ASSERT(FTL_LAYOUT_REGION_TYPE_SB == 0, "Invalid SB region type");
     326             :         }
     327             : 
     328           0 :         return layout_upgrade_select_next_region(dev, ctx);
     329             : }
     330             : 
     331             : uint64_t
     332          45 : ftl_layout_upgrade_region_get_latest_version(enum ftl_layout_region_type reg_type)
     333             : {
     334          45 :         assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
     335          45 :         return layout_upgrade_desc[reg_type].latest_ver;
     336             : }
     337             : 
     338             : int
     339           0 : ftl_layout_upgrade_drop_region(struct spdk_ftl_dev *dev,
     340             :                                struct ftl_layout_tracker_bdev *layout_tracker,
     341             :                                enum ftl_layout_region_type reg_type, uint32_t reg_ver)
     342             : {
     343           0 :         const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
     344           0 :         int rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg_type, reg_ver);
     345             : 
     346           0 :         ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, &reg_search_ctx);
     347           0 :         if (reg_search_ctx) {
     348           0 :                 FTL_ERRLOG(dev,
     349             :                            "Error when dropping region type %"PRId32", ver %"PRIu32": rc:%"PRId32" but found reg ver %"PRIu32"\n",
     350             :                            reg_type, reg_ver, rc, reg_search_ctx->ver);
     351           0 :                 return -1;
     352             :         }
     353           0 :         dev->layout.region[reg_type].type = FTL_LAYOUT_REGION_TYPE_INVALID;
     354           0 :         return 0;
     355             : }

Generated by: LCOV version 1.15