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