1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2022 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "mngt/ftl_mngt.h" 7 #include "mngt/ftl_mngt_steps.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 v2_upgrade_cleanup(struct ftl_layout_upgrade_ctx *lctx) 17 { 18 struct upgrade_ctx *ctx = lctx->ctx; 19 20 if (ctx->md) { 21 ftl_md_destroy(ctx->md, 0); 22 ctx->md = NULL; 23 } 24 } 25 26 static void 27 v2_upgrade_finish(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx, int status) 28 { 29 struct upgrade_ctx *ctx = lctx->ctx; 30 31 v2_upgrade_cleanup(lctx); 32 ftl_region_upgrade_completed(dev, lctx, ctx->reg.entry_size, ctx->reg.num_entries, status); 33 } 34 35 static void 36 v2_upgrade_md_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status) 37 { 38 struct ftl_layout_upgrade_ctx *lctx = md->owner.cb_ctx; 39 40 v2_upgrade_finish(dev, lctx, status); 41 } 42 43 static int 44 v2_upgrade_setup_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx, uint32_t type) 45 { 46 struct upgrade_ctx *ctx = lctx->ctx; 47 const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops; 48 49 /* TODO Add validation if no open bands */ 50 51 /* Open metadata region */ 52 if (md_ops->region_open(dev, lctx->reg->type, FTL_P2L_VERSION_2, 53 sizeof(struct ftl_p2l_ckpt_page_no_vss), 54 dev->layout.p2l.ckpt_pages, &ctx->reg)) { 55 return -1; 56 } 57 58 ctx->md = ftl_md_create(dev, ctx->reg.current.blocks, 0, ctx->reg.name, FTL_MD_CREATE_HEAP, 59 &ctx->reg); 60 if (!ctx->md) { 61 return -1; 62 } 63 64 ctx->md->owner.cb_ctx = lctx; 65 ctx->md->cb = v2_upgrade_md_cb; 66 67 return 0; 68 } 69 70 static int 71 v2_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx) 72 { 73 struct upgrade_ctx *ctx = lctx->ctx; 74 75 if (v2_upgrade_setup_ctx(dev, lctx, lctx->reg->type)) { 76 goto error; 77 } 78 ftl_md_clear(ctx->md, 0, NULL); 79 return 0; 80 error: 81 v2_upgrade_cleanup(lctx); 82 return -1; 83 } 84 85 static int 86 v1_to_v2_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region) 87 { 88 const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops; 89 90 if (ftl_region_major_upgrade_enabled(dev, region)) { 91 return -1; 92 } 93 94 /* Create the new P2L metadata region (v2) up front - this allocates a separate entry in the superblock and 95 * area on the cache for us. This is to reserve space for other region upgrades allocating new regions and it 96 * allows us to do an atomic upgrade of the whole region. 97 * 98 * If the upgrade is stopped by power failure/crash after the V2 region has been added, then the upgrade process 99 * will start again (since V1 still exists), but region_create will fail (since the v2 region has already been 100 * created). In such a case only verification of the region length by region_open is needed. 101 * 102 * Once the upgrade is fully done, the old v1 region entry will be removed from the SB and its area on the cache 103 * freed. 104 */ 105 if (md_ops->region_create(dev, region->type, FTL_P2L_VERSION_2, dev->layout.p2l.ckpt_pages) && 106 md_ops->region_open(dev, region->type, FTL_P2L_VERSION_2, sizeof(struct ftl_p2l_ckpt_page_no_vss), 107 dev->layout.p2l.ckpt_pages, NULL)) { 108 return -1; 109 } 110 111 return 0; 112 } 113 114 struct ftl_region_upgrade_desc p2l_upgrade_desc[] = { 115 [FTL_P2L_VERSION_0] = { 116 .verify = ftl_region_upgrade_disabled 117 }, 118 [FTL_P2L_VERSION_1] = { 119 .verify = v1_to_v2_upgrade_enabled, 120 .ctx_size = sizeof(struct upgrade_ctx), 121 .new_version = FTL_P2L_VERSION_2, 122 .upgrade = v2_upgrade, 123 }, 124 }; 125 126 SPDK_STATIC_ASSERT(SPDK_COUNTOF(p2l_upgrade_desc) == FTL_P2L_VERSION_CURRENT, 127 "Missing P2L region upgrade descriptors"); 128