xref: /spdk/lib/ftl/upgrade/ftl_layout_upgrade.c (revision 8afdeef3becfe9409cc9e7372bd0bc10e8b7d46d)
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 "spdk/assert.h"
8 
9 #include "ftl_layout_upgrade.h"
10 #include "ftl_layout.h"
11 #include "ftl_sb_current.h"
12 #include "ftl_sb_prev.h"
13 #include "ftl_core.h"
14 #include "ftl_band.h"
15 #include "utils/ftl_layout_tracker_bdev.h"
16 
17 int
18 ftl_region_major_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
19 {
20 	if (ftl_region_upgrade_enabled(dev, region)) {
21 		return -1;
22 	}
23 
24 	if (dev->sb->upgrade_ready) {
25 		return 0;
26 	} else {
27 		FTL_ERRLOG(dev, "FTL major upgrade ERROR, required upgrade shutdown in the previous version\n");
28 		return -1;
29 	}
30 }
31 
32 int
33 ftl_region_upgrade_disabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
34 {
35 	return -1;
36 }
37 
38 int
39 ftl_region_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
40 {
41 	if (!(dev->sb->clean == 1 && dev->sb_shm->shm_clean == 0)) {
42 		FTL_ERRLOG(dev, "FTL region upgrade: SB dirty\n");
43 		return -1;
44 	}
45 	return 0;
46 }
47 
48 #ifndef UTEST
49 extern struct ftl_region_upgrade_desc sb_upgrade_desc[];
50 extern struct ftl_region_upgrade_desc p2l_upgrade_desc[];
51 extern struct ftl_region_upgrade_desc nvc_upgrade_desc[];
52 extern struct ftl_region_upgrade_desc band_upgrade_desc[];
53 extern struct ftl_region_upgrade_desc trim_log_upgrade_desc[];
54 
55 static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = {
56 	[FTL_LAYOUT_REGION_TYPE_SB] = {
57 		.latest_ver = FTL_SB_VERSION_CURRENT,
58 		.count = FTL_SB_VERSION_CURRENT,
59 		.desc = sb_upgrade_desc,
60 	},
61 	[FTL_LAYOUT_REGION_TYPE_SB_BASE] = {
62 		.latest_ver = FTL_SB_VERSION_CURRENT,
63 		.count = FTL_SB_VERSION_CURRENT,
64 		.desc = sb_upgrade_desc,
65 	},
66 	[FTL_LAYOUT_REGION_TYPE_L2P] = {},
67 	[FTL_LAYOUT_REGION_TYPE_BAND_MD] = {
68 		.latest_ver = FTL_BAND_VERSION_CURRENT,
69 		.count = FTL_BAND_VERSION_CURRENT,
70 		.desc = band_upgrade_desc,
71 	},
72 	[FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = {
73 		.latest_ver = FTL_BAND_VERSION_CURRENT,
74 		.count = FTL_BAND_VERSION_CURRENT,
75 		.desc = band_upgrade_desc,
76 	},
77 	[FTL_LAYOUT_REGION_TYPE_VALID_MAP] = {},
78 	[FTL_LAYOUT_REGION_TYPE_NVC_MD] = {
79 		.latest_ver = FTL_NVC_VERSION_CURRENT,
80 		.count = FTL_NVC_VERSION_CURRENT,
81 		.desc = nvc_upgrade_desc,
82 	},
83 	[FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = {
84 		.latest_ver = FTL_NVC_VERSION_CURRENT,
85 		.count = FTL_NVC_VERSION_CURRENT,
86 		.desc = nvc_upgrade_desc,
87 	},
88 	[FTL_LAYOUT_REGION_TYPE_DATA_NVC] = {},
89 	[FTL_LAYOUT_REGION_TYPE_DATA_BASE] = {},
90 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = {
91 		.latest_ver = FTL_P2L_VERSION_CURRENT,
92 		.count = FTL_P2L_VERSION_CURRENT,
93 		.desc = p2l_upgrade_desc,
94 	},
95 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = {
96 		.latest_ver = FTL_P2L_VERSION_CURRENT,
97 		.count = FTL_P2L_VERSION_CURRENT,
98 		.desc = p2l_upgrade_desc,
99 	},
100 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = {
101 		.latest_ver = FTL_P2L_VERSION_CURRENT,
102 		.count = FTL_P2L_VERSION_CURRENT,
103 		.desc = p2l_upgrade_desc,
104 	},
105 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = {
106 		.latest_ver = FTL_P2L_VERSION_CURRENT,
107 		.count = FTL_P2L_VERSION_CURRENT,
108 		.desc = p2l_upgrade_desc,
109 	},
110 	[FTL_LAYOUT_REGION_TYPE_TRIM_MD] = {},
111 	[FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = {},
112 
113 	[FTL_LAYOUT_REGION_TYPE_TRIM_LOG] = {
114 		.latest_ver = FTL_TRIM_LOG_VERSION_CURRENT,
115 		.count = FTL_TRIM_LOG_VERSION_CURRENT,
116 		.desc = trim_log_upgrade_desc,
117 	},
118 	[FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR] = {
119 		.latest_ver = FTL_TRIM_LOG_VERSION_CURRENT,
120 		.count = FTL_TRIM_LOG_VERSION_CURRENT,
121 		.desc = trim_log_upgrade_desc,
122 	},
123 };
124 
125 SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) ==
126 		   FTL_LAYOUT_REGION_TYPE_MAX,
127 		   "Missing layout upgrade descriptors");
128 #endif
129 
130 uint64_t
131 ftl_layout_upgrade_get_latest_version(enum ftl_layout_region_type reg_type)
132 {
133 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
134 	return layout_upgrade_desc[reg_type].latest_ver;
135 }
136 
137 static int
138 region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
139 {
140 	uint64_t ver;
141 
142 	assert(ctx->reg);
143 	ver = ctx->reg->current.version;
144 	if (ver > ctx->upgrade->latest_ver) {
145 		FTL_ERRLOG(dev, "Unknown region version\n");
146 		return -1;
147 	}
148 
149 	while (ver < ctx->upgrade->latest_ver) {
150 		int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg);
151 		if (rc) {
152 			return rc;
153 		}
154 		ftl_bug(ver > ctx->upgrade->desc[ver].new_version);
155 		ftl_bug(ctx->upgrade->desc[ver].new_version > ctx->upgrade->latest_ver);
156 		ver = ctx->upgrade->desc[ver].new_version;
157 	}
158 	return 0;
159 }
160 
161 int
162 ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
163 {
164 	int rc = 0;
165 	uint64_t ver;
166 
167 	assert(ctx->reg);
168 	assert(ctx->reg->current.version <= ctx->upgrade->latest_ver);
169 	ver = ctx->reg->current.version;
170 	if (ver < ctx->upgrade->latest_ver) {
171 		ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version;
172 		rc = ctx->upgrade->desc[ver].upgrade(dev, ctx);
173 	}
174 	return rc;
175 }
176 
177 void
178 ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx,
179 			     uint64_t entry_size, uint64_t num_entries, int status)
180 {
181 	int rc;
182 
183 	assert(ctx->reg);
184 	assert(ctx->reg->current.version < ctx->next_reg_ver);
185 	assert(ctx->next_reg_ver <= ctx->upgrade->latest_ver);
186 
187 	if (!status) {
188 		if (ctx->reg->type != FTL_LAYOUT_REGION_TYPE_SB) {
189 			/* Superblock region is always default-created in the latest version - see ftl_layout_setup_superblock() */
190 			rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg, ctx->next_reg_ver);
191 			if (entry_size && num_entries) {
192 				dev->layout.region[ctx->reg->type].entry_size = entry_size;
193 				dev->layout.region[ctx->reg->type].num_entries = num_entries;
194 			}
195 
196 			ftl_bug(rc != 0);
197 		}
198 
199 		ctx->reg->current.version = ctx->next_reg_ver;
200 	}
201 
202 	if (ctx->cb) {
203 		ctx->cb(dev, ctx->cb_ctx, status);
204 	}
205 }
206 
207 int
208 ftl_layout_verify(struct spdk_ftl_dev *dev)
209 {
210 	struct ftl_layout *layout = &dev->layout;
211 	struct ftl_layout_upgrade_ctx ctx = {0};
212 	enum ftl_layout_region_type reg_type;
213 
214 	/**
215 	 * Upon SB upgrade some MD regions may be missing in the MD layout blob - e.g. v3 to v5, FTL_LAYOUT_REGION_TYPE_DATA_BASE.
216 	 * The regions couldn't have be added in the SB upgrade path, as the FTL layout wasn't initialized at that point.
217 	 * Now that the FTL layout is initialized, add the missing regions and store the MD layout blob again.
218 	 */
219 
220 	if (ftl_validate_regions(dev, layout)) {
221 		return -1;
222 	}
223 
224 	for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) {
225 		ctx.reg = ftl_layout_region_get(dev, reg_type);
226 		ctx.upgrade = &layout_upgrade_desc[reg_type];
227 		if (!ctx.reg) {
228 			continue;
229 		}
230 
231 		if (region_verify(dev, &ctx)) {
232 			return -1;
233 		}
234 	}
235 
236 	return 0;
237 }
238 
239 int
240 ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev)
241 {
242 	if (ftl_validate_regions(dev, &dev->layout)) {
243 		return -1;
244 	}
245 
246 	ftl_layout_dump(dev);
247 	ftl_superblock_md_layout_dump(dev);
248 	return 0;
249 }
250 
251 int
252 ftl_superblock_upgrade(struct spdk_ftl_dev *dev)
253 {
254 	struct ftl_layout_upgrade_ctx ctx = {0};
255 	struct ftl_layout_region *reg = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_SB);
256 	int rc;
257 
258 	ctx.reg = reg;
259 	ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB];
260 	reg->current.version = dev->sb->header.version;
261 
262 	rc = region_verify(dev, &ctx);
263 	if (rc) {
264 		return rc;
265 	}
266 
267 	while (reg->current.version < ctx.upgrade->latest_ver) {
268 		rc = ftl_region_upgrade(dev, &ctx);
269 		if (rc) {
270 			return rc;
271 		}
272 		/* SB upgrades are all synchronous */
273 		ftl_region_upgrade_completed(dev, &ctx, 0, 0, rc);
274 	}
275 
276 	/* The mirror shares the same DMA buf, so it is automatically updated upon SB store */
277 	dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.version = reg->current.version;
278 	return 0;
279 }
280 
281 static int
282 layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
283 {
284 	struct ftl_layout_region *reg;
285 	uint64_t reg_ver, reg_latest_ver;
286 	uint32_t reg_type = ctx->reg->type;
287 
288 	while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) {
289 		assert(ctx->reg);
290 		assert(ctx->upgrade);
291 		reg = ctx->reg;
292 		reg_latest_ver = ctx->upgrade->latest_ver;
293 		reg_ver = reg->current.version;
294 
295 		if (reg_ver == reg_latest_ver || reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) {
296 			/* select the next region to upgrade */
297 			reg_type++;
298 			if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) {
299 				break;
300 			}
301 			ctx->reg++;
302 			ctx->upgrade++;
303 		} else if (reg_ver < reg_latest_ver) {
304 			/* qualify region version to upgrade */
305 			return FTL_LAYOUT_UPGRADE_CONTINUE;
306 		} else {
307 			/* unknown version */
308 			assert(reg_ver <= reg_latest_ver);
309 			FTL_ERRLOG(dev, "Region %d upgrade fault: version %"PRIu64"/%"PRIu64"\n", reg_type, reg_ver,
310 				   reg_latest_ver);
311 			return FTL_LAYOUT_UPGRADE_FAULT;
312 		}
313 	}
314 
315 	return FTL_LAYOUT_UPGRADE_DONE;
316 }
317 
318 int
319 ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
320 {
321 	if (!ctx->reg) {
322 		ctx->reg = ftl_layout_region_get(dev, 0);
323 		ctx->upgrade = &layout_upgrade_desc[0];
324 		SPDK_STATIC_ASSERT(FTL_LAYOUT_REGION_TYPE_SB == 0, "Invalid SB region type");
325 	}
326 
327 	return layout_upgrade_select_next_region(dev, ctx);
328 }
329 
330 uint64_t
331 ftl_layout_upgrade_region_get_latest_version(enum ftl_layout_region_type reg_type)
332 {
333 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
334 	return layout_upgrade_desc[reg_type].latest_ver;
335 }
336 
337 int
338 ftl_layout_upgrade_drop_region(struct spdk_ftl_dev *dev,
339 			       struct ftl_layout_tracker_bdev *layout_tracker,
340 			       enum ftl_layout_region_type reg_type, uint32_t reg_ver)
341 {
342 	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
343 	int rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg_type, reg_ver);
344 
345 	ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, &reg_search_ctx);
346 	if (reg_search_ctx) {
347 		FTL_ERRLOG(dev,
348 			   "Error when dropping region type %"PRId32", ver %"PRIu32": rc:%"PRId32" but found reg ver %"PRIu32"\n",
349 			   reg_type, reg_ver, rc, reg_search_ctx->ver);
350 		return -1;
351 	}
352 	dev->layout.region[reg_type].type = FTL_LAYOUT_REGION_TYPE_INVALID;
353 	return 0;
354 }
355