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 3 : ftl_region_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
22 : {
23 3 : 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 3 : return 0;
28 : }
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 16 : region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
102 : {
103 : uint64_t ver;
104 :
105 16 : assert(ctx->reg);
106 16 : ver = ctx->reg->current.version;
107 16 : if (ver > ctx->upgrade->latest_ver) {
108 0 : FTL_ERRLOG(dev, "Unknown region version\n");
109 0 : return -1;
110 : }
111 :
112 19 : while (ver < ctx->upgrade->latest_ver) {
113 3 : int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg);
114 3 : if (rc) {
115 0 : return rc;
116 : }
117 3 : ftl_bug(ver > ctx->upgrade->desc[ver].new_version);
118 3 : ftl_bug(ctx->upgrade->desc[ver].new_version > ctx->upgrade->latest_ver);
119 3 : ver = ctx->upgrade->desc[ver].new_version;
120 : }
121 16 : return 0;
122 : }
123 :
124 : int
125 3 : ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
126 : {
127 3 : int rc = 0;
128 : uint64_t ver;
129 :
130 3 : assert(ctx->reg);
131 3 : assert(ctx->reg->current.version <= ctx->upgrade->latest_ver);
132 3 : ver = ctx->reg->current.version;
133 3 : if (ver < ctx->upgrade->latest_ver) {
134 3 : ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version;
135 3 : rc = ctx->upgrade->desc[ver].upgrade(dev, ctx);
136 : }
137 3 : return rc;
138 : }
139 :
140 : void
141 3 : 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 : int rc;
145 :
146 3 : assert(ctx->reg);
147 3 : assert(ctx->reg->current.version < ctx->next_reg_ver);
148 3 : assert(ctx->next_reg_ver <= ctx->upgrade->latest_ver);
149 :
150 3 : if (!status) {
151 3 : 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 3 : rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg, ctx->next_reg_ver);
154 3 : if (entry_size && num_entries) {
155 1 : dev->layout.region[ctx->reg->type].entry_size = entry_size;
156 1 : dev->layout.region[ctx->reg->type].num_entries = num_entries;
157 : }
158 :
159 3 : ftl_bug(rc != 0);
160 : }
161 :
162 3 : ctx->reg->current.version = ctx->next_reg_ver;
163 : }
164 :
165 3 : if (ctx->cb) {
166 0 : ctx->cb(dev, ctx->cb_ctx, status);
167 : }
168 3 : }
169 :
170 : int
171 0 : ftl_layout_verify(struct spdk_ftl_dev *dev)
172 : {
173 0 : struct ftl_layout *layout = &dev->layout;
174 0 : struct ftl_layout_upgrade_ctx ctx = {0};
175 : 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 0 : if (ftl_validate_regions(dev, layout)) {
184 0 : return -1;
185 : }
186 :
187 0 : for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) {
188 0 : ctx.reg = ftl_layout_region_get(dev, reg_type);
189 0 : ctx.upgrade = &layout_upgrade_desc[reg_type];
190 0 : if (!ctx.reg) {
191 0 : continue;
192 : }
193 :
194 0 : if (region_verify(dev, &ctx)) {
195 0 : return -1;
196 : }
197 : }
198 :
199 0 : return 0;
200 : }
201 :
202 : int
203 0 : ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev)
204 : {
205 0 : if (ftl_validate_regions(dev, &dev->layout)) {
206 0 : return -1;
207 : }
208 :
209 0 : ftl_layout_dump(dev);
210 0 : ftl_superblock_md_layout_dump(dev);
211 0 : return 0;
212 : }
213 :
214 : int
215 0 : ftl_superblock_upgrade(struct spdk_ftl_dev *dev)
216 : {
217 0 : struct ftl_layout_upgrade_ctx ctx = {0};
218 0 : struct ftl_layout_region *reg = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_SB);
219 : int rc;
220 :
221 0 : ctx.reg = reg;
222 0 : ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB];
223 0 : reg->current.version = dev->sb->header.version;
224 :
225 0 : rc = region_verify(dev, &ctx);
226 0 : if (rc) {
227 0 : return rc;
228 : }
229 :
230 0 : 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 0 : dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.version = reg->current.version;
241 0 : return 0;
242 : }
243 :
244 : static int
245 5 : layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
246 : {
247 : struct ftl_layout_region *reg;
248 : uint64_t reg_ver, reg_latest_ver;
249 5 : uint32_t reg_type = ctx->reg->type;
250 :
251 35 : while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) {
252 35 : assert(ctx->reg);
253 35 : assert(ctx->upgrade);
254 35 : reg = ctx->reg;
255 35 : reg_latest_ver = ctx->upgrade->latest_ver;
256 35 : reg_ver = reg->current.version;
257 :
258 35 : if (reg_ver == reg_latest_ver || reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) {
259 : /* select the next region to upgrade */
260 32 : reg_type++;
261 32 : if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) {
262 2 : break;
263 : }
264 30 : ctx->reg++;
265 30 : ctx->upgrade++;
266 3 : } else if (reg_ver < reg_latest_ver) {
267 : /* qualify region version to upgrade */
268 3 : 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 2 : return FTL_LAYOUT_UPGRADE_DONE;
279 : }
280 :
281 : int
282 0 : ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
283 : {
284 0 : if (!ctx->reg) {
285 0 : ctx->reg = ftl_layout_region_get(dev, 0);
286 0 : ctx->upgrade = &layout_upgrade_desc[0];
287 : static_assert(FTL_LAYOUT_REGION_TYPE_SB == 0, "Invalid SB region type");
288 : }
289 :
290 0 : return layout_upgrade_select_next_region(dev, ctx);
291 : }
292 :
293 : uint64_t
294 37 : ftl_layout_upgrade_region_get_latest_version(enum ftl_layout_region_type reg_type)
295 : {
296 37 : assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
297 37 : return layout_upgrade_desc[reg_type].latest_ver;
298 : }
|