xref: /spdk/lib/ftl/upgrade/ftl_trim_upgrade.c (revision 95d6c9fac17572b107042103439aafd696d60b0e)
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