Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright 2023 Solidigm All Rights Reserved
3 : * All rights reserved.
4 : */
5 :
6 : #include "spdk/string.h"
7 :
8 : #include "ftl_sb_v5.h"
9 : #include "ftl_core.h"
10 : #include "ftl_layout.h"
11 : #include "ftl_band.h"
12 : #include "upgrade/ftl_sb_prev.h"
13 : #include "upgrade/ftl_sb_upgrade.h"
14 : #include "upgrade/ftl_layout_upgrade.h"
15 : #include "utils/ftl_layout_tracker_bdev.h"
16 :
17 : typedef size_t (*blob_store_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz);
18 : typedef int (*blob_load_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz);
19 :
20 : bool
21 4 : ftl_superblock_v5_is_blob_area_empty(union ftl_superblock_ver *sb_ver)
22 : {
23 4 : return sb_ver->v5.blob_area_end == 0;
24 : }
25 :
26 : static bool
27 0 : validate_blob_area(struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr,
28 : ftl_df_obj_id sb_blob_area_end)
29 : {
30 0 : return sb_blob_hdr->df_id <= sb_blob_area_end &&
31 0 : (sb_blob_hdr->df_id + sb_blob_hdr->blob_sz) <= sb_blob_area_end;
32 : }
33 :
34 : bool
35 0 : ftl_superblock_v5_validate_blob_area(struct spdk_ftl_dev *dev)
36 : {
37 0 : union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)dev->sb;
38 :
39 0 : return validate_blob_area(&sb_ver->v5.md_layout_nvc, sb_ver->v5.blob_area_end) &&
40 0 : validate_blob_area(&sb_ver->v5.md_layout_base, sb_ver->v5.blob_area_end) &&
41 0 : validate_blob_area(&sb_ver->v5.layout_params, sb_ver->v5.blob_area_end);
42 : }
43 :
44 : static size_t
45 6 : sb_blob_store(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr,
46 : blob_store_fn blob_store, void *sb_blob_area)
47 : {
48 6 : struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;
49 6 : uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE;
50 6 : size_t blob_sz = sb_end - (uintptr_t)sb_blob_area;
51 :
52 : /* Test SB blob area overflow */
53 6 : if ((uintptr_t)sb_blob_area < (uintptr_t)sb->blob_area) {
54 0 : ftl_bug(true);
55 : return 0;
56 : }
57 6 : if ((uintptr_t)sb_blob_area >= sb_end) {
58 0 : ftl_bug(true);
59 : return 0;
60 : }
61 :
62 6 : blob_sz = blob_store(dev, sb_blob_area, blob_sz);
63 6 : sb_blob_hdr->blob_sz = blob_sz;
64 6 : sb_blob_hdr->df_id = ftl_df_get_obj_id(sb->blob_area, sb_blob_area);
65 6 : return blob_sz;
66 : }
67 :
68 : static size_t
69 2 : base_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz)
70 : {
71 2 : return ftl_layout_tracker_bdev_blob_store(dev->base_layout_tracker, blob_buf, blob_buf_sz);
72 : }
73 :
74 : static size_t
75 2 : nvc_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz)
76 : {
77 2 : return ftl_layout_tracker_bdev_blob_store(dev->nvc_layout_tracker, blob_buf, blob_buf_sz);
78 : }
79 :
80 : int
81 2 : ftl_superblock_v5_store_blob_area(struct spdk_ftl_dev *dev)
82 : {
83 2 : struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;
84 : void *sb_blob_area;
85 : size_t blob_sz;
86 :
87 : /* Store the NVC-backed FTL MD layout info */
88 2 : sb_blob_area = ftl_df_get_obj_ptr(sb->blob_area, 0);
89 2 : spdk_strcpy_pad(sb->nvc_dev_name, dev->nv_cache.nvc_type->name,
90 : SPDK_COUNTOF(sb->nvc_dev_name), '\0');
91 2 : blob_sz = sb_blob_store(dev, &sb->md_layout_nvc, nvc_blob_store, sb_blob_area);
92 2 : FTL_NOTICELOG(dev, "nvc layout blob store 0x%"PRIx64" bytes\n", blob_sz);
93 2 : if (!blob_sz) {
94 0 : return -1;
95 : }
96 :
97 : /* Store the base dev-backed FTL MD layout info */
98 2 : sb_blob_area += blob_sz;
99 2 : spdk_strcpy_pad(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name), '\0');
100 2 : blob_sz = sb_blob_store(dev, &sb->md_layout_base, base_blob_store, sb_blob_area);
101 2 : FTL_NOTICELOG(dev, "base layout blob store 0x%"PRIx64" bytes\n", blob_sz);
102 2 : if (!blob_sz) {
103 0 : return -1;
104 : }
105 :
106 : /* Store the region props */
107 2 : sb_blob_area += blob_sz;
108 2 : blob_sz = sb_blob_store(dev, &sb->layout_params, ftl_layout_blob_store, sb_blob_area);
109 2 : FTL_NOTICELOG(dev, "layout blob store 0x%"PRIx64" bytes\n", blob_sz);
110 2 : if (!blob_sz) {
111 0 : return -1;
112 : }
113 :
114 : /* Update the blob area end */
115 2 : sb_blob_area += blob_sz;
116 2 : sb->blob_area_end = ftl_df_get_obj_id(sb->blob_area, sb_blob_area);
117 :
118 2 : return 0;
119 : }
120 :
121 : static const struct ftl_layout_tracker_bdev_region_props *
122 14 : sb_md_layout_find_oldest_region(struct spdk_ftl_dev *dev,
123 : struct ftl_layout_tracker_bdev *layout_tracker,
124 : enum ftl_layout_region_type reg_type, void *find_filter)
125 : {
126 14 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
127 14 : const struct ftl_layout_tracker_bdev_region_props *reg_oldest = NULL;
128 : uint32_t ver_oldest;
129 :
130 : while (true) {
131 24 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx);
132 24 : if (!reg_search_ctx) {
133 14 : break;
134 : }
135 :
136 10 : if (!reg_oldest) {
137 7 : reg_oldest = reg_search_ctx;
138 7 : ver_oldest = reg_search_ctx->ver;
139 7 : continue;
140 : }
141 :
142 3 : ftl_bug(ver_oldest == reg_search_ctx->ver);
143 3 : if (ver_oldest > reg_search_ctx->ver) {
144 1 : reg_oldest = reg_search_ctx;
145 1 : ver_oldest = reg_search_ctx->ver;
146 : }
147 : }
148 :
149 14 : return reg_oldest;
150 : }
151 :
152 : static const struct ftl_layout_tracker_bdev_region_props *
153 10 : sb_md_layout_find_latest_region(struct spdk_ftl_dev *dev,
154 : struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type,
155 : void *find_filter)
156 : {
157 10 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
158 10 : const struct ftl_layout_tracker_bdev_region_props *reg_latest = NULL;
159 : uint32_t ver_latest;
160 :
161 : while (true) {
162 17 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx);
163 17 : if (!reg_search_ctx) {
164 10 : break;
165 : }
166 :
167 7 : if (!reg_latest) {
168 5 : reg_latest = reg_search_ctx;
169 5 : ver_latest = reg_search_ctx->ver;
170 5 : continue;
171 : }
172 :
173 2 : ftl_bug(ver_latest == reg_search_ctx->ver);
174 2 : if (ver_latest < reg_search_ctx->ver) {
175 1 : reg_latest = reg_search_ctx;
176 1 : ver_latest = reg_search_ctx->ver;
177 : }
178 : }
179 :
180 10 : return reg_latest;
181 : }
182 :
183 : static const struct ftl_layout_tracker_bdev_region_props *
184 8 : sb_md_layout_find_region_version(struct spdk_ftl_dev *dev,
185 : struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type,
186 : void *find_filter)
187 : {
188 8 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
189 8 : uint32_t *reg_ver = find_filter;
190 :
191 8 : assert(reg_ver);
192 :
193 : while (true) {
194 12 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx);
195 12 : if (!reg_search_ctx) {
196 6 : break;
197 : }
198 :
199 6 : if (reg_search_ctx->ver == *reg_ver) {
200 2 : break;
201 : }
202 : }
203 :
204 8 : return reg_search_ctx;
205 : }
206 :
207 : typedef const struct ftl_layout_tracker_bdev_region_props *(*sb_md_layout_find_fn)(
208 : struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker,
209 : enum ftl_layout_region_type reg_type, void *find_filter);
210 :
211 : static const struct ftl_layout_tracker_bdev_region_props *
212 16 : sb_md_layout_find_region(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
213 : sb_md_layout_find_fn find_fn, void *find_filter)
214 : {
215 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx;
216 16 : struct ftl_layout_tracker_bdev *nvc_layout_tracker = dev->nvc_layout_tracker;
217 16 : struct ftl_layout_tracker_bdev *base_layout_tracker = dev->base_layout_tracker;
218 :
219 16 : reg_search_ctx = find_fn(dev, nvc_layout_tracker, reg_type, find_filter);
220 16 : if (reg_search_ctx) {
221 14 : assert(find_fn(dev, base_layout_tracker, reg_type, find_filter) == NULL);
222 14 : return reg_search_ctx;
223 : }
224 :
225 2 : reg_search_ctx = find_fn(dev, base_layout_tracker, reg_type, find_filter);
226 2 : return reg_search_ctx;
227 : }
228 :
229 : static int
230 29 : sb_blob_load(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr,
231 : blob_load_fn blob_load)
232 : {
233 29 : struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;
234 29 : uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE;
235 : void *blob_area;
236 :
237 29 : if (sb_blob_hdr->df_id == FTL_DF_OBJ_ID_INVALID) {
238 : /* Uninitialized blob */
239 2 : return -1;
240 : }
241 :
242 27 : blob_area = ftl_df_get_obj_ptr(sb->blob_area, sb_blob_hdr->df_id);
243 :
244 : /* Test SB blob area overflow */
245 27 : if ((uintptr_t)blob_area < (uintptr_t)sb->blob_area) {
246 0 : ftl_bug(true);
247 : return -1;
248 : }
249 27 : if ((uintptr_t)blob_area + sb_blob_hdr->blob_sz >= sb_end) {
250 0 : ftl_bug(true);
251 : return -1;
252 : }
253 :
254 27 : return blob_load(dev, blob_area, sb_blob_hdr->blob_sz);
255 : }
256 :
257 : static int
258 8 : base_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz)
259 : {
260 8 : return ftl_layout_tracker_bdev_blob_load(dev->base_layout_tracker, blob_buf, blob_sz);
261 : }
262 :
263 : static int
264 12 : nvc_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz)
265 : {
266 12 : return ftl_layout_tracker_bdev_blob_load(dev->nvc_layout_tracker, blob_buf, blob_sz);
267 : }
268 :
269 : int
270 14 : ftl_superblock_v5_load_blob_area(struct spdk_ftl_dev *dev)
271 : {
272 14 : struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;
273 :
274 : /* Load the NVC-backed FTL MD layout info */
275 14 : if (strncmp(sb->nvc_dev_name, dev->nv_cache.nvc_type->name, SPDK_COUNTOF(sb->nvc_dev_name))) {
276 0 : return -1;
277 : }
278 14 : FTL_NOTICELOG(dev, "nvc layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->md_layout_nvc.blob_sz);
279 14 : if (sb_blob_load(dev, &sb->md_layout_nvc, nvc_blob_load)) {
280 6 : return -1;
281 : }
282 :
283 : /* Load the base dev-backed FTL MD layout info */
284 8 : if (strncmp(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name))) {
285 0 : return -1;
286 : }
287 8 : FTL_NOTICELOG(dev, "base layout blob load 0x%"PRIx64" bytes\n",
288 : (uint64_t)sb->md_layout_base.blob_sz);
289 8 : if (sb_blob_load(dev, &sb->md_layout_base, base_blob_load)) {
290 1 : return -1;
291 : }
292 :
293 : /* Load the region props */
294 7 : FTL_NOTICELOG(dev, "layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->layout_params.blob_sz);
295 7 : if (sb_blob_load(dev, &sb->layout_params, ftl_layout_blob_load)) {
296 1 : return -1;
297 : }
298 :
299 6 : return 0;
300 : }
301 :
302 : static struct ftl_layout_tracker_bdev *
303 3 : sb_get_md_layout_tracker(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg)
304 : {
305 3 : return (reg->bdev_desc == dev->base_bdev_desc) ? dev->base_layout_tracker : dev->nvc_layout_tracker;
306 : }
307 :
308 : static void
309 1 : sb_md_layout_delete_prev_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg)
310 : {
311 : int rc;
312 1 : struct ftl_layout_tracker_bdev *layout_tracker = sb_get_md_layout_tracker(dev, reg);
313 :
314 1 : rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg->type, reg->current.version);
315 : /* Version 0 indicates a placeholder for creation of a new region */
316 1 : ftl_bug(reg->current.version != 0 && rc != 0);
317 1 : }
318 :
319 : static void
320 2 : sb_md_layout_update_prev_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg,
321 : uint32_t new_version)
322 : {
323 : int rc;
324 2 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
325 2 : struct ftl_layout_tracker_bdev *layout_tracker = sb_get_md_layout_tracker(dev, reg);
326 : struct ftl_layout_tracker_bdev_region_props reg_props;
327 :
328 : /* Get region properties */
329 2 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg->type, ®_search_ctx);
330 2 : ftl_bug(reg_search_ctx == NULL);
331 2 : reg_props = *reg_search_ctx;
332 :
333 : /* Delete the region */
334 2 : rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg_props.type, reg_props.ver);
335 2 : ftl_bug(rc != 0);
336 :
337 : /* Insert the same region with new version */
338 2 : reg_search_ctx = ftl_layout_tracker_bdev_insert_region(layout_tracker, reg_props.type, new_version,
339 : reg_props.blk_offs, reg_props.blk_sz);
340 2 : ftl_bug(reg_search_ctx == NULL);
341 :
342 : /* Verify the oldest region version stored in the SB is the new_version */
343 2 : reg_search_ctx = sb_md_layout_find_region(dev, reg_props.type, sb_md_layout_find_oldest_region,
344 : NULL);
345 2 : ftl_bug(reg_search_ctx == NULL);
346 2 : ftl_bug(reg_search_ctx->ver != new_version);
347 2 : }
348 :
349 : int
350 3 : ftl_superblock_v5_md_layout_upgrade_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg,
351 : uint32_t new_version)
352 : {
353 3 : const struct ftl_layout_tracker_bdev_region_props *reg_next = NULL;
354 : uint64_t latest_ver;
355 :
356 3 : ftl_bug(reg->current.version >= new_version);
357 :
358 3 : reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_region_version, &new_version);
359 3 : if (reg_next) {
360 : /**
361 : * Major upgrade.
362 : * Found a new MD region allocated for upgrade to the next version.
363 : * Destroy the previous version now that the upgrade is completed.
364 : */
365 1 : ftl_bug(reg_next->ver != new_version);
366 1 : ftl_bug(reg_next->type != reg->type);
367 1 : sb_md_layout_delete_prev_region(dev, reg);
368 1 : reg->current.offset = reg_next->blk_offs;
369 1 : reg->current.blocks = reg_next->blk_sz;
370 : } else {
371 : /**
372 : * Minor upgrade.
373 : * Upgraded the MD region in place.
374 : * Update the version in place.
375 : */
376 2 : sb_md_layout_update_prev_region(dev, reg, new_version);
377 : }
378 :
379 3 : reg->current.version = new_version;
380 3 : latest_ver = ftl_layout_upgrade_region_get_latest_version(reg->type);
381 3 : if (new_version == latest_ver) {
382 : /* Audit the only region version stored in the SB */
383 1 : reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_latest_region, NULL);
384 1 : ftl_bug(reg_next == NULL);
385 1 : ftl_bug(reg_next->ver != new_version);
386 :
387 1 : reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_oldest_region, NULL);
388 1 : ftl_bug(reg_next == NULL);
389 1 : ftl_bug(reg_next->ver != new_version);
390 :
391 1 : reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_region_version, &new_version);
392 1 : ftl_bug(reg->type != reg_next->type);
393 1 : ftl_bug(reg->current.version != reg_next->ver);
394 1 : ftl_bug(reg->current.offset != reg_next->blk_offs);
395 1 : ftl_bug(reg->current.blocks != reg_next->blk_sz);
396 : }
397 :
398 3 : return 0;
399 : }
400 :
401 : void
402 0 : ftl_superblock_v5_md_layout_dump(struct spdk_ftl_dev *dev)
403 : {
404 0 : struct ftl_layout_tracker_bdev *nvc_layout_tracker = dev->nvc_layout_tracker;
405 0 : struct ftl_layout_tracker_bdev *base_layout_tracker = dev->base_layout_tracker;
406 0 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
407 :
408 0 : FTL_NOTICELOG(dev, "SB metadata layout - nvc:\n");
409 : while (true) {
410 0 : ftl_layout_tracker_bdev_find_next_region(nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID,
411 : ®_search_ctx);
412 0 : if (!reg_search_ctx) {
413 0 : break;
414 : }
415 :
416 0 : FTL_NOTICELOG(dev,
417 : "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n",
418 : reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz);
419 : }
420 :
421 0 : reg_search_ctx = NULL;
422 0 : FTL_NOTICELOG(dev, "SB metadata layout - base dev:\n");
423 : while (true) {
424 0 : ftl_layout_tracker_bdev_find_next_region(base_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID,
425 : ®_search_ctx);
426 0 : if (!reg_search_ctx) {
427 0 : break;
428 : }
429 :
430 0 : FTL_NOTICELOG(dev,
431 : "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n",
432 : reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz);
433 : }
434 0 : }
435 :
436 : static int
437 0 : layout_apply_from_sb_blob(struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker,
438 : int (*filter_region_type_fn)(enum ftl_layout_region_type))
439 : {
440 : struct ftl_layout_region *reg;
441 0 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
442 :
443 : while (true) {
444 0 : ftl_layout_tracker_bdev_find_next_region(layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID,
445 : ®_search_ctx);
446 0 : if (!reg_search_ctx) {
447 0 : break;
448 : }
449 0 : if (reg_search_ctx->type == FTL_LAYOUT_REGION_TYPE_FREE) {
450 0 : continue;
451 : }
452 0 : if (filter_region_type_fn(reg_search_ctx->type)) {
453 0 : FTL_ERRLOG(dev, "Unknown region found in layout blob: type 0x%"PRIx32"\n", reg_search_ctx->type);
454 0 : return -1;
455 : }
456 :
457 0 : reg = &dev->layout.region[reg_search_ctx->type];
458 :
459 : /* First region of a given type found */
460 0 : if (reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) {
461 0 : reg->type = reg_search_ctx->type;
462 0 : reg->current.version = reg_search_ctx->ver;
463 0 : reg->current.offset = reg_search_ctx->blk_offs;
464 0 : reg->current.blocks = reg_search_ctx->blk_sz;
465 0 : continue;
466 : }
467 :
468 : /* Update to the oldest region version found */
469 0 : if (reg_search_ctx->ver < reg->current.version) {
470 0 : reg->current.version = reg_search_ctx->ver;
471 0 : reg->current.offset = reg_search_ctx->blk_offs;
472 0 : reg->current.blocks = reg_search_ctx->blk_sz;
473 0 : continue;
474 : }
475 :
476 : /* Skip newer region versions */
477 0 : if (reg_search_ctx->ver > reg->current.version) {
478 0 : continue;
479 : }
480 :
481 : /* Current region version already found */
482 0 : assert(reg_search_ctx->ver == reg->current.version);
483 0 : if (reg->current.offset != reg_search_ctx->blk_offs ||
484 0 : reg->current.blocks != reg_search_ctx->blk_sz) {
485 0 : FTL_ERRLOG(dev, "Corrupted layout blob: reg type 0x%"PRIx32"\n", reg_search_ctx->type);
486 0 : return -1;
487 : }
488 : }
489 0 : return 0;
490 : }
491 :
492 : static int
493 0 : layout_region_verify(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type)
494 : {
495 0 : struct ftl_layout_region *reg = ftl_layout_region_get(dev, reg_type);
496 0 : if (!reg) {
497 0 : return -ENOENT;
498 : }
499 :
500 : /* Unknown version found in the blob */
501 0 : if (reg->current.version > ftl_layout_upgrade_get_latest_version(reg_type)) {
502 0 : FTL_ERRLOG(dev, "Unknown region version found in layout blob: reg type 0x%"PRIx32"\n",
503 : reg_type);
504 0 : return -EINVAL;
505 : }
506 :
507 0 : return 0;
508 : }
509 :
510 : static int
511 0 : layout_fixup_reg_data_base(struct spdk_ftl_dev *dev)
512 : {
513 0 : const struct ftl_md_layout_ops *base_md_ops = &dev->base_type->ops.md_layout_ops;
514 0 : struct ftl_layout_region *reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_DATA_BASE];
515 0 : const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
516 :
517 0 : assert(reg->type == FTL_LAYOUT_REGION_TYPE_INVALID);
518 :
519 0 : FTL_NOTICELOG(dev, "Adding a region\n");
520 :
521 : /* Add the region */
522 0 : if (base_md_ops->region_create(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0,
523 : ftl_layout_base_offset(dev))) {
524 0 : return -1;
525 : }
526 0 : if (base_md_ops->region_open(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE,
527 : ftl_layout_base_offset(dev), reg)) {
528 0 : return -1;
529 : }
530 :
531 0 : ftl_layout_tracker_bdev_find_next_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_DATA_BASE,
532 : ®_search_ctx);
533 0 : assert(reg_search_ctx);
534 0 : return 0;
535 : }
536 :
537 : static int
538 0 : layout_fixup_base(struct spdk_ftl_dev *dev)
539 : {
540 : struct ftl_layout_region_descr {
541 : enum ftl_layout_region_type type;
542 : uint32_t ver;
543 : int (*on_reg_miss)(struct spdk_ftl_dev *dev);
544 : };
545 : struct ftl_layout_region_descr *reg_descr;
546 : static struct ftl_layout_region_descr nvc_regs[] = {
547 : { .type = FTL_LAYOUT_REGION_TYPE_SB_BASE, .ver = FTL_SB_VERSION_CURRENT },
548 : { .type = FTL_LAYOUT_REGION_TYPE_DATA_BASE, .ver = 0, .on_reg_miss = layout_fixup_reg_data_base },
549 : { .type = FTL_LAYOUT_REGION_TYPE_VALID_MAP, .ver = 0 },
550 : { .type = FTL_LAYOUT_REGION_TYPE_INVALID, .ver = 0 },
551 : };
552 :
553 0 : for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) {
554 : struct ftl_layout_region *region;
555 :
556 0 : if (layout_region_verify(dev, reg_descr->type) &&
557 0 : reg_descr->on_reg_miss && reg_descr->on_reg_miss(dev)) {
558 0 : return -1;
559 : }
560 :
561 0 : region = &dev->layout.region[reg_descr->type];
562 0 : region->type = reg_descr->type;
563 0 : region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
564 0 : region->name = ftl_md_region_name(reg_descr->type);
565 :
566 0 : region->bdev_desc = dev->base_bdev_desc;
567 0 : region->ioch = dev->base_ioch;
568 0 : region->vss_blksz = 0;
569 : }
570 :
571 0 : return 0;
572 : }
573 :
574 : static int
575 0 : layout_fixup_nvc(struct spdk_ftl_dev *dev)
576 : {
577 : int rc;
578 : struct ftl_layout_region_descr {
579 : enum ftl_layout_region_type type;
580 : bool deprecated;
581 : enum ftl_layout_region_type mirror_type;
582 : };
583 : struct ftl_layout_region_descr *reg_descr;
584 : static struct ftl_layout_region_descr nvc_regs[] = {
585 : { .type = FTL_LAYOUT_REGION_TYPE_SB, .mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE },
586 : { .type = FTL_LAYOUT_REGION_TYPE_L2P },
587 : { .type = FTL_LAYOUT_REGION_TYPE_BAND_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR },
588 : { .type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR },
589 : { .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR },
590 : { .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR },
591 : { .type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG, .mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR },
592 : { .type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR },
593 : { .type = FTL_LAYOUT_REGION_TYPE_NVC_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR },
594 : { .type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR },
595 : { .type = FTL_LAYOUT_REGION_TYPE_DATA_NVC, .deprecated = true },
596 : { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC },
597 : { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT },
598 : { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP },
599 : { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT },
600 : { .type = FTL_LAYOUT_REGION_TYPE_INVALID },
601 : };
602 :
603 0 : for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) {
604 : struct ftl_layout_region *region;
605 :
606 0 : rc = layout_region_verify(dev, reg_descr->type);
607 0 : if (rc == -ENOENT) {
608 0 : if (reg_descr->deprecated) {
609 0 : continue;
610 : }
611 :
612 0 : ftl_layout_upgrade_add_region_placeholder(dev, dev->nvc_layout_tracker, reg_descr->type);
613 0 : } else if (rc) {
614 0 : return -1;
615 : }
616 :
617 0 : if (reg_descr->deprecated) {
618 0 : rc = ftl_layout_upgrade_drop_region(dev, dev->nvc_layout_tracker, reg_descr->type,
619 0 : dev->layout.region[reg_descr->type].current.version);
620 0 : if (rc) {
621 0 : return rc;
622 : }
623 0 : continue;
624 : }
625 :
626 0 : region = &dev->layout.region[reg_descr->type];
627 0 : region->type = reg_descr->type;
628 0 : region->mirror_type = (reg_descr->mirror_type) ? reg_descr->mirror_type :
629 : FTL_LAYOUT_REGION_TYPE_INVALID;
630 0 : region->name = ftl_md_region_name(reg_descr->type);
631 :
632 0 : region->bdev_desc = dev->nv_cache.bdev_desc;
633 0 : region->ioch = dev->nv_cache.cache_ioch;
634 0 : region->vss_blksz = dev->nv_cache.md_size;
635 : }
636 :
637 0 : return 0;
638 : }
639 :
640 : static int
641 0 : filter_region_type_base(enum ftl_layout_region_type reg_type)
642 : {
643 0 : switch (reg_type) {
644 0 : case FTL_LAYOUT_REGION_TYPE_SB_BASE:
645 : case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
646 : case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
647 0 : return 0;
648 :
649 0 : default:
650 0 : return 1;
651 : }
652 : }
653 :
654 : static int
655 0 : filter_region_type_nvc(enum ftl_layout_region_type reg_type)
656 : {
657 0 : return filter_region_type_base(reg_type) ? 0 : 1;
658 : }
659 :
660 : static int
661 0 : layout_apply_nvc(struct spdk_ftl_dev *dev)
662 : {
663 0 : if (layout_apply_from_sb_blob(dev, dev->nvc_layout_tracker, filter_region_type_nvc) ||
664 0 : layout_fixup_nvc(dev)) {
665 0 : return -1;
666 : }
667 0 : return 0;
668 : }
669 :
670 : static int
671 0 : layout_apply_base(struct spdk_ftl_dev *dev)
672 : {
673 0 : if (layout_apply_from_sb_blob(dev, dev->base_layout_tracker, filter_region_type_base) ||
674 0 : layout_fixup_base(dev)) {
675 0 : return -1;
676 : }
677 0 : return 0;
678 : }
679 :
680 : int
681 0 : ftl_superblock_v5_md_layout_apply(struct spdk_ftl_dev *dev)
682 : {
683 0 : if (layout_apply_nvc(dev) || layout_apply_base(dev)) {
684 0 : return -1;
685 : }
686 0 : return 0;
687 : }
|