xref: /spdk/lib/ftl/upgrade/ftl_layout_upgrade.c (revision 588dfe314bb83d86effdf67ec42837b11c2620bf)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2022 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "ftl_layout_upgrade.h"
7 #include "ftl_layout.h"
8 #include "ftl_sb_current.h"
9 #include "ftl_sb_prev.h"
10 #include "ftl_core.h"
11 #include "ftl_band.h"
12 
13 int
14 ftl_region_upgrade_disabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
15 {
16 	return -1;
17 }
18 
19 int
20 ftl_region_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
21 {
22 	if (!(dev->sb->clean == 1 && dev->sb_shm->shm_clean == 0)) {
23 		FTL_ERRLOG(dev, "FTL region upgrade: SB dirty\n");
24 		return -1;
25 	}
26 	return 0;
27 }
28 
29 #ifndef UTEST
30 extern struct ftl_region_upgrade_desc sb_upgrade_desc[];
31 extern struct ftl_region_upgrade_desc p2l_upgrade_desc[];
32 extern struct ftl_region_upgrade_desc nvc_upgrade_desc[];
33 extern struct ftl_region_upgrade_desc band_upgrade_desc[];
34 
35 static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = {
36 	[FTL_LAYOUT_REGION_TYPE_SB] = {
37 		.count = FTL_SB_VERSION_CURRENT,
38 		.desc = sb_upgrade_desc,
39 	},
40 	[FTL_LAYOUT_REGION_TYPE_SB_BASE] = {
41 		.count = FTL_SB_VERSION_CURRENT,
42 		.desc = sb_upgrade_desc,
43 	},
44 	[FTL_LAYOUT_REGION_TYPE_L2P] = {},
45 	[FTL_LAYOUT_REGION_TYPE_BAND_MD] = {
46 		.count = FTL_BAND_VERSION_CURRENT,
47 		.desc = band_upgrade_desc,
48 	},
49 	[FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = {
50 		.count = FTL_BAND_VERSION_CURRENT,
51 		.desc = band_upgrade_desc,
52 	},
53 	[FTL_LAYOUT_REGION_TYPE_VALID_MAP] = {},
54 	[FTL_LAYOUT_REGION_TYPE_NVC_MD] = {
55 		.count = FTL_NVC_VERSION_CURRENT,
56 		.desc = nvc_upgrade_desc,
57 	},
58 	[FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = {
59 		.count = FTL_NVC_VERSION_CURRENT,
60 		.desc = nvc_upgrade_desc,
61 	},
62 	[FTL_LAYOUT_REGION_TYPE_DATA_NVC] = {},
63 	[FTL_LAYOUT_REGION_TYPE_DATA_BASE] = {},
64 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = {
65 		.count = FTL_P2L_VERSION_CURRENT,
66 		.desc = p2l_upgrade_desc,
67 	},
68 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = {
69 		.count = FTL_P2L_VERSION_CURRENT,
70 		.desc = p2l_upgrade_desc,
71 	},
72 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = {
73 		.count = FTL_P2L_VERSION_CURRENT,
74 		.desc = p2l_upgrade_desc,
75 	},
76 	[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = {
77 		.count = FTL_P2L_VERSION_CURRENT,
78 		.desc = p2l_upgrade_desc,
79 	},
80 	[FTL_LAYOUT_REGION_TYPE_TRIM_MD] = {},
81 	[FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = {},
82 #ifdef SPDK_FTL_VSS_EMU
83 	[FTL_LAYOUT_REGION_TYPE_VSS] = {},
84 #endif
85 };
86 
87 SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) ==
88 		   FTL_LAYOUT_REGION_TYPE_MAX,
89 		   "Missing layout upgrade descriptors");
90 #endif
91 
92 static int
93 region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
94 {
95 	uint64_t ver;
96 
97 	assert(ctx->reg);
98 	assert(ctx->reg->current.version == ctx->upgrade->count);
99 	ver = ctx->reg->prev.version;
100 	if (ver > ctx->upgrade->count) {
101 		FTL_ERRLOG(dev, "Unknown region version\n");
102 		return -1;
103 	}
104 
105 	while (ver < ctx->reg->current.version) {
106 		int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg);
107 		if (rc) {
108 			return rc;
109 		}
110 		ver = ctx->upgrade->desc[ver].new_version;
111 	}
112 	return 0;
113 }
114 
115 int
116 ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
117 {
118 	int rc = 0;
119 	uint64_t ver;
120 
121 	assert(ctx->reg);
122 	assert(ctx->reg->prev.version <= ctx->reg->current.version);
123 	assert(ctx->reg->current.version == ctx->upgrade->count);
124 	ver = ctx->reg->prev.version;
125 	if (ver < ctx->upgrade->count) {
126 		ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version;
127 		rc = ctx->upgrade->desc[ver].upgrade(dev, ctx);
128 	}
129 	return rc;
130 }
131 
132 void
133 ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx,
134 			     int status)
135 {
136 	assert(ctx->reg);
137 	assert(ctx->reg->prev.version < ctx->next_reg_ver);
138 	assert(ctx->next_reg_ver <= ctx->reg->current.version);
139 
140 	/* SB MD isn't tracked in SB MD region list */
141 	if (!status) {
142 		if (ctx->reg->prev.sb_md_reg) {
143 			int rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg->prev.sb_md_reg, ctx->next_reg_ver);
144 			ftl_bug(rc != 0);
145 		}
146 
147 		ctx->reg->prev.version = ctx->next_reg_ver;
148 	}
149 
150 	if (ctx->cb) {
151 		ctx->cb(dev, ctx->cb_ctx, status);
152 	}
153 }
154 
155 int
156 ftl_layout_verify(struct spdk_ftl_dev *dev)
157 {
158 	int rc = 0;
159 	struct ftl_layout *layout = &dev->layout;
160 	struct ftl_layout_upgrade_ctx ctx = {0};
161 
162 	if (ftl_superblock_md_layout_is_empty(dev->sb)) {
163 		rc = ftl_superblock_md_layout_build(dev);
164 		goto exit;
165 	}
166 
167 	if (ftl_superblock_md_layout_load_all(dev)) {
168 		return -1;
169 	}
170 
171 	if (ftl_validate_regions(dev, layout)) {
172 		return -1;
173 	}
174 
175 	ctx.reg = &dev->layout.region[0];
176 	ctx.upgrade = &layout_upgrade_desc[0];
177 
178 	while (true) {
179 		if (region_verify(dev, &ctx)) {
180 			return -1;
181 		}
182 
183 		if (ctx.reg->type == FTL_LAYOUT_REGION_TYPE_MAX - 1) {
184 			break;
185 		}
186 
187 		ctx.reg++;
188 		ctx.upgrade++;
189 	}
190 
191 exit:
192 	return rc;
193 }
194 
195 int
196 ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev)
197 {
198 	if (ftl_validate_regions(dev, &dev->layout)) {
199 		return -1;
200 	}
201 
202 	ftl_layout_dump(dev);
203 	ftl_superblock_md_layout_dump(dev);
204 	return 0;
205 }
206 
207 int
208 ftl_superblock_upgrade(struct spdk_ftl_dev *dev)
209 {
210 	struct ftl_layout_upgrade_ctx ctx = {0};
211 	struct ftl_layout_region *reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB];
212 	int rc;
213 
214 	ctx.reg = reg;
215 	ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB];
216 	reg->prev.version = dev->sb->header.version;
217 
218 	rc = region_verify(dev, &ctx);
219 	if (rc) {
220 		return rc;
221 	}
222 
223 	while (reg->prev.version < reg->current.version) {
224 		rc = ftl_region_upgrade(dev, &ctx);
225 		if (rc) {
226 			return rc;
227 		}
228 		/* SB upgrades are all synchronous */
229 		ftl_region_upgrade_completed(dev, &ctx, rc);
230 	}
231 
232 	dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].prev.version = reg->prev.version;
233 	return 0;
234 }
235 
236 static int
237 layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
238 {
239 	struct ftl_layout_region *reg;
240 	uint64_t reg_ver;
241 	uint32_t reg_type = ctx->reg->type;
242 
243 	while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) {
244 		assert(ctx->reg);
245 		assert(ctx->upgrade);
246 		reg = ctx->reg;
247 		reg_ver = reg->prev.version;
248 
249 		if (reg_ver < reg->current.version) {
250 			/* qualify region version to upgrade */
251 			return FTL_LAYOUT_UPGRADE_CONTINUE;
252 		} else if (reg_ver == reg->current.version) {
253 			/* select the next region to upgrade */
254 			reg_type++;
255 			if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) {
256 				break;
257 			}
258 			ctx->reg++;
259 			ctx->upgrade++;
260 		} else {
261 			/* unknown version */
262 			assert(reg_ver > reg->current.version);
263 			FTL_ERRLOG(dev, "Region %d upgrade fault: version %"PRIu64"/%"PRIu64"\n", reg_type, reg_ver,
264 				   reg->current.version);
265 			return FTL_LAYOUT_UPGRADE_FAULT;
266 		}
267 	}
268 
269 	return FTL_LAYOUT_UPGRADE_DONE;
270 }
271 
272 int
273 ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
274 {
275 	if (!ctx->reg) {
276 		ctx->reg = &dev->layout.region[0];
277 		ctx->upgrade = &layout_upgrade_desc[0];
278 	}
279 
280 	return layout_upgrade_select_next_region(dev, ctx);
281 }
282