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