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; 13 struct ftl_layout_region reg; 14 }; 15 16 static void 17 v0_to_v1_upgrade_cleanup(struct ftl_layout_upgrade_ctx *lctx) 18 { 19 struct upgrade_ctx *ctx = lctx->ctx; 20 21 if (ctx->md) { 22 ftl_md_destroy(ctx->md, 0); 23 ctx->md = NULL; 24 } 25 } 26 27 static void 28 v0_to_v1_upgrade_finish(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx, int status) 29 { 30 struct upgrade_ctx *ctx = lctx->ctx; 31 32 v0_to_v1_upgrade_cleanup(lctx); 33 ftl_region_upgrade_completed(dev, lctx, ctx->reg.entry_size, ctx->reg.num_entries, status); 34 } 35 36 static void 37 v0_to_v1_upgrade_md_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status) 38 { 39 struct ftl_layout_upgrade_ctx *lctx = md->owner.cb_ctx; 40 41 v0_to_v1_upgrade_finish(dev, lctx, status); 42 } 43 44 static int 45 v0_to_v1_upgrade_setup_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx, 46 uint32_t type) 47 { 48 struct upgrade_ctx *ctx = lctx->ctx; 49 const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops; 50 51 /* Create the new NV cache metadata region - v2 */ 52 if (md_ops->region_open(dev, type, FTL_TRIM_LOG_VERSION_1, sizeof(struct ftl_trim_log), 1, 53 &ctx->reg)) { 54 return -1; 55 } 56 ctx->md = ftl_md_create(dev, ctx->reg.current.blocks, 0, ctx->reg.name, FTL_MD_CREATE_HEAP, 57 &ctx->reg); 58 if (!ctx->md) { 59 return -1; 60 } 61 62 ctx->md->owner.cb_ctx = lctx; 63 ctx->md->cb = v0_to_v1_upgrade_md_cb; 64 65 return 0; 66 } 67 68 static int 69 v0_to_v1_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx) 70 { 71 struct upgrade_ctx *ctx = lctx->ctx; 72 73 if (v0_to_v1_upgrade_setup_ctx(dev, lctx, lctx->reg->type)) { 74 goto error; 75 } 76 ftl_md_clear(ctx->md, 0, NULL); 77 return 0; 78 79 error: 80 v0_to_v1_upgrade_cleanup(lctx); 81 return -1; 82 } 83 84 static int 85 v0_to_v1_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region) 86 { 87 const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops; 88 89 assert(sizeof(struct ftl_nv_cache_chunk_md) == FTL_BLOCK_SIZE); 90 91 if (ftl_region_major_upgrade_enabled(dev, region)) { 92 return -1; 93 } 94 95 /* Create the new trim metadata region (v1) up front - this allocates a separate entry in the superblock and 96 * area on the cache for us. This is to reserve space for other region upgrades allocating new regions and it 97 * allows us to do an atomic upgrade of the whole region. 98 * 99 * If the upgrade is stopped by power failure/crash after the V1 region has been added, then the upgrade process 100 * will start again (since V0 still exists), but region_create will fail (since the v1 region has already been 101 * created). In such a case only verification of the region length by region_open is needed. 102 * 103 * Once the upgrade is fully done, the old v0 region entry will be removed from the SB and its area on the cache 104 * freed. 105 */ 106 107 108 if (md_ops->region_create(dev, region->type, FTL_TRIM_LOG_VERSION_1, 1) && 109 md_ops->region_open(dev, region->type, FTL_TRIM_LOG_VERSION_1, sizeof(struct ftl_trim_log), 110 1, NULL)) { 111 return -1; 112 } 113 114 return 0; 115 } 116 117 struct ftl_region_upgrade_desc trim_log_upgrade_desc[] = { 118 [FTL_TRIM_LOG_VERSION_0] = { 119 .verify = v0_to_v1_upgrade_enabled, 120 .ctx_size = sizeof(struct upgrade_ctx), 121 .new_version = FTL_TRIM_LOG_VERSION_1, 122 .upgrade = v0_to_v1_upgrade, 123 }, 124 }; 125 126 SPDK_STATIC_ASSERT(SPDK_COUNTOF(trim_log_upgrade_desc) == FTL_TRIM_LOG_VERSION_CURRENT, 127 "Missing NVC region upgrade descriptors"); 128