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