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