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