xref: /spdk/lib/ftl/upgrade/ftl_layout_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 "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 	[FTL_LAYOUT_REGION_TYPE_TRIM_LOG] = {
113 		.latest_ver = FTL_TRIM_LOG_VERSION_CURRENT,
114 		.count = FTL_TRIM_LOG_VERSION_CURRENT,
115 		.desc = trim_log_upgrade_desc,
116 	},
117 	[FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR] = {
118 		.latest_ver = FTL_TRIM_LOG_VERSION_CURRENT,
119 		.count = FTL_TRIM_LOG_VERSION_CURRENT,
120 		.desc = trim_log_upgrade_desc,
121 	},
122 	[FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN] = {},
123 	[FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX] = {},
124 };
125 
126 SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) ==
127 		   FTL_LAYOUT_REGION_TYPE_MAX,
128 		   "Missing layout upgrade descriptors");
129 #endif
130 
131 uint64_t
132 ftl_layout_upgrade_get_latest_version(enum ftl_layout_region_type reg_type)
133 {
134 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
135 	return layout_upgrade_desc[reg_type].latest_ver;
136 }
137 
138 static int
139 region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
140 {
141 	uint64_t ver;
142 
143 	assert(ctx->reg);
144 	ver = ctx->reg->current.version;
145 	if (ver > ctx->upgrade->latest_ver) {
146 		FTL_ERRLOG(dev, "Unknown region version\n");
147 		return -1;
148 	}
149 
150 	while (ver < ctx->upgrade->latest_ver) {
151 		int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg);
152 		if (rc) {
153 			return rc;
154 		}
155 		ftl_bug(ver > ctx->upgrade->desc[ver].new_version);
156 		ftl_bug(ctx->upgrade->desc[ver].new_version > ctx->upgrade->latest_ver);
157 		ver = ctx->upgrade->desc[ver].new_version;
158 	}
159 	return 0;
160 }
161 
162 int
163 ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
164 {
165 	int rc = 0;
166 	uint64_t ver;
167 
168 	assert(ctx->reg);
169 	assert(ctx->reg->current.version <= ctx->upgrade->latest_ver);
170 	ver = ctx->reg->current.version;
171 	if (ver < ctx->upgrade->latest_ver) {
172 		ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version;
173 		rc = ctx->upgrade->desc[ver].upgrade(dev, ctx);
174 	}
175 	return rc;
176 }
177 
178 void
179 ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx,
180 			     uint64_t entry_size, uint64_t num_entries, int status)
181 {
182 	int rc;
183 
184 	assert(ctx->reg);
185 	assert(ctx->reg->current.version < ctx->next_reg_ver);
186 	assert(ctx->next_reg_ver <= ctx->upgrade->latest_ver);
187 
188 	if (!status) {
189 		if (ctx->reg->type != FTL_LAYOUT_REGION_TYPE_SB) {
190 			/* Superblock region is always default-created in the latest version - see ftl_layout_setup_superblock() */
191 			rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg, ctx->next_reg_ver);
192 			if (entry_size && num_entries) {
193 				dev->layout.region[ctx->reg->type].entry_size = entry_size;
194 				dev->layout.region[ctx->reg->type].num_entries = num_entries;
195 			}
196 
197 			ftl_bug(rc != 0);
198 		}
199 
200 		ctx->reg->current.version = ctx->next_reg_ver;
201 	}
202 
203 	if (ctx->cb) {
204 		ctx->cb(dev, ctx->cb_ctx, status);
205 	}
206 }
207 
208 int
209 ftl_layout_verify(struct spdk_ftl_dev *dev)
210 {
211 	struct ftl_layout *layout = &dev->layout;
212 	struct ftl_layout_upgrade_ctx ctx = {0};
213 	enum ftl_layout_region_type reg_type;
214 
215 	/**
216 	 * 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.
217 	 * The regions couldn't have be added in the SB upgrade path, as the FTL layout wasn't initialized at that point.
218 	 * Now that the FTL layout is initialized, add the missing regions and store the MD layout blob again.
219 	 */
220 
221 	if (ftl_validate_regions(dev, layout)) {
222 		return -1;
223 	}
224 
225 	for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) {
226 		ctx.reg = ftl_layout_region_get(dev, reg_type);
227 		ctx.upgrade = &layout_upgrade_desc[reg_type];
228 		if (!ctx.reg) {
229 			continue;
230 		}
231 
232 		if (region_verify(dev, &ctx)) {
233 			return -1;
234 		}
235 	}
236 
237 	return 0;
238 }
239 
240 int
241 ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev)
242 {
243 	if (ftl_validate_regions(dev, &dev->layout)) {
244 		return -1;
245 	}
246 
247 	ftl_layout_dump(dev);
248 	ftl_superblock_md_layout_dump(dev);
249 	return 0;
250 }
251 
252 int
253 ftl_superblock_upgrade(struct spdk_ftl_dev *dev)
254 {
255 	struct ftl_layout_upgrade_ctx ctx = {0};
256 	struct ftl_layout_region *reg = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_SB);
257 	int rc;
258 
259 	ctx.reg = reg;
260 	ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB];
261 	reg->current.version = dev->sb->header.version;
262 
263 	rc = region_verify(dev, &ctx);
264 	if (rc) {
265 		return rc;
266 	}
267 
268 	while (reg->current.version < ctx.upgrade->latest_ver) {
269 		rc = ftl_region_upgrade(dev, &ctx);
270 		if (rc) {
271 			return rc;
272 		}
273 		/* SB upgrades are all synchronous */
274 		ftl_region_upgrade_completed(dev, &ctx, 0, 0, rc);
275 	}
276 
277 	/* The mirror shares the same DMA buf, so it is automatically updated upon SB store */
278 	dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.version = reg->current.version;
279 	return 0;
280 }
281 
282 static int
283 layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
284 {
285 	struct ftl_layout_region *reg;
286 	uint64_t reg_ver, reg_latest_ver;
287 	uint32_t reg_type = ctx->reg->type;
288 
289 	while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) {
290 		assert(ctx->reg);
291 		assert(ctx->upgrade);
292 		reg = ctx->reg;
293 		reg_latest_ver = ctx->upgrade->latest_ver;
294 		reg_ver = reg->current.version;
295 
296 		if (reg_ver == reg_latest_ver || reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) {
297 			/* select the next region to upgrade */
298 			reg_type++;
299 			if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) {
300 				break;
301 			}
302 			ctx->reg++;
303 			ctx->upgrade++;
304 		} else if (reg_ver < reg_latest_ver) {
305 			/* qualify region version to upgrade */
306 			return FTL_LAYOUT_UPGRADE_CONTINUE;
307 		} else {
308 			/* unknown version */
309 			assert(reg_ver <= reg_latest_ver);
310 			FTL_ERRLOG(dev, "Region %d upgrade fault: version %"PRIu64"/%"PRIu64"\n", reg_type, reg_ver,
311 				   reg_latest_ver);
312 			return FTL_LAYOUT_UPGRADE_FAULT;
313 		}
314 	}
315 
316 	return FTL_LAYOUT_UPGRADE_DONE;
317 }
318 
319 int
320 ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
321 {
322 	if (!ctx->reg) {
323 		ctx->reg = ftl_layout_region_get(dev, 0);
324 		ctx->upgrade = &layout_upgrade_desc[0];
325 		SPDK_STATIC_ASSERT(FTL_LAYOUT_REGION_TYPE_SB == 0, "Invalid SB region type");
326 	}
327 
328 	return layout_upgrade_select_next_region(dev, ctx);
329 }
330 
331 uint64_t
332 ftl_layout_upgrade_region_get_latest_version(enum ftl_layout_region_type reg_type)
333 {
334 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
335 	return layout_upgrade_desc[reg_type].latest_ver;
336 }
337 
338 int
339 ftl_layout_upgrade_drop_region(struct spdk_ftl_dev *dev,
340 			       struct ftl_layout_tracker_bdev *layout_tracker,
341 			       enum ftl_layout_region_type reg_type, uint32_t reg_ver)
342 {
343 	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
344 	int rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg_type, reg_ver);
345 
346 	ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, &reg_search_ctx);
347 	if (reg_search_ctx) {
348 		FTL_ERRLOG(dev,
349 			   "Error when dropping region type %"PRId32", ver %"PRIu32": rc:%"PRId32" but found reg ver %"PRIu32"\n",
350 			   reg_type, reg_ver, rc, reg_search_ctx->ver);
351 		return -1;
352 	}
353 	dev->layout.region[reg_type].type = FTL_LAYOUT_REGION_TYPE_INVALID;
354 	return 0;
355 }
356