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