LCOV - code coverage report
Current view: top level - lib/ftl/upgrade - ftl_band_upgrade.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 66 0.0 %
Date: 2024-07-11 09:52:25 Functions: 0 7 0.0 %

          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_band.h"
       8             : #include "ftl_layout_upgrade.h"
       9             : 
      10             : struct upgrade_ctx {
      11             :         struct ftl_md                   *md;
      12             :         struct ftl_layout_region        reg;
      13             : };
      14             : 
      15             : static void
      16           0 : v2_upgrade_cleanup(struct ftl_layout_upgrade_ctx *lctx)
      17             : {
      18           0 :         struct upgrade_ctx *ctx = lctx->ctx;
      19             : 
      20           0 :         if (ctx->md) {
      21           0 :                 ftl_md_destroy(ctx->md, 0);
      22           0 :                 ctx->md = NULL;
      23             :         }
      24           0 : }
      25             : 
      26             : static void
      27           0 : v2_upgrade_finish(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx, int status)
      28             : {
      29           0 :         struct upgrade_ctx *ctx = lctx->ctx;
      30             : 
      31           0 :         v2_upgrade_cleanup(lctx);
      32           0 :         ftl_region_upgrade_completed(dev, lctx, ctx->reg.entry_size, ctx->reg.num_entries, status);
      33           0 : }
      34             : 
      35             : static void
      36           0 : v2_upgrade_md_persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
      37             : {
      38           0 :         struct ftl_layout_upgrade_ctx *lctx = md->owner.cb_ctx;
      39             : 
      40           0 :         v2_upgrade_finish(dev, lctx, status);
      41           0 : }
      42             : 
      43             : static void
      44           0 : v2_upgrade_md_restore_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
      45             : {
      46           0 :         struct ftl_layout_upgrade_ctx *lctx = md->owner.cb_ctx;
      47           0 :         struct upgrade_ctx *ctx = lctx->ctx;
      48           0 :         struct ftl_band_md *band = ftl_md_get_buffer(md);
      49           0 :         uint64_t move = sizeof(band->version);
      50             : 
      51           0 :         if (status) {
      52           0 :                 v2_upgrade_finish(dev, lctx, status);
      53           0 :                 return;
      54             :         }
      55             : 
      56             :         /* If the upgrade process is interrupted while only part of the update persisted,
      57             :          * then the V1 version will be read from again and this section will rewrite the whole band md.
      58             :          */
      59           0 :         for (uint64_t i = 0; i < dev->num_bands; i++, band++) {
      60           0 :                 char *buffer = (char *)band;
      61             : 
      62           0 :                 memmove(buffer + move, buffer, sizeof(*band) - move);
      63           0 :                 band->version = FTL_BAND_VERSION_2;
      64             : 
      65           0 :                 if (band->state != FTL_BAND_STATE_CLOSED && band->state != FTL_BAND_STATE_FREE) {
      66           0 :                         v2_upgrade_finish(dev, lctx, -EINVAL);
      67           0 :                         return;
      68             :                 }
      69             :         }
      70             : 
      71           0 :         ctx->md->cb = v2_upgrade_md_persist_cb;
      72           0 :         ftl_md_set_region(ctx->md, &ctx->reg);
      73           0 :         ftl_md_persist(ctx->md);
      74             : }
      75             : 
      76             : static int
      77           0 : v2_upgrade_setup_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx)
      78             : {
      79           0 :         struct upgrade_ctx *ctx = lctx->ctx;
      80           0 :         const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
      81             : 
      82             :         assert(sizeof(struct ftl_band_md) == FTL_BLOCK_SIZE);
      83             : 
      84           0 :         if (lctx->reg->num_entries != dev->num_bands) {
      85           0 :                 return -1;
      86             :         }
      87             : 
      88             :         /* Open metadata region */
      89           0 :         if (md_ops->region_open(dev, lctx->reg->type, FTL_BAND_VERSION_2, sizeof(struct ftl_band_md),
      90             :                                 dev->num_bands, &ctx->reg)) {
      91           0 :                 return -1;
      92             :         }
      93             : 
      94           0 :         if (lctx->reg->current.blocks != ctx->reg.current.blocks) {
      95           0 :                 return -1;
      96             :         }
      97             : 
      98           0 :         ctx->md = ftl_md_create(dev, lctx->reg->current.blocks, 0, ctx->reg.name, FTL_MD_CREATE_HEAP,
      99           0 :                                 lctx->reg);
     100           0 :         if (!ctx->md) {
     101           0 :                 return -1;
     102             :         }
     103             : 
     104           0 :         ctx->md->owner.cb_ctx = lctx;
     105           0 :         ctx->md->cb = v2_upgrade_md_restore_cb;
     106             : 
     107           0 :         return 0;
     108             : }
     109             : 
     110             : static int
     111           0 : v2_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx)
     112             : {
     113           0 :         struct upgrade_ctx *ctx = lctx->ctx;
     114             : 
     115           0 :         if (v2_upgrade_setup_ctx(dev, lctx)) {
     116           0 :                 goto error;
     117             :         }
     118             :         /* At this point we're reading the contents of the v1 md */
     119           0 :         ftl_md_restore(ctx->md);
     120           0 :         return 0;
     121           0 : error:
     122           0 :         v2_upgrade_cleanup(lctx);
     123           0 :         return -1;
     124             : }
     125             : 
     126             : static int
     127           0 : v1_to_v2_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
     128             : {
     129           0 :         const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
     130             : 
     131           0 :         if (ftl_region_major_upgrade_enabled(dev, region)) {
     132           0 :                 return -1;
     133             :         }
     134             : 
     135             :         /* Create the new band metadata region (v2) up front - this allocates a separate entry in the superblock and
     136             :          * area on the cache for us. This is to reserve space for other region upgrades allocating new regions and it
     137             :          * allows us to do an atomic upgrade of the whole region.
     138             :          *
     139             :          * If the upgrade is stopped by power failure/crash after the V2 region has been added, then the upgrade process
     140             :          * will start again (since V1 still exists), but region_create will fail (since the v2 region has already been
     141             :          * created). In such a case only verification of the region length by region_open is needed.
     142             :          *
     143             :          * Once the upgrade is fully done, the old v1 region entry will be removed from the SB and its area on the cache
     144             :          * freed.
     145             :          */
     146           0 :         if (md_ops->region_create(dev, region->type, FTL_BAND_VERSION_2, dev->num_bands) &&
     147           0 :             md_ops->region_open(dev, region->type, FTL_BAND_VERSION_2, sizeof(struct ftl_band_md),
     148             :                                 dev->num_bands, NULL)) {
     149           0 :                 return -1;
     150             :         }
     151             : 
     152           0 :         return 0;
     153             : }
     154             : 
     155             : struct ftl_region_upgrade_desc band_upgrade_desc[] = {
     156             :         [FTL_BAND_VERSION_0] = {
     157             :                 .verify = ftl_region_upgrade_disabled,
     158             :         },
     159             :         [FTL_BAND_VERSION_1] = {
     160             :                 .verify = v1_to_v2_upgrade_enabled,
     161             :                 .ctx_size = sizeof(struct upgrade_ctx),
     162             :                 .new_version = FTL_BAND_VERSION_2,
     163             :                 .upgrade = v2_upgrade,
     164             :         },
     165             : };
     166             : 
     167             : SPDK_STATIC_ASSERT(SPDK_COUNTOF(band_upgrade_desc) == FTL_BAND_VERSION_CURRENT,
     168             :                    "Missing band region upgrade descriptors");

Generated by: LCOV version 1.15