xref: /spdk/lib/ftl/ftl_layout.c (revision 28fa2c2f668e229a1b215535d2a8ea5039c28deb)
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/bdev.h"
8 
9 #include "ftl_core.h"
10 #include "ftl_utils.h"
11 #include "ftl_band.h"
12 #include "ftl_layout.h"
13 #include "ftl_nv_cache.h"
14 #include "ftl_sb.h"
15 #include "nvc/ftl_nvc_dev.h"
16 #include "utils/ftl_layout_tracker_bdev.h"
17 #include "upgrade/ftl_layout_upgrade.h"
18 
19 enum ftl_layout_setup_mode {
20 	FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT = 0,
21 	FTL_LAYOUT_SETUP_MODE_NO_RESTRICT,
22 	FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT,
23 };
24 
25 static inline float
26 blocks2mib(uint64_t blocks)
27 {
28 	float result;
29 
30 	result = blocks;
31 	result *= FTL_BLOCK_SIZE;
32 	result /= 1024UL;
33 	result /= 1024UL;
34 
35 	return result;
36 }
37 
38 static uint64_t
39 superblock_region_size(struct spdk_ftl_dev *dev)
40 {
41 	const struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
42 	uint64_t wus = spdk_bdev_get_write_unit_size(bdev) * FTL_BLOCK_SIZE;
43 
44 	if (wus > FTL_SUPERBLOCK_SIZE) {
45 		return wus;
46 	} else {
47 		return wus * spdk_divide_round_up(FTL_SUPERBLOCK_SIZE, wus);
48 	}
49 }
50 
51 static uint64_t
52 superblock_region_blocks(struct spdk_ftl_dev *dev)
53 {
54 	return superblock_region_size(dev) / FTL_BLOCK_SIZE;
55 }
56 
57 uint64_t
58 ftl_md_region_blocks(struct spdk_ftl_dev *dev, uint64_t bytes)
59 {
60 	const uint64_t alignment = superblock_region_size(dev);
61 	uint64_t result;
62 
63 	result = spdk_divide_round_up(bytes, alignment);
64 	result *= alignment;
65 	result /= FTL_BLOCK_SIZE;
66 
67 	return result;
68 }
69 
70 uint64_t
71 ftl_md_region_align_blocks(struct spdk_ftl_dev *dev, uint64_t blocks)
72 {
73 	const uint64_t alignment = superblock_region_blocks(dev);
74 	uint64_t result;
75 
76 	result = spdk_divide_round_up(blocks, alignment);
77 	result *= alignment;
78 
79 	return result;
80 }
81 
82 const char *
83 ftl_md_region_name(enum ftl_layout_region_type reg_type)
84 {
85 	static const char *md_region_name[FTL_LAYOUT_REGION_TYPE_MAX] = {
86 		[FTL_LAYOUT_REGION_TYPE_SB] = "sb",
87 		[FTL_LAYOUT_REGION_TYPE_SB_BASE] = "sb_mirror",
88 		[FTL_LAYOUT_REGION_TYPE_L2P] = "l2p",
89 		[FTL_LAYOUT_REGION_TYPE_BAND_MD] = "band_md",
90 		[FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = "band_md_mirror",
91 		[FTL_LAYOUT_REGION_TYPE_VALID_MAP] = "vmap",
92 		[FTL_LAYOUT_REGION_TYPE_NVC_MD] = "nvc_md",
93 		[FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = "nvc_md_mirror",
94 		[FTL_LAYOUT_REGION_TYPE_DATA_NVC] = "data_nvc",
95 		[FTL_LAYOUT_REGION_TYPE_DATA_BASE] = "data_btm",
96 		[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = "p2l0",
97 		[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = "p2l1",
98 		[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = "p2l2",
99 		[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = "p2l3",
100 		[FTL_LAYOUT_REGION_TYPE_TRIM_MD] = "trim_md",
101 		[FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = "trim_md_mirror",
102 	};
103 	const char *reg_name = md_region_name[reg_type];
104 
105 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
106 	assert(reg_name != NULL);
107 	return reg_name;
108 }
109 
110 static void
111 dump_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
112 {
113 	assert(!(region->current.offset % superblock_region_blocks(dev)));
114 	assert(!(region->current.blocks % superblock_region_blocks(dev)));
115 
116 	FTL_NOTICELOG(dev, "Region %s\n", region->name);
117 	FTL_NOTICELOG(dev, "	offset:                      %.2f MiB\n",
118 		      blocks2mib(region->current.offset));
119 	FTL_NOTICELOG(dev, "	blocks:                      %.2f MiB\n",
120 		      blocks2mib(region->current.blocks));
121 }
122 
123 int
124 ftl_validate_regions(struct spdk_ftl_dev *dev, struct ftl_layout *layout)
125 {
126 	enum ftl_layout_region_type i, j;
127 
128 	/* Validate if regions doesn't overlap each other  */
129 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
130 		struct ftl_layout_region *r1 = ftl_layout_region_get(dev, i);
131 
132 		if (!r1) {
133 			continue;
134 		}
135 
136 		for (j = 0; j < FTL_LAYOUT_REGION_TYPE_MAX; j++) {
137 			struct ftl_layout_region *r2 = ftl_layout_region_get(dev, j);
138 
139 			if (!r2) {
140 				continue;
141 			}
142 
143 			if (r1->bdev_desc != r2->bdev_desc) {
144 				continue;
145 			}
146 
147 			if (i == j) {
148 				continue;
149 			}
150 
151 			uint64_t r1_begin = r1->current.offset;
152 			uint64_t r1_end = r1->current.offset + r1->current.blocks - 1;
153 			uint64_t r2_begin = r2->current.offset;
154 			uint64_t r2_end = r2->current.offset + r2->current.blocks - 1;
155 
156 			if (spdk_max(r1_begin, r2_begin) <= spdk_min(r1_end, r2_end)) {
157 				FTL_ERRLOG(dev, "Layout initialization ERROR, two regions overlap, "
158 					   "%s and %s\n", r1->name, r2->name);
159 				return -1;
160 			}
161 		}
162 	}
163 
164 	return 0;
165 }
166 
167 static uint64_t
168 get_num_user_lbas(struct spdk_ftl_dev *dev)
169 {
170 	uint64_t blocks;
171 
172 	blocks = dev->num_bands * ftl_get_num_blocks_in_band(dev);
173 	blocks = (blocks * (100 - dev->conf.overprovisioning)) / 100;
174 
175 	return blocks;
176 }
177 
178 struct ftl_layout_region *
179 ftl_layout_region_get(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type)
180 {
181 	struct ftl_layout_region *reg = &dev->layout.region[reg_type];
182 
183 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
184 	return reg->type == reg_type ? reg : NULL;
185 }
186 
187 uint64_t
188 ftl_layout_base_offset(struct spdk_ftl_dev *dev)
189 {
190 	return dev->num_bands * ftl_get_num_blocks_in_band(dev);
191 }
192 
193 static int
194 layout_region_create_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
195 			 uint32_t reg_version, size_t entry_size, size_t entry_count)
196 {
197 	const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
198 	size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size);
199 
200 	if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) {
201 		return -1;
202 	}
203 	if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count,
204 				&dev->layout.region[reg_type])) {
205 		return -1;
206 	}
207 	return 0;
208 }
209 
210 static int
211 layout_region_create_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
212 			  uint32_t reg_version, size_t entry_size, size_t entry_count)
213 {
214 	const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops;
215 	size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size);
216 
217 	if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) {
218 		return -1;
219 	}
220 	if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count,
221 				&dev->layout.region[reg_type])) {
222 		return -1;
223 	}
224 	return 0;
225 }
226 
227 static void
228 legacy_layout_verify_region(struct ftl_layout_tracker_bdev *layout_tracker,
229 			    enum ftl_layout_region_type reg_type, uint32_t reg_version)
230 {
231 	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
232 	const struct ftl_layout_tracker_bdev_region_props *reg_found = NULL;
233 
234 	while (true) {
235 		ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, &reg_search_ctx);
236 		if (!reg_search_ctx) {
237 			break;
238 		}
239 
240 		/* Only a single region version is present in upgrade from the legacy layout */
241 		ftl_bug(reg_search_ctx->ver != reg_version);
242 		ftl_bug(reg_found != NULL);
243 
244 		reg_found = reg_search_ctx;
245 	}
246 }
247 
248 static int
249 legacy_layout_region_open_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
250 			      uint32_t reg_version, size_t entry_size, size_t entry_count)
251 {
252 	struct ftl_layout_region *reg = &dev->layout.region[reg_type];
253 	const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
254 
255 	legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version);
256 	return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg);
257 }
258 
259 static int
260 legacy_layout_region_open_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
261 			       uint32_t reg_version, size_t entry_size, size_t entry_count)
262 {
263 	struct ftl_layout_region *reg = &dev->layout.region[reg_type];
264 	const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops;
265 
266 	legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version);
267 	return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg);
268 }
269 
270 static int
271 layout_setup_legacy_default_nvc(struct spdk_ftl_dev *dev)
272 {
273 	int region_type;
274 	uint64_t blocks, chunk_count;
275 	struct ftl_layout *layout = &dev->layout;
276 	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
277 
278 	/* Initialize L2P region */
279 	blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas);
280 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE,
281 					  blocks)) {
282 		goto error;
283 	}
284 
285 	/* Initialize band info metadata */
286 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_1,
287 					  sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
288 		goto error;
289 	}
290 
291 	/* Initialize band info metadata mirror */
292 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_1,
293 					  sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
294 		goto error;
295 	}
296 	layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR;
297 
298 	/*
299 	 * Initialize P2L checkpointing regions
300 	 */
301 	for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
302 	     region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX;
303 	     region_type++) {
304 		const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
305 
306 		/* Get legacy number of blocks */
307 		ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, region_type, &reg_search_ctx);
308 		if (!reg_search_ctx || reg_search_ctx->ver != FTL_P2L_VERSION_1) {
309 			goto error;
310 		}
311 		blocks = reg_search_ctx->blk_sz;
312 
313 		if (legacy_layout_region_open_nvc(dev, region_type, FTL_P2L_VERSION_1, FTL_BLOCK_SIZE, blocks)) {
314 			goto error;
315 		}
316 	}
317 
318 	/*
319 	 * Initialize trim metadata region
320 	 */
321 	blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks;
322 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, sizeof(uint64_t),
323 					  blocks)) {
324 		goto error;
325 	}
326 
327 	/* Initialize trim metadata mirror region */
328 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, sizeof(uint64_t),
329 					  blocks)) {
330 		goto error;
331 	}
332 	layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR;
333 
334 	/* Restore chunk count */
335 	ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_DATA_NVC,
336 			&reg_search_ctx);
337 	if (!reg_search_ctx || reg_search_ctx->ver != 0) {
338 		goto error;
339 	}
340 	blocks = reg_search_ctx->blk_sz;
341 	chunk_count = blocks / ftl_get_num_blocks_in_band(dev);
342 	if (0 == chunk_count) {
343 		goto error;
344 	}
345 
346 	/*
347 	 * Initialize NV Cache metadata
348 	 */
349 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_1,
350 					  sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) {
351 		goto error;
352 	}
353 
354 	/*
355 	 * Initialize NV Cache metadata mirror
356 	 */
357 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_1,
358 					  sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) {
359 		goto error;
360 	}
361 	layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR;
362 
363 	/*
364 	 * Initialize data region on NV cache
365 	 */
366 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_DATA_NVC, 0,
367 					  layout->nvc.chunk_data_blocks * FTL_BLOCK_SIZE, chunk_count)) {
368 		goto error;
369 	}
370 
371 	return 0;
372 
373 error:
374 	FTL_ERRLOG(dev, "Invalid legacy NV Cache metadata layout\n");
375 	return -1;
376 }
377 
378 static int
379 layout_setup_legacy_default_base(struct spdk_ftl_dev *dev)
380 {
381 	struct ftl_layout *layout = &dev->layout;
382 
383 	/* Base device layout is as follows:
384 	 * - superblock
385 	 * - data
386 	 * - valid map
387 	 */
388 	if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE,
389 				      ftl_layout_base_offset(dev))) {
390 		return -1;
391 	}
392 
393 	if (legacy_layout_region_open_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE,
394 					   ftl_md_region_blocks(dev, spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks,
395 							   8)))) {
396 		return -1;
397 	}
398 
399 	return 0;
400 }
401 
402 static int
403 layout_setup_legacy_default(struct spdk_ftl_dev *dev)
404 {
405 	if (layout_setup_legacy_default_nvc(dev) || layout_setup_legacy_default_base(dev)) {
406 		return -1;
407 	}
408 	return 0;
409 }
410 
411 static int
412 layout_setup_default_nvc(struct spdk_ftl_dev *dev)
413 {
414 	int region_type;
415 	uint64_t l2p_blocks;
416 	struct ftl_layout *layout = &dev->layout;
417 
418 	/* Initialize L2P region */
419 	l2p_blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas);
420 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE, l2p_blocks)) {
421 		goto error;
422 	}
423 
424 	/* Initialize band info metadata */
425 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_CURRENT,
426 				     sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
427 		goto error;
428 	}
429 
430 	/* Initialize band info metadata mirror */
431 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_CURRENT,
432 				     sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
433 		goto error;
434 	}
435 	layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR;
436 
437 	/*
438 	 * Initialize P2L checkpointing regions
439 	 */
440 	for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
441 	     region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX;
442 	     region_type++) {
443 		if (layout_region_create_nvc(dev, region_type, FTL_P2L_VERSION_CURRENT, FTL_BLOCK_SIZE,
444 					     layout->p2l.ckpt_pages)) {
445 			goto error;
446 		}
447 	}
448 
449 	/*
450 	 * Initialize trim metadata region
451 	 */
452 	l2p_blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks;
453 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, sizeof(uint64_t),
454 				     l2p_blocks)) {
455 		goto error;
456 	}
457 
458 	/* Initialize trim metadata mirror region */
459 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, sizeof(uint64_t),
460 				     l2p_blocks)) {
461 		goto error;
462 	}
463 	layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR;
464 
465 	/*
466 	 * Initialize NV Cache metadata
467 	 */
468 	if (0 == layout->nvc.chunk_count) {
469 		goto error;
470 	}
471 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_CURRENT,
472 				     sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) {
473 		goto error;
474 	}
475 
476 	/*
477 	 * Initialize NV Cache metadata mirror
478 	 */
479 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_CURRENT,
480 				     sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) {
481 		goto error;
482 	}
483 	layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR;
484 
485 	return 0;
486 
487 error:
488 	FTL_ERRLOG(dev, "Insufficient NV Cache capacity to preserve metadata\n");
489 	return -1;
490 }
491 
492 static int
493 layout_setup_default_base(struct spdk_ftl_dev *dev)
494 {
495 	struct ftl_layout *layout = &dev->layout;
496 	uint64_t valid_map_size;
497 
498 	/* Base device layout is as follows:
499 	 * - superblock
500 	 * - data
501 	 * - valid map
502 	 */
503 	if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE,
504 				      ftl_layout_base_offset(dev))) {
505 		return -1;
506 	}
507 
508 	valid_map_size = spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks, 8);
509 	if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE,
510 				      ftl_md_region_blocks(dev, valid_map_size))) {
511 		return -1;
512 	}
513 
514 	return 0;
515 }
516 
517 static int
518 layout_setup_default(struct spdk_ftl_dev *dev)
519 {
520 	if (layout_setup_default_nvc(dev) || layout_setup_default_base(dev)) {
521 		return -1;
522 	}
523 	return 0;
524 }
525 
526 static int
527 layout_load(struct spdk_ftl_dev *dev)
528 {
529 	if (ftl_superblock_load_blob_area(dev)) {
530 		return -1;
531 	}
532 	if (ftl_superblock_md_layout_apply(dev)) {
533 		return -1;
534 	}
535 	return 0;
536 }
537 
538 int
539 ftl_layout_setup(struct spdk_ftl_dev *dev)
540 {
541 	struct ftl_layout *layout = &dev->layout;
542 	uint64_t i;
543 	uint64_t num_lbas;
544 	enum ftl_layout_setup_mode setup_mode;
545 	int rc;
546 
547 	/*
548 	 * SB v5 adds the ability to create MD regions dynamically, i.e. depending on the underlying device type.
549 	 * For compatibility reasons:
550 	 * 1. When upgrading from pre-v5 SB, only the legacy default layout is created.
551 	 *    Pre-v5: some regions were static and not stored in the SB layout. These must be created to match
552 	 *            the legacy default layout.
553 	 *    v5: all regions are stored in the SB layout. Upon the SB upgrade, the legacy default layout
554 	 *        is updated with pre-v5 layout stored in the SB. The whole layout is then stored in v5 SB.
555 	 *
556 	 * 2. When SB v5 or later was loaded, the layout is instantiated from the nvc and base layout blobs.
557 	 *    No default layout is created.
558 	 *
559 	 * 3. When the FTL layout is being created for the first time, there are no restrictions.
560 	 *
561 	 * Any new regions to be created in cases (1) and (2) can only be placed in the unallocated area
562 	 * of the underlying device.
563 	 */
564 
565 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
566 		setup_mode = FTL_LAYOUT_SETUP_MODE_NO_RESTRICT;
567 	} else if (ftl_superblock_is_blob_area_empty(dev->sb)) {
568 		setup_mode = FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT;
569 	} else {
570 		setup_mode = FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT;
571 	}
572 	FTL_NOTICELOG(dev, "FTL layout setup mode %d\n", (int)setup_mode);
573 
574 	/* Invalidate all regions */
575 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
576 		if (i == FTL_LAYOUT_REGION_TYPE_SB || i == FTL_LAYOUT_REGION_TYPE_SB_BASE) {
577 			/* Super block has been already initialized */
578 			continue;
579 		}
580 
581 		layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
582 		/* Mark the region inactive */
583 		layout->region[i].type = FTL_LAYOUT_REGION_TYPE_INVALID;
584 	}
585 
586 	/*
587 	 * Initialize L2P information
588 	 */
589 	num_lbas = get_num_user_lbas(dev);
590 	if (dev->num_lbas == 0) {
591 		assert(dev->conf.mode & SPDK_FTL_MODE_CREATE);
592 		dev->num_lbas = num_lbas;
593 		dev->sb->lba_cnt = num_lbas;
594 	} else if (dev->num_lbas != num_lbas) {
595 		FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n");
596 		return -EINVAL;
597 	}
598 	layout->l2p.addr_length = spdk_u64log2(layout->base.total_blocks + layout->nvc.total_blocks) + 1;
599 	layout->l2p.addr_size = layout->l2p.addr_length > 32 ? 8 : 4;
600 	layout->l2p.lbas_in_page = FTL_BLOCK_SIZE / layout->l2p.addr_size;
601 
602 	/* Setup P2L ckpt */
603 	layout->p2l.pages_per_xfer = spdk_divide_round_up(dev->xfer_size, FTL_NUM_P2L_ENTRIES_NO_VSS);
604 	layout->p2l.ckpt_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev),
605 				 dev->xfer_size) * layout->p2l.pages_per_xfer;
606 
607 	layout->nvc.chunk_data_blocks = ftl_get_num_blocks_in_band(dev);
608 	layout->nvc.chunk_count = layout->nvc.total_blocks / ftl_get_num_blocks_in_band(dev);
609 	layout->nvc.chunk_tail_md_num_blocks = ftl_nv_cache_chunk_tail_md_num_blocks(&dev->nv_cache);
610 
611 	layout->base.num_usable_blocks = ftl_get_num_blocks_in_band(dev);
612 	layout->base.user_blocks = ftl_band_user_blocks(dev->bands);
613 
614 	switch (setup_mode) {
615 	case FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT:
616 		if (layout_setup_legacy_default(dev)) {
617 			return -EINVAL;
618 		}
619 		break;
620 
621 	case FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT:
622 		if (layout_load(dev)) {
623 			return -EINVAL;
624 		}
625 		break;
626 
627 	case FTL_LAYOUT_SETUP_MODE_NO_RESTRICT:
628 		if (layout_setup_default(dev)) {
629 			return -EINVAL;
630 		}
631 		break;
632 
633 	default:
634 		ftl_abort();
635 		break;
636 	}
637 
638 	if (ftl_validate_regions(dev, layout)) {
639 		return -EINVAL;
640 	}
641 
642 	/* Now drop the unused regions in preparation for the layout upgrade */
643 	if (ftl_layout_upgrade_drop_regions(dev)) {
644 		return -EINVAL;
645 	}
646 
647 	rc = ftl_superblock_store_blob_area(dev);
648 
649 	FTL_NOTICELOG(dev, "Base device capacity:         %.2f MiB\n",
650 		      blocks2mib(layout->base.total_blocks));
651 	FTL_NOTICELOG(dev, "NV cache device capacity:       %.2f MiB\n",
652 		      blocks2mib(layout->nvc.total_blocks));
653 	FTL_NOTICELOG(dev, "L2P entries:                    %"PRIu64"\n", dev->num_lbas);
654 	FTL_NOTICELOG(dev, "L2P address size:               %"PRIu64"\n", layout->l2p.addr_size);
655 	FTL_NOTICELOG(dev, "P2L checkpoint pages:           %"PRIu64"\n", layout->p2l.ckpt_pages);
656 	FTL_NOTICELOG(dev, "NV cache chunk count            %"PRIu64"\n", dev->layout.nvc.chunk_count);
657 
658 	return rc;
659 }
660 
661 int
662 ftl_layout_setup_superblock(struct spdk_ftl_dev *dev)
663 {
664 	const struct spdk_bdev *bdev;
665 	struct ftl_layout *layout = &dev->layout;
666 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
667 	uint64_t total_blocks, offset, left;
668 
669 	assert(layout->md[FTL_LAYOUT_REGION_TYPE_SB] == NULL);
670 
671 	bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
672 	layout->base.total_blocks = spdk_bdev_get_num_blocks(bdev);
673 
674 	bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
675 	layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev);
676 
677 	/* Initialize superblock region */
678 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_SB, FTL_SB_VERSION_CURRENT,
679 				     superblock_region_size(dev), 1)) {
680 		FTL_ERRLOG(dev, "Error when setting up primary super block\n");
681 		return -1;
682 	}
683 
684 	assert(region->bdev_desc != NULL);
685 	assert(region->ioch != NULL);
686 	assert(region->current.offset == 0);
687 
688 	if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_SB_BASE, FTL_SB_VERSION_CURRENT,
689 				      superblock_region_size(dev), 1)) {
690 		FTL_ERRLOG(dev, "Error when setting up secondary super block\n");
691 		return -1;
692 	}
693 	layout->region[FTL_LAYOUT_REGION_TYPE_SB].mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE;
694 
695 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
696 	assert(region->current.offset == 0);
697 
698 	/* Check if SB can be stored at the end of base device */
699 	total_blocks = spdk_bdev_get_num_blocks(
700 			       spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
701 	offset = region->current.offset + region->current.blocks;
702 	left = total_blocks - offset;
703 	if ((left > total_blocks) || (offset > total_blocks)) {
704 		FTL_ERRLOG(dev, "Error when setup base device super block\n");
705 		return -1;
706 	}
707 
708 	return 0;
709 }
710 
711 int
712 ftl_layout_clear_superblock(struct spdk_ftl_dev *dev)
713 {
714 	int rc;
715 
716 	rc = ftl_layout_tracker_bdev_rm_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB,
717 					       FTL_SB_VERSION_CURRENT);
718 	if (rc) {
719 		return rc;
720 	}
721 
722 	return ftl_layout_tracker_bdev_rm_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB_BASE,
723 			FTL_SB_VERSION_CURRENT);
724 }
725 
726 void
727 ftl_layout_dump(struct spdk_ftl_dev *dev)
728 {
729 	struct ftl_layout_region *reg;
730 	enum ftl_layout_region_type i;
731 
732 	FTL_NOTICELOG(dev, "NV cache layout:\n");
733 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
734 		reg = ftl_layout_region_get(dev, i);
735 		if (reg && reg->bdev_desc == dev->nv_cache.bdev_desc) {
736 			dump_region(dev, reg);
737 		}
738 	}
739 	FTL_NOTICELOG(dev, "Base device layout:\n");
740 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
741 		reg = ftl_layout_region_get(dev, i);
742 		if (reg && reg->bdev_desc == dev->base_bdev_desc) {
743 			dump_region(dev, reg);
744 		}
745 	}
746 }
747 
748 uint64_t
749 ftl_layout_base_md_blocks(struct spdk_ftl_dev *dev)
750 {
751 	const struct spdk_bdev *bdev;
752 	uint64_t md_blocks = 0, total_blocks = 0;
753 
754 	bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
755 	total_blocks += spdk_bdev_get_num_blocks(bdev);
756 
757 	bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
758 	total_blocks += spdk_bdev_get_num_blocks(bdev);
759 
760 	/* Count space needed for validity map */
761 	md_blocks += ftl_md_region_blocks(dev, spdk_divide_round_up(total_blocks, 8));
762 
763 	/* Count space needed for superblock */
764 	md_blocks += superblock_region_blocks(dev);
765 	return md_blocks;
766 }
767 
768 struct layout_blob_entry {
769 	uint32_t type;
770 	uint64_t entry_size;
771 	uint64_t num_entries;
772 } __attribute__((packed));
773 
774 size_t
775 ftl_layout_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz)
776 {
777 	struct layout_blob_entry *blob_entry = blob_buf;
778 	struct ftl_layout_region *reg;
779 	enum ftl_layout_region_type reg_type;
780 	size_t blob_sz = 0;
781 
782 	for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) {
783 		if (blob_sz + sizeof(*blob_entry) > blob_buf_sz) {
784 			return 0;
785 		}
786 
787 		reg = &dev->layout.region[reg_type];
788 		blob_entry->type = reg_type;
789 		blob_entry->entry_size = reg->entry_size;
790 		blob_entry->num_entries = reg->num_entries;
791 
792 		blob_entry++;
793 		blob_sz += sizeof(*blob_entry);
794 	}
795 
796 	return blob_sz;
797 }
798 
799 int
800 ftl_layout_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz)
801 {
802 	struct layout_blob_entry *blob_entry = blob_buf;
803 	size_t blob_entry_num = blob_sz / sizeof(*blob_entry);
804 	struct layout_blob_entry *blob_entry_end = blob_entry + blob_entry_num;
805 	struct ftl_layout_region *reg;
806 
807 	if (blob_sz % sizeof(*blob_entry) != 0) {
808 		/* Invalid blob size */
809 		return -1;
810 	}
811 
812 	for (; blob_entry < blob_entry_end; blob_entry++) {
813 		/* Verify the type */
814 		if (blob_entry->type >= FTL_LAYOUT_REGION_TYPE_MAX) {
815 			return -1;
816 		}
817 
818 		/* Load the entry */
819 		reg = &dev->layout.region[blob_entry->type];
820 		reg->entry_size = blob_entry->entry_size;
821 		reg->num_entries = blob_entry->num_entries;
822 	}
823 
824 	return 0;
825 }
826