xref: /spdk/lib/ftl/mngt/ftl_mngt_md.c (revision 18c8b52afa69f39481ebb75711b2f30b11693f9d)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/thread.h"
7 #include "spdk/crc32.h"
8 
9 #include "ftl_core.h"
10 #include "ftl_mngt.h"
11 #include "ftl_mngt_steps.h"
12 #include "ftl_utils.h"
13 #include "ftl_band.h"
14 #include "ftl_internal.h"
15 #include "ftl_sb.h"
16 
17 void
18 ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
19 {
20 	if (ftl_layout_setup(dev)) {
21 		ftl_mngt_fail_step(mngt);
22 	} else {
23 		ftl_mngt_next_step(mngt);
24 	}
25 }
26 
27 static bool
28 is_buffer_needed(enum ftl_layout_region_type type)
29 {
30 	switch (type) {
31 #ifdef SPDK_FTL_VSS_EMU
32 	case FTL_LAYOUT_REGION_TYPE_VSS:
33 #endif
34 	case FTL_LAYOUT_REGION_TYPE_SB:
35 	case FTL_LAYOUT_REGION_TYPE_SB_BASE:
36 	case FTL_LAYOUT_REGION_TYPE_DATA_NVC:
37 	case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
38 	case FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR:
39 	case FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR:
40 #ifndef SPDK_FTL_L2P_FLAT
41 	case FTL_LAYOUT_REGION_TYPE_L2P:
42 #endif
43 	case FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR:
44 		return false;
45 
46 	default:
47 		return true;
48 	}
49 }
50 
51 void
52 ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
53 {
54 	struct ftl_layout *layout = &dev->layout;
55 	struct ftl_layout_region *region = layout->region;
56 	uint64_t i;
57 	int md_flags;
58 
59 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
60 		if (layout->md[i]) {
61 			/*
62 			 * Some metadata objects are initialized by other FTL
63 			 * components. At the moment it's only used by superblock (and its mirror) -
64 			 * during load time we need to read it earlier in order to get the layout for the
65 			 * other regions.
66 			 */
67 			continue;
68 		}
69 		md_flags = is_buffer_needed(i) ? ftl_md_create_region_flags(dev,
70 				region->type) : FTL_MD_CREATE_NO_MEM;
71 		layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name,
72 					      md_flags, region);
73 		if (NULL == layout->md[i]) {
74 			ftl_mngt_fail_step(mngt);
75 			return;
76 		}
77 	}
78 
79 	ftl_mngt_next_step(mngt);
80 }
81 
82 void
83 ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
84 {
85 	struct ftl_layout *layout = &dev->layout;
86 	struct ftl_layout_region *region = layout->region;
87 	uint64_t i;
88 
89 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
90 		if (layout->md[i]) {
91 			ftl_md_destroy(layout->md[i], ftl_md_destroy_region_flags(dev, layout->region[i].type));
92 			layout->md[i] = NULL;
93 		}
94 	}
95 
96 	ftl_mngt_next_step(mngt);
97 }
98 
99 static void
100 persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
101 {
102 	struct ftl_mngt_process *mngt = md->owner.cb_ctx;
103 
104 	if (status) {
105 		ftl_mngt_fail_step(mngt);
106 	} else {
107 		ftl_mngt_next_step(mngt);
108 	}
109 }
110 
111 static void
112 persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
113 	enum ftl_layout_region_type type)
114 {
115 	struct ftl_layout *layout = &dev->layout;
116 	struct ftl_md *md;
117 
118 	assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
119 
120 	md = layout->md[type];
121 	if (!md) {
122 		ftl_mngt_fail_step(mngt);
123 		return;
124 	}
125 
126 	md->owner.cb_ctx = mngt;
127 	md->cb = persist_cb;
128 	ftl_md_persist(md);
129 }
130 
131 static int
132 ftl_md_restore_region(struct spdk_ftl_dev *dev, int region_type)
133 {
134 	int status = 0;
135 	switch (region_type) {
136 	case FTL_LAYOUT_REGION_TYPE_NVC_MD:
137 		status = ftl_nv_cache_load_state(&dev->nv_cache);
138 		break;
139 	case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
140 		ftl_valid_map_load_state(dev);
141 		break;
142 	case FTL_LAYOUT_REGION_TYPE_BAND_MD:
143 		ftl_bands_load_state(dev);
144 		break;
145 	default:
146 		break;
147 	}
148 	return status;
149 }
150 
151 static void
152 restore_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
153 {
154 	struct ftl_mngt_process *mngt = md->owner.cb_ctx;
155 	const struct ftl_layout_region *region = ftl_md_get_region(md);
156 
157 	if (status) {
158 		/* Restore error, end step */
159 		ftl_mngt_fail_step(mngt);
160 		return;
161 	}
162 
163 	assert(region);
164 	status = ftl_md_restore_region(dev, region->type);
165 
166 	if (status) {
167 		ftl_mngt_fail_step(mngt);
168 	} else {
169 		ftl_mngt_next_step(mngt);
170 	}
171 }
172 
173 static void
174 restore(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt, enum ftl_layout_region_type type)
175 {
176 	struct ftl_layout *layout = &dev->layout;
177 	assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
178 	struct ftl_md *md = layout->md[type];
179 
180 	if (!md) {
181 		ftl_mngt_fail_step(mngt);
182 		return;
183 	}
184 
185 	md->owner.cb_ctx = mngt;
186 	md->cb = restore_cb;
187 	ftl_md_restore(md);
188 }
189 
190 void
191 ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
192 {
193 	if (ftl_nv_cache_save_state(&dev->nv_cache)) {
194 		ftl_mngt_fail_step(mngt);
195 		return;
196 	}
197 
198 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
199 }
200 
201 static void
202 ftl_mngt_fast_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
203 {
204 	if (ftl_nv_cache_save_state(&dev->nv_cache)) {
205 		ftl_mngt_fail_step(mngt);
206 		return;
207 	}
208 	ftl_mngt_next_step(mngt);
209 }
210 
211 static void
212 ftl_mngt_persist_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
213 {
214 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
215 }
216 
217 static void
218 ftl_mngt_persist_p2l_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
219 {
220 	/* Sync runtime P2L to persist any invalidation that may have happened */
221 
222 	struct ftl_p2l_sync_ctx *ctx = ftl_mngt_get_step_ctx(mngt);
223 
224 	/*
225 	 * ftl_mngt_persist_bands_p2l will increment the md_region before the step_continue for next regions
226 	 */
227 	if (ctx->md_region <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN) {
228 		ctx->md_region = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
229 	}
230 	ftl_mngt_persist_bands_p2l(mngt);
231 }
232 
233 void
234 ftl_mngt_persist_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
235 {
236 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
237 }
238 
239 static void
240 ftl_mngt_persist_trim_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
241 {
242 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_TRIM_MD);
243 }
244 
245 static uint32_t
246 get_sb_crc(struct ftl_superblock *sb)
247 {
248 	uint32_t crc = 0;
249 
250 	/* Calculate CRC excluding CRC field in superblock */
251 	void *buffer = sb;
252 	size_t offset = offsetof(struct ftl_superblock, header.crc);
253 	size_t size = offset;
254 	crc = spdk_crc32c_update(buffer, size, crc);
255 
256 	buffer += offset + sizeof(sb->header.crc);
257 	size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc);
258 	crc = spdk_crc32c_update(buffer, size, crc);
259 
260 	return crc;
261 }
262 
263 static void
264 ftl_mngt_persist_super_block(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
265 {
266 	dev->sb->overprovisioning = dev->conf.overprovisioning;
267 	dev->sb->gc_info = dev->sb_shm->gc_info;
268 	dev->sb->header.crc = get_sb_crc(dev->sb);
269 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
270 }
271 
272 #ifdef SPDK_FTL_VSS_EMU
273 static void
274 ftl_mngt_persist_vss(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
275 {
276 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_VSS);
277 }
278 #endif
279 
280 /*
281  * Persists all necessary metadata (band state, P2L, etc) during FTL's clean shutdown.
282  */
283 static const struct ftl_mngt_process_desc desc_persist = {
284 	.name = "Persist metadata",
285 	.steps = {
286 		{
287 			.name = "Persist NV cache metadata",
288 			.action = ftl_mngt_persist_nv_cache_metadata,
289 		},
290 		{
291 			.name = "Persist valid map metadata",
292 			.action = ftl_mngt_persist_vld_map_metadata,
293 		},
294 		{
295 			.name = "Persist P2L metadata",
296 			.action = ftl_mngt_persist_p2l_metadata,
297 			.ctx_size = sizeof(struct ftl_p2l_sync_ctx),
298 		},
299 		{
300 			.name = "persist band info metadata",
301 			.action = ftl_mngt_persist_band_info_metadata,
302 		},
303 		{
304 			.name = "persist trim metadata",
305 			.action = ftl_mngt_persist_trim_metadata,
306 		},
307 		{
308 			.name = "Persist superblock",
309 			.action = ftl_mngt_persist_super_block,
310 		},
311 #ifdef SPDK_FTL_VSS_EMU
312 		{
313 			.name = "Persist VSS metadata",
314 			.action = ftl_mngt_persist_vss,
315 		},
316 #endif
317 		{}
318 	}
319 };
320 
321 void
322 ftl_mngt_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
323 {
324 	ftl_mngt_call_process(mngt, &desc_persist);
325 }
326 
327 /*
328  * Fast clean shutdown path - skips the persistance of most metadata regions and
329  * relies on their shared memory state instead.
330  */
331 static const struct ftl_mngt_process_desc desc_fast_persist = {
332 	.name = "Fast persist metadata",
333 	.steps = {
334 		{
335 			.name = "Fast persist NV cache metadata",
336 			.action = ftl_mngt_fast_persist_nv_cache_metadata,
337 		},
338 #ifdef SPDK_FTL_VSS_EMU
339 		{
340 			.name = "Persist VSS metadata",
341 			.action = ftl_mngt_persist_vss,
342 		},
343 #endif
344 		{}
345 	}
346 };
347 
348 void
349 ftl_mngt_fast_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
350 {
351 	ftl_mngt_call_process(mngt, &desc_fast_persist);
352 }
353 
354 void
355 ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
356 {
357 	struct ftl_superblock *sb = dev->sb;
358 
359 	sb->header.magic = FTL_SUPERBLOCK_MAGIC;
360 	sb->header.version = FTL_METADATA_VERSION_CURRENT;
361 	sb->uuid = dev->conf.uuid;
362 	sb->clean = 0;
363 	dev->sb_shm->shm_clean = false;
364 	sb->ckpt_seq_id = 0;
365 
366 	/* Max 16 IO depth per band relocate */
367 	sb->max_reloc_qdepth = 16;
368 
369 	sb->overprovisioning = dev->conf.overprovisioning;
370 
371 	ftl_band_init_gc_iter(dev);
372 
373 	/* md layout isn't initialized yet.
374 	 * empty region list => all regions in the default location */
375 	sb->md_layout_head.type = FTL_LAYOUT_REGION_TYPE_INVALID;
376 
377 	sb->header.crc = get_sb_crc(sb);
378 
379 	ftl_mngt_next_step(mngt);
380 }
381 
382 void
383 ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
384 {
385 	struct ftl_superblock *sb = dev->sb;
386 
387 	sb->clean = 0;
388 	dev->sb_shm->shm_clean = false;
389 	sb->header.crc = get_sb_crc(sb);
390 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
391 }
392 
393 void
394 ftl_mngt_set_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
395 {
396 	struct ftl_superblock *sb = dev->sb;
397 
398 	sb->clean = 1;
399 	dev->sb_shm->shm_clean = false;
400 	sb->header.crc = get_sb_crc(sb);
401 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
402 
403 	dev->sb_shm->shm_ready = false;
404 }
405 
406 void
407 ftl_mngt_set_shm_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
408 {
409 	struct ftl_superblock *sb = dev->sb;
410 
411 	sb->clean = 1;
412 	dev->sb_shm->shm_clean = true;
413 	sb->header.crc = get_sb_crc(sb);
414 	ftl_mngt_next_step(mngt);
415 }
416 
417 void
418 ftl_mngt_load_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
419 {
420 	FTL_NOTICELOG(dev, "SHM: clean %"PRIu64", shm_clean %d\n", dev->sb->clean, dev->sb_shm->shm_clean);
421 
422 	if (!ftl_fast_startup(dev)) {
423 		restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
424 		return;
425 	}
426 
427 	FTL_DEBUGLOG(dev, "SHM: found SB\n");
428 	if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_SB)) {
429 		ftl_mngt_fail_step(mngt);
430 		return;
431 	}
432 	ftl_mngt_next_step(mngt);
433 }
434 
435 void
436 ftl_mngt_validate_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
437 {
438 	struct ftl_superblock *sb = dev->sb;
439 
440 	if (!ftl_superblock_check_magic(sb)) {
441 		FTL_ERRLOG(dev, "Invalid FTL superblock magic\n");
442 		ftl_mngt_fail_step(mngt);
443 		return;
444 	}
445 
446 	if (sb->header.crc != get_sb_crc(sb)) {
447 		FTL_ERRLOG(dev, "Invalid FTL superblock CRC\n");
448 		ftl_mngt_fail_step(mngt);
449 		return;
450 	}
451 
452 	if (spdk_uuid_compare(&sb->uuid, &dev->conf.uuid) != 0) {
453 		FTL_ERRLOG(dev, "Invalid FTL superblock UUID\n");
454 		ftl_mngt_fail_step(mngt);
455 		return;
456 	}
457 
458 	if (sb->lba_cnt == 0) {
459 		FTL_ERRLOG(dev, "Invalid FTL superblock lba_cnt\n");
460 		ftl_mngt_fail_step(mngt);
461 		return;
462 	}
463 	dev->num_lbas = sb->lba_cnt;
464 
465 	/* The sb has just been read. Validate and update the conf */
466 	if (sb->overprovisioning == 0 || sb->overprovisioning >= 100) {
467 		FTL_ERRLOG(dev, "Invalid FTL superblock lba_rsvd\n");
468 		ftl_mngt_fail_step(mngt);
469 		return;
470 	}
471 	dev->conf.overprovisioning = sb->overprovisioning;
472 
473 	ftl_mngt_next_step(mngt);
474 }
475 
476 /*
477  * Loads and verifies superblock contents - utilized during the load of an FTL
478  * instance (both from a clean and dirty shutdown).
479  */
480 static const struct ftl_mngt_process_desc desc_restore_sb = {
481 	.name = "SB restore",
482 	.steps = {
483 		{
484 			.name = "Load super block",
485 			.action = ftl_mngt_load_sb
486 		},
487 		{
488 			.name = "Validate super block",
489 			.action = ftl_mngt_validate_sb
490 		},
491 		{}
492 	}
493 };
494 
495 /*
496  * Initializes the superblock fields during first startup of FTL
497  */
498 static const struct ftl_mngt_process_desc desc_init_sb = {
499 	.name = "SB initialize",
500 	.steps = {
501 		{
502 			.name = "Default-initialize superblock",
503 			.action = ftl_mngt_init_default_sb,
504 		},
505 		{}
506 	}
507 };
508 
509 #ifdef SPDK_FTL_VSS_EMU
510 void
511 ftl_mngt_md_init_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
512 {
513 	struct ftl_layout *layout = &dev->layout;
514 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS];
515 
516 	/* Initialize VSS layout */
517 	ftl_layout_setup_vss_emu(dev);
518 
519 	/* Allocate md buf */
520 	layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = ftl_md_create(dev, region->current.blocks,
521 			region->vss_blksz, NULL, 0, region);
522 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
523 		ftl_mngt_fail_step(mngt);
524 		return;
525 	}
526 	ftl_mngt_next_step(mngt);
527 }
528 
529 void
530 ftl_mngt_md_deinit_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
531 {
532 	struct ftl_layout *layout = &dev->layout;
533 
534 	if (layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
535 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_VSS], 0);
536 		layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = NULL;
537 	}
538 
539 	ftl_mngt_next_step(mngt);
540 }
541 #endif
542 
543 void
544 ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
545 {
546 	struct ftl_layout *layout = &dev->layout;
547 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
548 	char uuid[SPDK_UUID_STRING_LEN];
549 	int md_create_flags = ftl_md_create_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB);
550 
551 	/* Must generate UUID before MD create on SHM for the SB */
552 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
553 		spdk_uuid_generate(&dev->conf.uuid);
554 		spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
555 		FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid);
556 	}
557 
558 shm_retry:
559 	/* Allocate md buf */
560 	dev->sb_shm = NULL;
561 	dev->sb_shm_md = ftl_md_create(dev, spdk_divide_round_up(sizeof(*dev->sb_shm), FTL_BLOCK_SIZE),
562 				       0, "sb_shm",
563 				       md_create_flags, NULL);
564 	if (dev->sb_shm_md == NULL) {
565 		/* The first attempt may fail when trying to open SHM - try to create new */
566 		if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
567 			md_create_flags |= FTL_MD_CREATE_SHM_NEW;
568 			goto shm_retry;
569 		}
570 		if (dev->sb_shm_md == NULL) {
571 			ftl_mngt_fail_step(mngt);
572 			return;
573 		}
574 	}
575 
576 	dev->sb_shm = ftl_md_get_buffer(dev->sb_shm_md);
577 
578 	/* Setup the layout of a superblock */
579 	if (ftl_layout_setup_superblock(dev)) {
580 		ftl_mngt_fail_step(mngt);
581 		return;
582 	}
583 
584 	/* Allocate md buf */
585 	layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
586 						region->vss_blksz, region->name,
587 						md_create_flags, region);
588 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
589 		/* The first attempt may fail when trying to open SHM - try to create new */
590 		if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
591 			md_create_flags |= FTL_MD_CREATE_SHM_NEW;
592 			ftl_md_destroy(dev->sb_shm_md, 0);
593 			goto shm_retry;
594 		}
595 		ftl_mngt_fail_step(mngt);
596 		return;
597 	}
598 
599 	/* Link the md buf to the device */
600 	dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
601 
602 	/* Setup superblock mirror to QLC */
603 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
604 	layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
605 			region->vss_blksz, NULL, FTL_MD_CREATE_HEAP, region);
606 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
607 		ftl_mngt_fail_step(mngt);
608 		return;
609 	}
610 
611 	/* Initialize the superblock */
612 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
613 		ftl_mngt_call_process(mngt, &desc_init_sb);
614 	} else {
615 		ftl_mngt_call_process(mngt, &desc_restore_sb);
616 	}
617 }
618 
619 void
620 ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
621 {
622 	struct ftl_layout *layout = &dev->layout;
623 
624 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
625 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB],
626 			       ftl_md_destroy_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB));
627 		layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL;
628 	}
629 
630 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
631 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE], 0);
632 		layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL;
633 	}
634 
635 	ftl_md_destroy(dev->sb_shm_md, ftl_md_destroy_shm_flags(dev));
636 	dev->sb_shm_md = NULL;
637 	dev->sb_shm = NULL;
638 
639 	ftl_mngt_next_step(mngt);
640 }
641 
642 static void
643 ftl_mngt_restore_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
644 {
645 	if (ftl_fast_startup(dev)) {
646 		FTL_DEBUGLOG(dev, "SHM: found nv cache md\n");
647 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD)) {
648 			ftl_mngt_fail_step(mngt);
649 			return;
650 		}
651 		ftl_mngt_next_step(mngt);
652 		return;
653 	}
654 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
655 }
656 
657 static void
658 ftl_mngt_restore_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
659 {
660 	if (ftl_fast_startup(dev)) {
661 		FTL_DEBUGLOG(dev, "SHM: found vldmap\n");
662 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP)) {
663 			ftl_mngt_fail_step(mngt);
664 			return;
665 		}
666 		ftl_mngt_next_step(mngt);
667 		return;
668 	}
669 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
670 }
671 
672 static void
673 ftl_mngt_restore_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
674 {
675 	if (ftl_fast_startup(dev)) {
676 		FTL_DEBUGLOG(dev, "SHM: found band md\n");
677 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD)) {
678 			ftl_mngt_fail_step(mngt);
679 			return;
680 		}
681 		ftl_mngt_next_step(mngt);
682 		return;
683 	}
684 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
685 }
686 
687 static void
688 ftl_mngt_restore_trim_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
689 {
690 	if (ftl_fast_startup(dev)) {
691 		FTL_DEBUGLOG(dev, "SHM: found trim md\n");
692 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD)) {
693 			ftl_mngt_fail_step(mngt);
694 			return;
695 		}
696 		ftl_mngt_next_step(mngt);
697 		return;
698 	}
699 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_TRIM_MD);
700 }
701 
702 
703 
704 #ifdef SPDK_FTL_VSS_EMU
705 static void
706 ftl_mngt_restore_vss_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
707 {
708 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_VSS);
709 }
710 #endif
711 
712 /*
713  * Loads metadata after a clean shutdown.
714  */
715 static const struct ftl_mngt_process_desc desc_restore = {
716 	.name = "Restore metadata",
717 	.steps = {
718 #ifdef SPDK_FTL_VSS_EMU
719 		{
720 			.name = "Restore VSS metadata",
721 			.action = ftl_mngt_restore_vss_metadata,
722 		},
723 #endif
724 		{
725 			.name = "Restore NV cache metadata",
726 			.action = ftl_mngt_restore_nv_cache_metadata,
727 		},
728 		{
729 			.name = "Restore valid map metadata",
730 			.action = ftl_mngt_restore_vld_map_metadata,
731 		},
732 		{
733 			.name = "Restore band info metadata",
734 			.action = ftl_mngt_restore_band_info_metadata,
735 		},
736 		{
737 			.name = "Restore trim metadata",
738 			.action = ftl_mngt_restore_trim_metadata,
739 		},
740 		{}
741 	}
742 };
743 
744 void
745 ftl_mngt_restore_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
746 {
747 	ftl_mngt_call_process(mngt, &desc_restore);
748 }
749