xref: /spdk/lib/ftl/ftl_layout.c (revision 588dfe314bb83d86effdf67ec42837b11c2620bf)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2022 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/bdev.h"
7 
8 #include "ftl_core.h"
9 #include "ftl_utils.h"
10 #include "ftl_band.h"
11 #include "ftl_layout.h"
12 #include "ftl_nv_cache.h"
13 #include "ftl_sb.h"
14 
15 #define FTL_NV_CACHE_CHUNK_DATA_SIZE(blocks) ((uint64_t)blocks * FTL_BLOCK_SIZE)
16 #define FTL_NV_CACHE_CHUNK_SIZE(blocks) \
17 	(FTL_NV_CACHE_CHUNK_DATA_SIZE(blocks) + (2 * FTL_NV_CACHE_CHUNK_MD_SIZE))
18 
19 static inline float
20 blocks2mib(uint64_t blocks)
21 {
22 	float result;
23 
24 	result = blocks;
25 	result *= FTL_BLOCK_SIZE;
26 	result /= 1024UL;
27 	result /= 1024UL;
28 
29 	return result;
30 }
31 /* TODO: This should be aligned to the write unit size of the device a given piece of md is on.
32  * The tricky part is to make sure interpreting old alignment values will still be valid...
33  */
34 #define FTL_LAYOUT_REGION_ALIGNMENT_BLOCKS 32ULL
35 #define FTL_LAYOUT_REGION_ALIGNMENT_BYTES (FTL_LAYOUT_REGION_ALIGNMENT_BLOCKS * FTL_BLOCK_SIZE)
36 
37 static inline uint64_t
38 blocks_region(uint64_t bytes)
39 {
40 	const uint64_t alignment = FTL_LAYOUT_REGION_ALIGNMENT_BYTES;
41 	uint64_t result;
42 
43 	result = spdk_divide_round_up(bytes, alignment);
44 	result *= alignment;
45 	result /= FTL_BLOCK_SIZE;
46 
47 	return result;
48 }
49 
50 static void
51 dump_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
52 {
53 	assert(!(region->current.offset % FTL_LAYOUT_REGION_ALIGNMENT_BLOCKS));
54 	assert(!(region->current.blocks % FTL_LAYOUT_REGION_ALIGNMENT_BLOCKS));
55 
56 	FTL_NOTICELOG(dev, "Region %s\n", region->name);
57 	FTL_NOTICELOG(dev, "	offset:                      %.2f MiB\n",
58 		      blocks2mib(region->current.offset));
59 	FTL_NOTICELOG(dev, "	blocks:                      %.2f MiB\n",
60 		      blocks2mib(region->current.blocks));
61 }
62 
63 int
64 ftl_validate_regions(struct spdk_ftl_dev *dev, struct ftl_layout *layout)
65 {
66 	uint64_t i, j;
67 
68 	/* Validate if regions doesn't overlap each other  */
69 	/* TODO: major upgrades: keep track of and validate free_nvc/free_btm regions */
70 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
71 		struct ftl_layout_region *r1 = &layout->region[i];
72 
73 		for (j = 0; j < FTL_LAYOUT_REGION_TYPE_MAX; j++) {
74 			struct ftl_layout_region *r2 = &layout->region[j];
75 
76 			if (r1->bdev_desc != r2->bdev_desc) {
77 				continue;
78 			}
79 
80 			if (i == j) {
81 				continue;
82 			}
83 
84 			uint64_t r1_begin = r1->current.offset;
85 			uint64_t r1_end = r1->current.offset + r1->current.blocks - 1;
86 			uint64_t r2_begin = r2->current.offset;
87 			uint64_t r2_end = r2->current.offset + r2->current.blocks - 1;
88 
89 			if (spdk_max(r1_begin, r2_begin) <= spdk_min(r1_end, r2_end)) {
90 				FTL_ERRLOG(dev, "Layout initialization ERROR, two regions overlap, "
91 					   "%s and %s\n", r1->name, r2->name);
92 				return -1;
93 			}
94 		}
95 	}
96 
97 	return 0;
98 }
99 
100 static uint64_t
101 get_num_user_lbas(struct spdk_ftl_dev *dev)
102 {
103 	uint64_t blocks;
104 
105 	blocks = dev->num_bands * ftl_get_num_blocks_in_band(dev);
106 	blocks = (blocks * (100 - dev->conf.overprovisioning)) / 100;
107 
108 	return blocks;
109 }
110 
111 static void
112 set_region_bdev_nvc(struct ftl_layout_region *reg, struct spdk_ftl_dev *dev)
113 {
114 	reg->bdev_desc = dev->nv_cache.bdev_desc;
115 	reg->ioch = dev->nv_cache.cache_ioch;
116 	reg->vss_blksz = dev->nv_cache.md_size;
117 }
118 
119 static void
120 set_region_bdev_btm(struct ftl_layout_region *reg, struct spdk_ftl_dev *dev)
121 {
122 	reg->bdev_desc = dev->base_bdev_desc;
123 	reg->ioch = dev->base_ioch;
124 	reg->vss_blksz = 0;
125 }
126 
127 static int
128 setup_layout_nvc(struct spdk_ftl_dev *dev)
129 {
130 	int region_type;
131 	uint64_t left, offset = 0, l2p_blocks;
132 	struct ftl_layout *layout = &dev->layout;
133 	struct ftl_layout_region *region, *mirror;
134 	static const char *p2l_region_name[] = {
135 		"p2l0",
136 		"p2l1",
137 		"p2l2",
138 		"p2l3"
139 	};
140 
141 #ifdef SPDK_FTL_VSS_EMU
142 	/* Skip the already init`d VSS region */
143 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS];
144 	offset += region->current.blocks;
145 
146 	if (offset >= layout->nvc.total_blocks) {
147 		goto error;
148 	}
149 #endif
150 
151 	/* Skip the superblock region. Already init`d in ftl_layout_setup_superblock */
152 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
153 	offset += region->current.blocks;
154 
155 	/* Initialize L2P region */
156 	if (offset >= layout->nvc.total_blocks) {
157 		goto error;
158 	}
159 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_L2P];
160 	region->type = FTL_LAYOUT_REGION_TYPE_L2P;
161 	region->name = "l2p";
162 	region->current.version = 0;
163 	region->prev.version = 0;
164 	region->current.offset = offset;
165 	region->current.blocks = blocks_region(layout->l2p.addr_size * dev->num_lbas);
166 	set_region_bdev_nvc(region, dev);
167 	offset += region->current.blocks;
168 
169 	/* Initialize band info metadata */
170 	if (offset >= layout->nvc.total_blocks) {
171 		goto error;
172 	}
173 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD];
174 	region->type = FTL_LAYOUT_REGION_TYPE_BAND_MD;
175 	region->mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR;
176 	region->name = "band_md";
177 	region->current.version = region->prev.version = FTL_BAND_VERSION_CURRENT;
178 	region->current.offset = offset;
179 	region->current.blocks = blocks_region(ftl_get_num_bands(dev) * sizeof(struct ftl_band_md));
180 	region->entry_size = sizeof(struct ftl_band_md) / FTL_BLOCK_SIZE;
181 	region->num_entries = ftl_get_num_bands(dev);
182 	set_region_bdev_nvc(region, dev);
183 	offset += region->current.blocks;
184 
185 	/* Initialize band info metadata mirror */
186 	if (offset >= layout->nvc.total_blocks) {
187 		goto error;
188 	}
189 	mirror = &layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR];
190 	*mirror = *region;
191 	mirror->type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR;
192 	mirror->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
193 	mirror->name = "band_md_mirror";
194 	mirror->current.offset += region->current.blocks;
195 	offset += mirror->current.blocks;
196 
197 	if (offset >= layout->nvc.total_blocks) {
198 		goto error;
199 	}
200 
201 	/*
202 	 * Initialize P2L checkpointing regions
203 	 */
204 	SPDK_STATIC_ASSERT(SPDK_COUNTOF(p2l_region_name) == FTL_LAYOUT_REGION_TYPE_P2L_COUNT,
205 			   "Incorrect # of P2L region names");
206 	for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
207 	     region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX;
208 	     region_type++) {
209 		if (offset >= layout->nvc.total_blocks) {
210 			goto error;
211 		}
212 		region = &layout->region[region_type];
213 		region->type = region_type;
214 		region->name = p2l_region_name[region_type - FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN];
215 		region->current.version = FTL_P2L_VERSION_CURRENT;
216 		region->prev.version = FTL_P2L_VERSION_CURRENT;
217 		region->current.offset = offset;
218 		region->current.blocks = blocks_region(layout->p2l.ckpt_pages * FTL_BLOCK_SIZE);
219 		region->entry_size = 1;
220 		region->num_entries = region->current.blocks;
221 		set_region_bdev_nvc(region, dev);
222 		offset += region->current.blocks;
223 	}
224 
225 	/*
226 	 * Initialize trim metadata region
227 	 */
228 	if (offset >= layout->nvc.total_blocks) {
229 		goto error;
230 	}
231 	l2p_blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks;
232 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD];
233 	region->type = FTL_LAYOUT_REGION_TYPE_TRIM_MD;
234 	region->mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR;
235 	region->name = "trim_md";
236 	region->current.version = 0;
237 	region->prev.version = 0;
238 	region->current.offset = offset;
239 	region->current.blocks = blocks_region(l2p_blocks * sizeof(uint64_t));
240 	region->entry_size = 1;
241 	region->num_entries = region->current.blocks;
242 	set_region_bdev_nvc(region, dev);
243 	offset += region->current.blocks;
244 
245 	/* Initialize trim metadata mirror region */
246 	if (offset >= layout->nvc.total_blocks) {
247 		goto error;
248 	}
249 	mirror = &layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR];
250 	*mirror = *region;
251 	mirror->type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR;
252 	mirror->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
253 	mirror->name = "trim_md_mirror";
254 	mirror->current.offset += region->current.blocks;
255 	offset += mirror->current.blocks;
256 
257 	/*
258 	 * Initialize NV Cache metadata
259 	 */
260 	if (offset >= layout->nvc.total_blocks) {
261 		goto error;
262 	}
263 
264 	left = layout->nvc.total_blocks - offset;
265 	layout->nvc.chunk_data_blocks =
266 		FTL_NV_CACHE_CHUNK_DATA_SIZE(ftl_get_num_blocks_in_band(dev)) / FTL_BLOCK_SIZE;
267 	layout->nvc.chunk_meta_size = FTL_NV_CACHE_CHUNK_MD_SIZE;
268 	layout->nvc.chunk_count = (left * FTL_BLOCK_SIZE) /
269 				  FTL_NV_CACHE_CHUNK_SIZE(ftl_get_num_blocks_in_band(dev));
270 	layout->nvc.chunk_tail_md_num_blocks = ftl_nv_cache_chunk_tail_md_num_blocks(&dev->nv_cache);
271 
272 	if (0 == layout->nvc.chunk_count) {
273 		goto error;
274 	}
275 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD];
276 	region->type = FTL_LAYOUT_REGION_TYPE_NVC_MD;
277 	region->mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR;
278 	region->name = "nvc_md";
279 	region->current.version = region->prev.version = FTL_NVC_VERSION_CURRENT;
280 	region->current.offset = offset;
281 	region->current.blocks = blocks_region(layout->nvc.chunk_count *
282 					       sizeof(struct ftl_nv_cache_chunk_md));
283 	region->entry_size = sizeof(struct ftl_nv_cache_chunk_md) / FTL_BLOCK_SIZE;
284 	region->num_entries = layout->nvc.chunk_count;
285 	set_region_bdev_nvc(region, dev);
286 	offset += region->current.blocks;
287 
288 	/*
289 	 * Initialize NV Cache metadata mirror
290 	 */
291 	mirror = &layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR];
292 	*mirror = *region;
293 	mirror->type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR;
294 	mirror->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
295 	mirror->name = "nvc_md_mirror";
296 	mirror->current.offset += region->current.blocks;
297 	offset += mirror->current.blocks;
298 
299 	/*
300 	 * Initialize data region on NV cache
301 	 */
302 	if (offset >= layout->nvc.total_blocks) {
303 		goto error;
304 	}
305 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_DATA_NVC];
306 	region->type = FTL_LAYOUT_REGION_TYPE_DATA_NVC;
307 	region->name = "data_nvc";
308 	region->current.version = region->prev.version = 0;
309 	region->current.offset = offset;
310 	region->current.blocks = layout->nvc.chunk_count * layout->nvc.chunk_data_blocks;
311 	set_region_bdev_nvc(region, dev);
312 	offset += region->current.blocks;
313 
314 	left = layout->nvc.total_blocks - offset;
315 	if (left > layout->nvc.chunk_data_blocks) {
316 		FTL_ERRLOG(dev, "Error when setup NV cache layout\n");
317 		return -1;
318 	}
319 
320 	if (offset > layout->nvc.total_blocks) {
321 		FTL_ERRLOG(dev, "Error when setup NV cache layout\n");
322 		goto error;
323 	}
324 
325 	return 0;
326 
327 error:
328 	FTL_ERRLOG(dev, "Insufficient NV Cache capacity to preserve metadata\n");
329 	return -1;
330 }
331 
332 static ftl_addr
333 layout_base_offset(struct spdk_ftl_dev *dev)
334 {
335 	ftl_addr addr;
336 
337 	addr = dev->num_bands * ftl_get_num_blocks_in_band(dev);
338 	return addr;
339 }
340 
341 static int
342 setup_layout_base(struct spdk_ftl_dev *dev)
343 {
344 	uint64_t left, offset;
345 	struct ftl_layout *layout = &dev->layout;
346 	struct ftl_layout_region *region;
347 	uint64_t data_base_alignment = 8 * ftl_bitmap_buffer_alignment;
348 	/* Allocating a ftl_bitmap requires a 8B input buffer alignment, since we're reusing the global valid map md buffer
349 	 * this means that each band starting address needs to be aligned too - each device sector takes 1b in the valid map,
350 	 * so 64 sectors (8*8) is the needed alignment
351 	 */
352 
353 	layout->base.num_usable_blocks = ftl_get_num_blocks_in_band(dev);
354 	layout->base.user_blocks = ftl_band_user_blocks(dev->bands);
355 
356 	/* Base device layout is following:
357 	 * - superblock
358 	 * - data
359 	 * - valid map
360 	 */
361 	offset = layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.blocks;
362 	offset = SPDK_ALIGN_CEIL(offset, data_base_alignment);
363 
364 	/* Setup data region on base device */
365 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_DATA_BASE];
366 	region->type = FTL_LAYOUT_REGION_TYPE_DATA_BASE;
367 	region->name = "data_btm";
368 	region->current.version = region->prev.version = 0;
369 	region->current.offset = offset;
370 	region->current.blocks = layout_base_offset(dev);
371 	set_region_bdev_btm(region, dev);
372 
373 	offset += region->current.blocks;
374 
375 	/* Setup validity map */
376 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_VALID_MAP];
377 	region->type = FTL_LAYOUT_REGION_TYPE_VALID_MAP;
378 	region->name = "vmap";
379 	region->current.version = region->prev.version = 0;
380 	region->current.offset = offset;
381 	region->current.blocks = blocks_region(spdk_divide_round_up(
382 			layout->base.total_blocks + layout->nvc.total_blocks, 8));
383 	set_region_bdev_btm(region, dev);
384 	offset += region->current.blocks;
385 
386 	/* Checking for underflow */
387 	left = layout->base.total_blocks - offset;
388 	if (left > layout->base.total_blocks) {
389 		FTL_ERRLOG(dev, "Error when setup base device layout\n");
390 		return -1;
391 	}
392 
393 	if (offset > layout->base.total_blocks) {
394 		FTL_ERRLOG(dev, "Error when setup base device layout\n");
395 		return -1;
396 	}
397 
398 	return 0;
399 }
400 
401 int
402 ftl_layout_setup(struct spdk_ftl_dev *dev)
403 {
404 	const struct spdk_bdev *bdev;
405 	struct ftl_layout *layout = &dev->layout;
406 	uint64_t i;
407 	uint64_t num_lbas;
408 
409 	bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
410 	layout->base.total_blocks = spdk_bdev_get_num_blocks(bdev);
411 
412 	bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
413 	layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev);
414 
415 	/* Initialize mirrors types */
416 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
417 		if (i == FTL_LAYOUT_REGION_TYPE_SB) {
418 			/* Super block has been already initialized */
419 			continue;
420 		}
421 
422 		layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
423 	}
424 
425 	/*
426 	 * Initialize L2P information
427 	 */
428 	num_lbas = get_num_user_lbas(dev);
429 	if (dev->num_lbas == 0) {
430 		assert(dev->conf.mode & SPDK_FTL_MODE_CREATE);
431 		dev->num_lbas = num_lbas;
432 		dev->sb->lba_cnt = num_lbas;
433 	} else if (dev->num_lbas != num_lbas) {
434 		FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n");
435 		return -EINVAL;
436 	}
437 	layout->l2p.addr_length = spdk_u64log2(layout->base.total_blocks + layout->nvc.total_blocks) + 1;
438 	layout->l2p.addr_size = layout->l2p.addr_length > 32 ? 8 : 4;
439 	layout->l2p.lbas_in_page = FTL_BLOCK_SIZE / layout->l2p.addr_size;
440 
441 	/* Setup P2L ckpt */
442 	layout->p2l.ckpt_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev), dev->xfer_size);
443 
444 	if (setup_layout_nvc(dev)) {
445 		return -EINVAL;
446 	}
447 
448 	if (setup_layout_base(dev)) {
449 		return -EINVAL;
450 	}
451 
452 	if (ftl_validate_regions(dev, layout)) {
453 		return -EINVAL;
454 	}
455 
456 	FTL_NOTICELOG(dev, "Base device capacity:         %.2f MiB\n",
457 		      blocks2mib(layout->base.total_blocks));
458 	FTL_NOTICELOG(dev, "NV cache device capacity:       %.2f MiB\n",
459 		      blocks2mib(layout->nvc.total_blocks));
460 	FTL_NOTICELOG(dev, "L2P entries:                    %"PRIu64"\n", dev->num_lbas);
461 	FTL_NOTICELOG(dev, "L2P address size:               %"PRIu64"\n", layout->l2p.addr_size);
462 	FTL_NOTICELOG(dev, "P2L checkpoint pages:           %"PRIu64"\n", layout->p2l.ckpt_pages);
463 
464 	return 0;
465 }
466 
467 #ifdef SPDK_FTL_VSS_EMU
468 void
469 ftl_layout_setup_vss_emu(struct spdk_ftl_dev *dev)
470 {
471 	const struct spdk_bdev *bdev;
472 	struct ftl_layout *layout = &dev->layout;
473 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS];
474 
475 	assert(layout->md[FTL_LAYOUT_REGION_TYPE_VSS] == NULL);
476 
477 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS];
478 	region->type = FTL_LAYOUT_REGION_TYPE_VSS;
479 	region->name = "vss";
480 	region->current.version = region->prev.version = 0;
481 	region->current.offset = 0;
482 
483 	bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
484 	layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev);
485 	region->current.blocks = blocks_region(dev->nv_cache.md_size * layout->nvc.total_blocks);
486 
487 	region->vss_blksz = 0;
488 	region->bdev_desc = dev->nv_cache.bdev_desc;
489 	region->ioch = dev->nv_cache.cache_ioch;
490 
491 	assert(region->bdev_desc != NULL);
492 	assert(region->ioch != NULL);
493 }
494 #endif
495 
496 int
497 ftl_layout_setup_superblock(struct spdk_ftl_dev *dev)
498 {
499 	struct ftl_layout *layout = &dev->layout;
500 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
501 	uint64_t total_blocks, offset, left;
502 
503 	assert(layout->md[FTL_LAYOUT_REGION_TYPE_SB] == NULL);
504 
505 	/* Initialize superblock region */
506 	region->type = FTL_LAYOUT_REGION_TYPE_SB;
507 	region->mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE;
508 	region->name = "sb";
509 	region->current.version = FTL_SB_VERSION_CURRENT;
510 	region->prev.version = FTL_SB_VERSION_CURRENT;
511 	region->current.offset = 0;
512 
513 	/*
514 	 * VSS region must go first in case SB to make calculating its relative size easier
515 	 */
516 #ifdef SPDK_FTL_VSS_EMU
517 	region->current.offset = layout->region[FTL_LAYOUT_REGION_TYPE_VSS].current.offset +
518 				 layout->region[FTL_LAYOUT_REGION_TYPE_VSS].current.blocks;
519 #endif
520 
521 	region->current.blocks = blocks_region(FTL_SUPERBLOCK_SIZE);
522 	region->vss_blksz = 0;
523 	region->bdev_desc = dev->nv_cache.bdev_desc;
524 	region->ioch = dev->nv_cache.cache_ioch;
525 
526 	assert(region->bdev_desc != NULL);
527 	assert(region->ioch != NULL);
528 
529 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
530 	region->type = FTL_LAYOUT_REGION_TYPE_SB_BASE;
531 	region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
532 	region->name = "sb_mirror";
533 	region->current.version = FTL_SB_VERSION_CURRENT;
534 	region->prev.version = FTL_SB_VERSION_CURRENT;
535 	region->current.offset = 0;
536 	region->current.blocks = blocks_region(FTL_SUPERBLOCK_SIZE);
537 	set_region_bdev_btm(region, dev);
538 
539 	/* Check if SB can be stored at the end of base device */
540 	total_blocks = spdk_bdev_get_num_blocks(
541 			       spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
542 	offset = region->current.offset + region->current.blocks;
543 	left = total_blocks - offset;
544 	if ((left > total_blocks) || (offset > total_blocks)) {
545 		FTL_ERRLOG(dev, "Error when setup base device super block\n");
546 		return -1;
547 	}
548 
549 	return 0;
550 }
551 
552 void
553 ftl_layout_dump(struct spdk_ftl_dev *dev)
554 {
555 	struct ftl_layout *layout = &dev->layout;
556 	int i;
557 	FTL_NOTICELOG(dev, "NV cache layout:\n");
558 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
559 		if (layout->region[i].bdev_desc == dev->nv_cache.bdev_desc) {
560 			dump_region(dev, &layout->region[i]);
561 		}
562 	}
563 	FTL_NOTICELOG(dev, "Bottom device layout:\n");
564 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
565 		if (layout->region[i].bdev_desc == dev->base_bdev_desc) {
566 			dump_region(dev, &layout->region[i]);
567 		}
568 	}
569 }
570