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