xref: /spdk/lib/ftl/upgrade/ftl_layout_upgrade.c (revision 12fbe739a31b09aff0d05f354d4f3bbef99afc55)
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_layout_upgrade.h"
8 #include "ftl_layout.h"
9 #include "ftl_sb_current.h"
10 #include "ftl_sb_prev.h"
11 #include "ftl_core.h"
12 #include "ftl_band.h"
13 
14 int
15 ftl_region_upgrade_disabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
16 {
17 	return -1;
18 }
19 
20 int
21 ftl_region_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
22 {
23 	if (!(dev->sb->clean == 1 && dev->sb_shm->shm_clean == 0)) {
24 		FTL_ERRLOG(dev, "FTL region upgrade: SB dirty\n");
25 		return -1;
26 	}
27 	return 0;
28 }
29 
30 #ifndef UTEST
31 extern struct ftl_region_upgrade_desc sb_upgrade_desc[];
32 extern struct ftl_region_upgrade_desc p2l_upgrade_desc[];
33 extern struct ftl_region_upgrade_desc nvc_upgrade_desc[];
34 extern struct ftl_region_upgrade_desc band_upgrade_desc[];
35 
36 static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = {
37 	[FTL_LAYOUT_REGION_TYPE_SB] = {
38 		.count = FTL_SB_VERSION_CURRENT,
39 		.desc = sb_upgrade_desc,
40 	},
41 	[FTL_LAYOUT_REGION_TYPE_SB_BASE] = {
42 		.count = FTL_SB_VERSION_CURRENT,
43 		.desc = sb_upgrade_desc,
44 	},
45 	[FTL_LAYOUT_REGION_TYPE_L2P] = {},
46 	[FTL_LAYOUT_REGION_TYPE_BAND_MD] = {
47 		.count = FTL_BAND_VERSION_CURRENT,
48 		.desc = band_upgrade_desc,
49 	},
50 	[FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = {
51 		.count = FTL_BAND_VERSION_CURRENT,
52 		.desc = band_upgrade_desc,
53 	},
54 	[FTL_LAYOUT_REGION_TYPE_VALID_MAP] = {},
55 	[FTL_LAYOUT_REGION_TYPE_NVC_MD] = {
56 		.count = FTL_NVC_VERSION_CURRENT,
57 		.desc = nvc_upgrade_desc,
58 	},
59 	[FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = {
60 		.count = FTL_NVC_VERSION_CURRENT,
61 		.desc = nvc_upgrade_desc,
62 	},
63 	[FTL_LAYOUT_REGION_TYPE_DATA_NVC] = {},
64 	[FTL_LAYOUT_REGION_TYPE_DATA_BASE] = {},
65 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = {
66 		.count = FTL_P2L_VERSION_CURRENT,
67 		.desc = p2l_upgrade_desc,
68 	},
69 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = {
70 		.count = FTL_P2L_VERSION_CURRENT,
71 		.desc = p2l_upgrade_desc,
72 	},
73 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = {
74 		.count = FTL_P2L_VERSION_CURRENT,
75 		.desc = p2l_upgrade_desc,
76 	},
77 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = {
78 		.count = FTL_P2L_VERSION_CURRENT,
79 		.desc = p2l_upgrade_desc,
80 	},
81 	[FTL_LAYOUT_REGION_TYPE_TRIM_MD] = {},
82 	[FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = {},
83 };
84 
85 SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) ==
86 		   FTL_LAYOUT_REGION_TYPE_MAX,
87 		   "Missing layout upgrade descriptors");
88 #endif
89 
90 static int
91 region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
92 {
93 	uint64_t ver;
94 
95 	assert(ctx->reg);
96 	assert(ctx->reg->current.version == ctx->upgrade->count);
97 	ver = ctx->reg->prev.version;
98 	if (ver > ctx->upgrade->count) {
99 		FTL_ERRLOG(dev, "Unknown region version\n");
100 		return -1;
101 	}
102 
103 	while (ver < ctx->reg->current.version) {
104 		int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg);
105 		if (rc) {
106 			return rc;
107 		}
108 		ver = ctx->upgrade->desc[ver].new_version;
109 	}
110 	return 0;
111 }
112 
113 int
114 ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
115 {
116 	int rc = 0;
117 	uint64_t ver;
118 
119 	assert(ctx->reg);
120 	assert(ctx->reg->prev.version <= ctx->reg->current.version);
121 	assert(ctx->reg->current.version == ctx->upgrade->count);
122 	ver = ctx->reg->prev.version;
123 	if (ver < ctx->upgrade->count) {
124 		ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version;
125 		rc = ctx->upgrade->desc[ver].upgrade(dev, ctx);
126 	}
127 	return rc;
128 }
129 
130 void
131 ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx,
132 			     int status)
133 {
134 	assert(ctx->reg);
135 	assert(ctx->reg->prev.version < ctx->next_reg_ver);
136 	assert(ctx->next_reg_ver <= ctx->reg->current.version);
137 
138 	/* SB MD isn't tracked in SB MD region list */
139 	if (!status) {
140 		if (ctx->reg->prev.sb_md_reg) {
141 			int rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg->prev.sb_md_reg, ctx->next_reg_ver);
142 			ftl_bug(rc != 0);
143 		}
144 
145 		ctx->reg->prev.version = ctx->next_reg_ver;
146 	}
147 
148 	if (ctx->cb) {
149 		ctx->cb(dev, ctx->cb_ctx, status);
150 	}
151 }
152 
153 int
154 ftl_layout_verify(struct spdk_ftl_dev *dev)
155 {
156 	int rc = 0;
157 	struct ftl_layout *layout = &dev->layout;
158 	struct ftl_layout_upgrade_ctx ctx = {0};
159 
160 	if (ftl_superblock_md_layout_is_empty(dev->sb)) {
161 		rc = ftl_superblock_md_layout_build(dev);
162 		goto exit;
163 	}
164 
165 	if (ftl_superblock_md_layout_load_all(dev)) {
166 		return -1;
167 	}
168 
169 	if (ftl_validate_regions(dev, layout)) {
170 		return -1;
171 	}
172 
173 	ctx.reg = &dev->layout.region[0];
174 	ctx.upgrade = &layout_upgrade_desc[0];
175 
176 	while (true) {
177 		if (region_verify(dev, &ctx)) {
178 			return -1;
179 		}
180 
181 		if (ctx.reg->type == FTL_LAYOUT_REGION_TYPE_MAX - 1) {
182 			break;
183 		}
184 
185 		ctx.reg++;
186 		ctx.upgrade++;
187 	}
188 
189 exit:
190 	return rc;
191 }
192 
193 int
194 ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev)
195 {
196 	if (ftl_validate_regions(dev, &dev->layout)) {
197 		return -1;
198 	}
199 
200 	ftl_layout_dump(dev);
201 	ftl_superblock_md_layout_dump(dev);
202 	return 0;
203 }
204 
205 int
206 ftl_superblock_upgrade(struct spdk_ftl_dev *dev)
207 {
208 	struct ftl_layout_upgrade_ctx ctx = {0};
209 	struct ftl_layout_region *reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB];
210 	int rc;
211 
212 	ctx.reg = reg;
213 	ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB];
214 	reg->prev.version = dev->sb->header.version;
215 
216 	rc = region_verify(dev, &ctx);
217 	if (rc) {
218 		return rc;
219 	}
220 
221 	while (reg->prev.version < reg->current.version) {
222 		rc = ftl_region_upgrade(dev, &ctx);
223 		if (rc) {
224 			return rc;
225 		}
226 		/* SB upgrades are all synchronous */
227 		ftl_region_upgrade_completed(dev, &ctx, rc);
228 	}
229 
230 	dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].prev.version = reg->prev.version;
231 	return 0;
232 }
233 
234 static int
235 layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
236 {
237 	struct ftl_layout_region *reg;
238 	uint64_t reg_ver;
239 	uint32_t reg_type = ctx->reg->type;
240 
241 	while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) {
242 		assert(ctx->reg);
243 		assert(ctx->upgrade);
244 		reg = ctx->reg;
245 		reg_ver = reg->prev.version;
246 
247 		if (reg_ver < reg->current.version) {
248 			/* qualify region version to upgrade */
249 			return FTL_LAYOUT_UPGRADE_CONTINUE;
250 		} else if (reg_ver == reg->current.version) {
251 			/* select the next region to upgrade */
252 			reg_type++;
253 			if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) {
254 				break;
255 			}
256 			ctx->reg++;
257 			ctx->upgrade++;
258 		} else {
259 			/* unknown version */
260 			assert(reg_ver > reg->current.version);
261 			FTL_ERRLOG(dev, "Region %d upgrade fault: version %"PRIu64"/%"PRIu64"\n", reg_type, reg_ver,
262 				   reg->current.version);
263 			return FTL_LAYOUT_UPGRADE_FAULT;
264 		}
265 	}
266 
267 	return FTL_LAYOUT_UPGRADE_DONE;
268 }
269 
270 int
271 ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
272 {
273 	if (!ctx->reg) {
274 		ctx->reg = &dev->layout.region[0];
275 		ctx->upgrade = &layout_upgrade_desc[0];
276 	}
277 
278 	return layout_upgrade_select_next_region(dev, ctx);
279 }
280