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