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 : : }
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 : 6 : ftl_region_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
40 : : {
41 [ + - - + ]: 6 : 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 : 6 : 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 : 36 : region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
139 : : {
140 : : uint64_t ver;
141 : :
142 [ - + ]: 36 : assert(ctx->reg);
143 : 36 : ver = ctx->reg->current.version;
144 [ - + ]: 36 : if (ver > ctx->upgrade->latest_ver) {
145 [ # # ]: 0 : FTL_ERRLOG(dev, "Unknown region version\n");
146 : 0 : return -1;
147 : : }
148 : :
149 [ + + ]: 42 : while (ver < ctx->upgrade->latest_ver) {
150 : 6 : int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg);
151 [ - + ]: 6 : if (rc) {
152 : 0 : return rc;
153 : : }
154 [ - + ]: 6 : ftl_bug(ver > ctx->upgrade->desc[ver].new_version);
155 [ - + ]: 6 : ftl_bug(ctx->upgrade->desc[ver].new_version > ctx->upgrade->latest_ver);
156 : 6 : ver = ctx->upgrade->desc[ver].new_version;
157 : : }
158 : 36 : return 0;
159 : : }
160 : :
161 : : int
162 : 6 : ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
163 : : {
164 : 6 : int rc = 0;
165 : : uint64_t ver;
166 : :
167 [ - + ]: 6 : assert(ctx->reg);
168 [ - + ]: 6 : assert(ctx->reg->current.version <= ctx->upgrade->latest_ver);
169 : 6 : ver = ctx->reg->current.version;
170 [ + - ]: 6 : if (ver < ctx->upgrade->latest_ver) {
171 : 6 : ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version;
172 : 6 : rc = ctx->upgrade->desc[ver].upgrade(dev, ctx);
173 : : }
174 : 6 : return rc;
175 : : }
176 : :
177 : : void
178 : 6 : 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 [ - + ]: 6 : assert(ctx->reg);
184 [ - + ]: 6 : assert(ctx->reg->current.version < ctx->next_reg_ver);
185 [ - + ]: 6 : assert(ctx->next_reg_ver <= ctx->upgrade->latest_ver);
186 : :
187 [ + - ]: 6 : if (!status) {
188 [ + - ]: 6 : 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 : 6 : rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg, ctx->next_reg_ver);
191 [ + + + - ]: 6 : if (entry_size && num_entries) {
192 : 2 : dev->layout.region[ctx->reg->type].entry_size = entry_size;
193 : 2 : dev->layout.region[ctx->reg->type].num_entries = num_entries;
194 : : }
195 : :
196 [ - + ]: 6 : ftl_bug(rc != 0);
197 : : }
198 : :
199 : 6 : ctx->reg->current.version = ctx->next_reg_ver;
200 : : }
201 : :
202 [ - + ]: 6 : if (ctx->cb) {
203 : 0 : ctx->cb(dev, ctx->cb_ctx, status);
204 : : }
205 : 6 : }
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 : 10 : 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 : 10 : uint32_t reg_type = ctx->reg->type;
287 : :
288 [ + - ]: 78 : while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) {
289 [ - + ]: 78 : assert(ctx->reg);
290 [ - + ]: 78 : assert(ctx->upgrade);
291 : 78 : reg = ctx->reg;
292 : 78 : reg_latest_ver = ctx->upgrade->latest_ver;
293 : 78 : reg_ver = reg->current.version;
294 : :
295 [ + + - + ]: 78 : if (reg_ver == reg_latest_ver || reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) {
296 : : /* select the next region to upgrade */
297 : 72 : reg_type++;
298 [ + + ]: 72 : if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) {
299 : 4 : break;
300 : : }
301 : 68 : ctx->reg++;
302 : 68 : ctx->upgrade++;
303 [ + - ]: 6 : } else if (reg_ver < reg_latest_ver) {
304 : : /* qualify region version to upgrade */
305 : 6 : 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 : 4 : 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 : 82 : ftl_layout_upgrade_region_get_latest_version(enum ftl_layout_region_type reg_type)
332 : : {
333 [ - + ]: 82 : assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
334 : 82 : 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 : : }
|