LCOV - code coverage report
Current view: top level - lib/ftl/upgrade - ftl_chunk_upgrade.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 51 0.0 %
Date: 2024-07-12 11:42:48 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_nv_cache.h"
       8             : #include "ftl_layout_upgrade.h"
       9             : #include "ftl_utils.h"
      10             : 
      11             : struct upgrade_ctx {
      12             :         struct ftl_md                   *md_v2;
      13             :         struct ftl_layout_region        reg_v2;
      14             : };
      15             : 
      16             : static void
      17           0 : v1_to_v2_upgrade_cleanup(struct ftl_layout_upgrade_ctx *lctx)
      18             : {
      19           0 :         struct upgrade_ctx *ctx = lctx->ctx;
      20             : 
      21           0 :         if (ctx->md_v2) {
      22           0 :                 ftl_md_destroy(ctx->md_v2, 0);
      23           0 :                 ctx->md_v2 = NULL;
      24             :         }
      25           0 : }
      26             : 
      27             : static void
      28           0 : v1_to_v2_upgrade_finish(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx, int status)
      29             : {
      30           0 :         struct upgrade_ctx *ctx = lctx->ctx;
      31             : 
      32           0 :         v1_to_v2_upgrade_cleanup(lctx);
      33           0 :         ftl_region_upgrade_completed(dev, lctx, ctx->reg_v2.entry_size, ctx->reg_v2.num_entries, status);
      34           0 : }
      35             : 
      36             : static void
      37           0 : v1_to_v2_upgrade_set(struct ftl_layout_upgrade_ctx *lctx)
      38             : {
      39           0 :         struct upgrade_ctx *ctx = lctx->ctx;
      40           0 :         struct ftl_nv_cache_chunk_md *md = ftl_md_get_buffer(ctx->md_v2);
      41             : 
      42             :         assert(sizeof(struct ftl_nv_cache_chunk_md) == FTL_BLOCK_SIZE);
      43           0 :         for (uint64_t i = 0; i < ctx->reg_v2.current.blocks; i++, md++) {
      44           0 :                 ftl_nv_cache_chunk_md_initialize(md);
      45             :         }
      46           0 : }
      47             : 
      48             : static void
      49           0 : v1_to_v2_upgrade_md_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
      50             : {
      51           0 :         struct ftl_layout_upgrade_ctx *lctx = md->owner.cb_ctx;
      52             : 
      53           0 :         v1_to_v2_upgrade_finish(dev, lctx, status);
      54           0 : }
      55             : 
      56             : static int
      57           0 : v1_to_v2_upgrade_setup_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx,
      58             :                            uint32_t type)
      59             : {
      60           0 :         struct upgrade_ctx *ctx = lctx->ctx;
      61           0 :         const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
      62             : 
      63             :         assert(sizeof(struct ftl_nv_cache_chunk_md) == FTL_BLOCK_SIZE);
      64             : 
      65             :         /* Create the new NV cache metadata region - v2 */
      66           0 :         if (md_ops->region_open(dev, type, FTL_NVC_VERSION_2, sizeof(struct ftl_nv_cache_chunk_md),
      67             :                                 dev->layout.nvc.chunk_count, &ctx->reg_v2)) {
      68           0 :                 return -1;
      69             :         }
      70           0 :         ctx->md_v2 = ftl_md_create(dev, ctx->reg_v2.current.blocks, 0, ctx->reg_v2.name, FTL_MD_CREATE_HEAP,
      71           0 :                                    &ctx->reg_v2);
      72           0 :         if (!ctx->md_v2) {
      73           0 :                 return -1;
      74             :         }
      75             : 
      76           0 :         ctx->md_v2->owner.cb_ctx = lctx;
      77           0 :         ctx->md_v2->cb = v1_to_v2_upgrade_md_cb;
      78           0 :         v1_to_v2_upgrade_set(lctx);
      79             : 
      80           0 :         return 0;
      81             : }
      82             : 
      83             : static int
      84           0 : v1_to_v2_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx)
      85             : {
      86           0 :         struct upgrade_ctx *ctx = lctx->ctx;
      87             : 
      88             :         /*
      89             :          * Chunks at this point should be fully drained of user data (major upgrade). This means that it's safe to reinitialize
      90             :          * the MD and fully change the structure layout (we're not interpreting the metadata contents at this point).
      91             :          * Once we're done the version of the region in the superblock will be updated.
      92             :          */
      93             : 
      94           0 :         if (v1_to_v2_upgrade_setup_ctx(dev, lctx, lctx->reg->type)) {
      95           0 :                 goto error;
      96             :         }
      97           0 :         ftl_md_persist(ctx->md_v2);
      98           0 :         return 0;
      99             : 
     100           0 : error:
     101           0 :         v1_to_v2_upgrade_cleanup(lctx);
     102           0 :         return -1;
     103             : }
     104             : 
     105             : static int
     106           0 : v1_to_v2_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
     107             : {
     108           0 :         const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
     109             : 
     110             :         assert(sizeof(struct ftl_nv_cache_chunk_md) == FTL_BLOCK_SIZE);
     111             : 
     112           0 :         if (ftl_region_major_upgrade_enabled(dev, region)) {
     113           0 :                 return -1;
     114             :         }
     115             : 
     116             :         /* Create the new NV cache metadata region (v2) up front - this allocates a separate entry in the superblock and
     117             :          * area on the cache for us. This is to reserve space for other region upgrades allocating new regions and it
     118             :          * allows us to do an atomic upgrade of the whole region.
     119             :          *
     120             :          * If the upgrade is stopped by power failure/crash after the V2 region has been added, then the upgrade process
     121             :          * will start again (since V1 still exists), but region_create will fail (since the v2 region has already been
     122             :          * created). In such a case only verification of the region length by region_open is needed.
     123             :          *
     124             :          * Once the upgrade is fully done, the old v1 region entry will be removed from the SB and its area on the cache
     125             :          * freed.
     126             :          */
     127           0 :         if (md_ops->region_create(dev, region->type, FTL_NVC_VERSION_2, dev->layout.nvc.chunk_count) &&
     128           0 :             md_ops->region_open(dev, region->type, FTL_NVC_VERSION_2, sizeof(struct ftl_nv_cache_chunk_md),
     129             :                                 dev->layout.nvc.chunk_count, NULL)) {
     130           0 :                 return -1;
     131             :         }
     132             : 
     133           0 :         return 0;
     134             : }
     135             : 
     136             : struct ftl_region_upgrade_desc nvc_upgrade_desc[] = {
     137             :         [FTL_NVC_VERSION_0] = {
     138             :                 .verify = ftl_region_upgrade_disabled,
     139             :         },
     140             :         [FTL_NVC_VERSION_1] = {
     141             :                 .verify = v1_to_v2_upgrade_enabled,
     142             :                 .ctx_size = sizeof(struct upgrade_ctx),
     143             :                 .new_version = FTL_NVC_VERSION_2,
     144             :                 .upgrade = v1_to_v2_upgrade,
     145             :         },
     146             : };
     147             : 
     148             : SPDK_STATIC_ASSERT(SPDK_COUNTOF(nvc_upgrade_desc) == FTL_NVC_VERSION_CURRENT,
     149             :                    "Missing NVC region upgrade descriptors");

Generated by: LCOV version 1.15