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