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