Commit 9f42898a authored by Lukasz Lasek's avatar Lukasz Lasek Committed by Tomasz Zawadzki
Browse files

lib/ftl: Create and load FTL using new superblock



Switch FTL to make use of the new superblock version. The ability to
load older (i.e. v4) FTL instances is added in future commits.

Change-Id: I5753024b6423b2009df067a798f400e0214f6ab7
Signed-off-by: default avatarLukasz Lasek <lukasz.lasek@solidigm.com>
Signed-off-by: default avatarMariusz Barczak <Mariusz.Barczak@solidigmtechnology.com>
Signed-off-by: default avatarMateusz Kozlowski <mateusz.kozlowski@solidigm.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/19596


Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarBen Walker <ben@nvidia.com>
parent d55b9f29
Loading
Loading
Loading
Loading
+40 −12
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include "ftl_base_dev.h"
#include "ftl_core.h"
#include "ftl_layout.h"
#include "ftl_band.h"
#include "utils/ftl_layout_tracker_bdev.h"

static bool
@@ -27,51 +28,78 @@ md_region_setup(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
	region->vss_blksz = 0;
}

static struct ftl_layout_region *
static int
md_region_create(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
		 uint32_t reg_version, size_t entry_size, size_t entry_count)
		 uint32_t reg_version, size_t reg_blks)
{
	struct ftl_layout *layout = &dev->layout;
	struct ftl_layout_region *region;
	uint64_t data_base_alignment, reg_blks;
	const struct ftl_layout_tracker_bdev_region_props *reg_props;
	uint64_t data_base_alignment;

	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
	reg_blks = ftl_md_region_align_blocks(dev, reg_blks);

	/* Allocating a ftl_bitmap requires a 8B input buffer alignment, since we're reusing the global valid map md buffer
	 * this means that each band starting address needs to be aligned too - each device sector takes 1b in the valid map,
	 * so 64 sectors (8*8) is the needed alignment
	 */
	data_base_alignment = 8 * ftl_bitmap_buffer_alignment;
	reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size);
	reg_props = ftl_layout_tracker_bdev_add_region(dev->base_layout_tracker, reg_type, reg_version,
			reg_blks, data_base_alignment);
	if (!reg_props) {
		return NULL;
		return -1;
	}
	assert(reg_props->type == reg_type);
	assert(reg_props->ver == reg_version);
	assert(reg_props->blk_sz == reg_blks);
	assert(reg_props->blk_offs + reg_blks <= dev->layout.base.total_blocks);
	return 0;
}

static int
md_region_open(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, uint32_t reg_version,
	       size_t entry_size, size_t entry_count, struct ftl_layout_region *region)
{
	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
	uint64_t reg_blks = ftl_md_region_blocks(dev, entry_size * entry_count);

	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);

	while (true) {
		ftl_layout_tracker_bdev_find_next_region(dev->base_layout_tracker, reg_type, &reg_search_ctx);
		if (!reg_search_ctx || reg_search_ctx->ver == reg_version) {
			break;
		}
	}

	if (!reg_search_ctx || reg_search_ctx->blk_sz < reg_blks) {
		/* Region not found or insufficient space */
		return -1;
	}

	if (!region) {
		return 0;
	}

	region = &layout->region[reg_type];
	md_region_setup(dev, reg_type, region);

	region->current.version = region->prev.version = reg_version;
	region->current.offset = reg_props->blk_offs;
	region->current.blocks = reg_blks;
	region->entry_size = entry_size / FTL_BLOCK_SIZE;
	region->num_entries = entry_count;

	return region;
	region->current.version = region->prev.version = reg_version;
	region->current.offset = reg_search_ctx->blk_offs;
	region->current.blocks = reg_search_ctx->blk_sz;

	return 0;
}

struct ftl_base_device_type base_bdev = {
	.name = "base_bdev",
	.ops = {
		.is_bdev_compatible = is_bdev_compatible,

		.md_layout_ops = {
			.region_create = md_region_create,
			.region_open = md_region_open,
		},
	}
};
+117 −30
Original line number Diff line number Diff line
@@ -15,9 +15,10 @@
#include "nvc/ftl_nvc_dev.h"
#include "utils/ftl_layout_tracker_bdev.h"

#define FTL_NV_CACHE_CHUNK_DATA_SIZE(blocks) ((uint64_t)blocks * FTL_BLOCK_SIZE)
#define FTL_NV_CACHE_CHUNK_SIZE(blocks) \
	(FTL_NV_CACHE_CHUNK_DATA_SIZE(blocks) + (2 * FTL_NV_CACHE_CHUNK_MD_SIZE))
enum ftl_layout_setup_mode {
	FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT = 0,
	FTL_LAYOUT_SETUP_MODE_NO_RESTRICT,
};

static inline float
blocks2mib(uint64_t blocks)
@@ -202,8 +203,13 @@ layout_region_create_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type r
			 uint32_t reg_version, size_t entry_size, size_t entry_count)
{
	const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_desc->ops.md_layout_ops;
	size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size);

	if (md_ops->region_create(dev, reg_type, reg_version, entry_size, entry_count)) {
	if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) {
		return -1;
	}
	if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count,
				&dev->layout.region[reg_type])) {
		return -1;
	}
	return 0;
@@ -214,15 +220,20 @@ layout_region_create_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type
			  uint32_t reg_version, size_t entry_size, size_t entry_count)
{
	const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops;
	size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size);

	if (md_ops->region_create(dev, reg_type, reg_version, entry_size, entry_count)) {
	if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) {
		return -1;
	}
	if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count,
				&dev->layout.region[reg_type])) {
		return -1;
	}
	return 0;
}

static int
setup_layout_nvc(struct spdk_ftl_dev *dev)
layout_setup_default_nvc(struct spdk_ftl_dev *dev)
{
	int region_type;
	uint64_t left, l2p_blocks;
@@ -279,14 +290,8 @@ setup_layout_nvc(struct spdk_ftl_dev *dev)
	 * Initialize NV Cache metadata
	 */
	left = layout_blocks_left(dev, dev->nvc_layout_tracker);

	layout->nvc.chunk_data_blocks =
		FTL_NV_CACHE_CHUNK_DATA_SIZE(ftl_get_num_blocks_in_band(dev)) / FTL_BLOCK_SIZE;
	layout->nvc.chunk_meta_size = FTL_NV_CACHE_CHUNK_MD_SIZE;
	layout->nvc.chunk_count = (left * FTL_BLOCK_SIZE) /
				  FTL_NV_CACHE_CHUNK_SIZE(ftl_get_num_blocks_in_band(dev));
	layout->nvc.chunk_tail_md_num_blocks = ftl_nv_cache_chunk_tail_md_num_blocks(&dev->nv_cache);

	if (0 == layout->nvc.chunk_count) {
		goto error;
	}
@@ -320,14 +325,11 @@ error:
}

static int
setup_layout_base(struct spdk_ftl_dev *dev)
layout_setup_default_base(struct spdk_ftl_dev *dev)
{
	struct ftl_layout *layout = &dev->layout;
	uint64_t valid_map_size;

	layout->base.num_usable_blocks = ftl_get_num_blocks_in_band(dev);
	layout->base.user_blocks = ftl_band_user_blocks(dev->bands);

	/* Base device layout is as follows:
	 * - superblock
	 * - data
@@ -347,21 +349,72 @@ setup_layout_base(struct spdk_ftl_dev *dev)
	return 0;
}

static int
layout_setup_default(struct spdk_ftl_dev *dev)
{
	if (layout_setup_default_nvc(dev) || layout_setup_default_base(dev)) {
		return -1;
	}
	return 0;
}

static int
layout_load(struct spdk_ftl_dev *dev)
{
	if (ftl_superblock_load_blob_area(dev)) {
		return -1;
	}
	dev->layout.nvc.chunk_count = dev->layout.region[FTL_LAYOUT_REGION_TYPE_DATA_NVC].num_entries;
	if (ftl_superblock_md_layout_apply(dev)) {
		return -1;
	}
	return 0;
}

int
ftl_layout_setup(struct spdk_ftl_dev *dev)
{
	struct ftl_layout *layout = &dev->layout;
	uint64_t i;
	uint64_t num_lbas;
	enum ftl_layout_setup_mode setup_mode;
	int rc;

	/* Initialize mirrors types */
	/*
	 * SB v5 adds the ability to create MD regions dynamically, i.e. depending on the underlying device type.
	 * For compatibility reasons:
	 * 1. When upgrading from pre-v5 SB, only the legacy default layout is created.
	 *    Pre-v5: some regions were static and not stored in the SB layout. These must be created to match
	 *            the legacy default layout.
	 *    v5: all regions are stored in the SB layout. Upon the SB upgrade, the legacy default layout
	 *        is updated with pre-v5 layout stored in the SB. The whole layout is then stored in v5 SB.
	 *
	 * 2. When SB v5 or later was loaded, the layout is instantiated from the nvc and base layout blobs.
	 *    No default layout is created.
	 *
	 * 3. When the FTL layout is being created for the first time, there are no restrictions.
	 *
	 * Any new regions to be created in cases (1) and (2) can only be placed in the unallocated area
	 * of the underlying device.
	 */

	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
		setup_mode = FTL_LAYOUT_SETUP_MODE_NO_RESTRICT;
	} else {
		setup_mode = FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT;
	}
	FTL_NOTICELOG(dev, "FTL layout setup mode %d\n", (int)setup_mode);

	/* Invalidate all regions */
	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
		if (i == FTL_LAYOUT_REGION_TYPE_SB) {
		if (i == FTL_LAYOUT_REGION_TYPE_SB || i == FTL_LAYOUT_REGION_TYPE_SB_BASE) {
			/* Super block has been already initialized */
			continue;
		}

		layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
		/* Mark the region inactive */
		layout->region[i].type = FTL_LAYOUT_REGION_TYPE_INVALID;
	}

	/*
@@ -383,18 +436,38 @@ ftl_layout_setup(struct spdk_ftl_dev *dev)
	/* Setup P2L ckpt */
	layout->p2l.ckpt_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev), dev->xfer_size);

	if (setup_layout_nvc(dev)) {
	layout->nvc.chunk_data_blocks =
		FTL_NV_CACHE_CHUNK_DATA_SIZE(ftl_get_num_blocks_in_band(dev)) / FTL_BLOCK_SIZE;
	layout->nvc.chunk_meta_size = FTL_NV_CACHE_CHUNK_MD_SIZE;
	layout->nvc.chunk_tail_md_num_blocks = ftl_nv_cache_chunk_tail_md_num_blocks(&dev->nv_cache);

	layout->base.num_usable_blocks = ftl_get_num_blocks_in_band(dev);
	layout->base.user_blocks = ftl_band_user_blocks(dev->bands);

	switch (setup_mode) {
	case FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT:
		if (layout_load(dev)) {
			return -EINVAL;
		}
		break;

	if (setup_layout_base(dev)) {
	case FTL_LAYOUT_SETUP_MODE_NO_RESTRICT:
		if (layout_setup_default(dev)) {
			return -EINVAL;
		}
		break;

	default:
		ftl_abort();
		break;
	}

	if (ftl_validate_regions(dev, layout)) {
		return -EINVAL;
	}

	rc = ftl_superblock_store_blob_area(dev);

	FTL_NOTICELOG(dev, "Base device capacity:         %.2f MiB\n",
		      blocks2mib(layout->base.total_blocks));
	FTL_NOTICELOG(dev, "NV cache device capacity:       %.2f MiB\n",
@@ -402,8 +475,9 @@ ftl_layout_setup(struct spdk_ftl_dev *dev)
	FTL_NOTICELOG(dev, "L2P entries:                    %"PRIu64"\n", dev->num_lbas);
	FTL_NOTICELOG(dev, "L2P address size:               %"PRIu64"\n", layout->l2p.addr_size);
	FTL_NOTICELOG(dev, "P2L checkpoint pages:           %"PRIu64"\n", layout->p2l.ckpt_pages);
	FTL_NOTICELOG(dev, "NV cache chunk count            %"PRIu64"\n", dev->layout.nvc.chunk_count);

	return 0;
	return rc;
}

int
@@ -413,8 +487,6 @@ ftl_layout_setup_superblock(struct spdk_ftl_dev *dev)
	struct ftl_layout *layout = &dev->layout;
	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
	uint64_t total_blocks, offset, left;
	const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_desc->ops.md_layout_ops;
	const struct ftl_md_layout_ops *base_md_ops = &dev->base_type->ops.md_layout_ops;

	assert(layout->md[FTL_LAYOUT_REGION_TYPE_SB] == NULL);

@@ -425,7 +497,7 @@ ftl_layout_setup_superblock(struct spdk_ftl_dev *dev)
	layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev);

	/* Initialize superblock region */
	if (!md_ops->region_create(dev, FTL_LAYOUT_REGION_TYPE_SB, FTL_SB_VERSION_CURRENT,
	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_SB, FTL_SB_VERSION_CURRENT,
				     superblock_region_size(dev), 1)) {
		FTL_ERRLOG(dev, "Error when setting up primary super block\n");
		return -1;
@@ -435,7 +507,7 @@ ftl_layout_setup_superblock(struct spdk_ftl_dev *dev)
	assert(region->ioch != NULL);
	assert(region->current.offset == 0);

	if (!base_md_ops->region_create(dev, FTL_LAYOUT_REGION_TYPE_SB_BASE, FTL_SB_VERSION_CURRENT,
	if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_SB_BASE, FTL_SB_VERSION_CURRENT,
				      superblock_region_size(dev), 1)) {
		FTL_ERRLOG(dev, "Error when setting up secondary super block\n");
		return -1;
@@ -458,6 +530,21 @@ ftl_layout_setup_superblock(struct spdk_ftl_dev *dev)
	return 0;
}

int
ftl_layout_clear_superblock(struct spdk_ftl_dev *dev)
{
	int rc;

	rc = ftl_layout_tracker_bdev_rm_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB,
					       FTL_SB_VERSION_CURRENT);
	if (rc) {
		return rc;
	}

	return ftl_layout_tracker_bdev_rm_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB_BASE,
			FTL_SB_VERSION_CURRENT);
}

void
ftl_layout_dump(struct spdk_ftl_dev *dev)
{
+18 −4
Original line number Diff line number Diff line
@@ -12,6 +12,10 @@
struct spdk_ftl_dev;
struct ftl_md;

#define FTL_NV_CACHE_CHUNK_DATA_SIZE(blocks) ((uint64_t)blocks * FTL_BLOCK_SIZE)
#define FTL_NV_CACHE_CHUNK_SIZE(blocks) \
	(FTL_NV_CACHE_CHUNK_DATA_SIZE(blocks) + (2 * FTL_NV_CACHE_CHUNK_MD_SIZE))

#define FTL_LAYOUT_REGION_TYPE_P2L_COUNT \
	(FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX - FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN + 1)

@@ -56,7 +60,8 @@ enum ftl_layout_region_type {
	/* Mirrored information about trim */
	FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR = 15,

	FTL_LAYOUT_REGION_TYPE_MAX = 16
	FTL_LAYOUT_REGION_TYPE_MAX = 16,
	FTL_LAYOUT_REGION_TYPE_MAX_V3 = 16
};

/* last nvc/base region in terms of lba address space */
@@ -172,10 +177,14 @@ struct ftl_md_layout_ops {
	 * @param entry_size MD entry size in bytes
	 * @param entry_count number of MD entries
	 *
	 * @return pointer to FTL MD region descriptor or NULL if failed
	 * @retval 0 on success
	 * @retval -1 on fault
	 */
	struct ftl_layout_region *(*region_create)(struct spdk_ftl_dev *dev,
			enum ftl_layout_region_type reg_type, uint32_t reg_version, size_t entry_size, size_t entry_count);
	int (*region_create)(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
			     uint32_t reg_version, size_t reg_blks);

	int (*region_open)(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
			   uint32_t reg_version, size_t entry_size, size_t entry_count, struct ftl_layout_region *region);
};

/**
@@ -217,6 +226,11 @@ int ftl_layout_setup(struct spdk_ftl_dev *dev);
 */
int ftl_layout_setup_superblock(struct spdk_ftl_dev *dev);

/**
 * @brief Clear the superblock from the layout. Used after failure of shared memory files verification causes a retry.
 */
int ftl_layout_clear_superblock(struct spdk_ftl_dev *dev);

void ftl_layout_dump(struct spdk_ftl_dev *dev);
int ftl_validate_regions(struct spdk_ftl_dev *dev, struct ftl_layout *layout);

+46 −15
Original line number Diff line number Diff line
@@ -9,19 +9,23 @@
#include "ftl_layout.h"
#include "upgrade/ftl_sb_upgrade.h"
#include "upgrade/ftl_sb_v3.h"
#include "upgrade/ftl_sb_v5.h"

static bool ftl_superblock_v2_check_magic(union ftl_superblock_ver *sb_ver);

struct sb_ops {
	bool (*check_magic)(union ftl_superblock_ver *sb_ver);
	bool (*layout_is_empty)(union ftl_superblock_ver *sb_ver);
	void (*layout_dump)(struct spdk_ftl_dev *dev);

	bool (*blob_is_empty)(union ftl_superblock_ver *sb_ver);
	bool (*blob_validate)(struct spdk_ftl_dev *dev);
	int (*blob_store)(struct spdk_ftl_dev *dev);
	int (*blob_load)(struct spdk_ftl_dev *dev);

	int (*upgrade_region)(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg,
			      uint32_t new_version);

	int (*layout_apply)(struct spdk_ftl_dev *dev);
	void (*layout_dump)(struct spdk_ftl_dev *dev);
};

static struct sb_ops *
@@ -39,19 +43,24 @@ sb_get_ops(uint64_t version)
		},
		[FTL_SB_VERSION_3] = {
			.check_magic = ftl_superblock_v3_check_magic,
			.layout_is_empty = ftl_superblock_v3_md_layout_is_empty,
			.layout_dump = ftl_superblock_v3_md_layout_dump,
			.blob_store = ftl_superblock_v3_md_layout_build,
			.blob_is_empty = ftl_superblock_v3_md_layout_is_empty,
			.blob_load = ftl_superblock_v3_md_layout_load_all,
			.upgrade_region = ftl_superblock_v3_md_layout_upgrade_region,
			.layout_dump = ftl_superblock_v3_md_layout_dump,
		},
		[FTL_SB_VERSION_4] = {
			.check_magic = ftl_superblock_v3_check_magic,
			.layout_is_empty = ftl_superblock_v3_md_layout_is_empty,
			.layout_dump = ftl_superblock_v3_md_layout_dump,
			.blob_store = ftl_superblock_v3_md_layout_build,
			.blob_is_empty = ftl_superblock_v3_md_layout_is_empty,
			.blob_load = ftl_superblock_v3_md_layout_load_all,
			.upgrade_region = ftl_superblock_v3_md_layout_upgrade_region,
			.layout_dump = ftl_superblock_v3_md_layout_dump,
		},
		[FTL_SB_VERSION_5] = {
			.check_magic = ftl_superblock_v3_check_magic,
			.blob_is_empty = ftl_superblock_v5_is_blob_area_empty,
			.blob_validate = ftl_superblock_v5_validate_blob_area,
			.blob_store = ftl_superblock_v5_store_blob_area,
			.blob_load = ftl_superblock_v5_load_blob_area,
			.layout_apply = ftl_superblock_v5_md_layout_apply,
			.layout_dump = ftl_superblock_v5_md_layout_dump,
		},
	};

@@ -82,20 +91,31 @@ ftl_superblock_check_magic(struct ftl_superblock *sb)
}

bool
ftl_superblock_md_layout_is_empty(struct ftl_superblock *sb)
ftl_superblock_is_blob_area_empty(struct ftl_superblock *sb)
{
	union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)sb;
	struct sb_ops *ops = sb_get_ops(sb_ver->header.version);

	if (!ops || !ops->layout_is_empty) {
	if (!ops || !ops->blob_is_empty) {
		ftl_abort();
		return false;
	}
	return ops->layout_is_empty(sb_ver);
	return ops->blob_is_empty(sb_ver);
}

bool
ftl_superblock_validate_blob_area(struct spdk_ftl_dev *dev)
{
	struct sb_ops *ops = sb_get_ops(dev->sb->header.version);

	if (!ops || !ops->blob_validate) {
		return true;
	}
	return ops->blob_validate(dev);
}

int
ftl_superblock_md_layout_build(struct spdk_ftl_dev *dev)
ftl_superblock_store_blob_area(struct spdk_ftl_dev *dev)
{
	struct sb_ops *ops = sb_get_ops(dev->sb->header.version);

@@ -107,7 +127,7 @@ ftl_superblock_md_layout_build(struct spdk_ftl_dev *dev)
}

int
ftl_superblock_md_layout_load_all(struct spdk_ftl_dev *dev)
ftl_superblock_load_blob_area(struct spdk_ftl_dev *dev)
{
	struct sb_ops *ops = sb_get_ops(dev->sb->header.version);

@@ -131,6 +151,17 @@ ftl_superblock_md_layout_upgrade_region(struct spdk_ftl_dev *dev,
	return ops->upgrade_region(dev, reg, new_version);
}

int
ftl_superblock_md_layout_apply(struct spdk_ftl_dev *dev)
{
	struct sb_ops *ops = sb_get_ops(dev->sb->header.version);

	if (!ops || !ops->layout_apply) {
		return 0;
	}
	return ops->layout_apply(dev);
}

void
ftl_superblock_md_layout_dump(struct spdk_ftl_dev *dev)
{
+7 −3
Original line number Diff line number Diff line
@@ -15,15 +15,19 @@ struct ftl_layout_region;

bool ftl_superblock_check_magic(struct ftl_superblock *sb);

bool ftl_superblock_md_layout_is_empty(struct ftl_superblock *sb);
bool ftl_superblock_is_blob_area_empty(struct ftl_superblock *sb);

int ftl_superblock_md_layout_build(struct spdk_ftl_dev *dev);
bool ftl_superblock_validate_blob_area(struct spdk_ftl_dev *dev);

int ftl_superblock_md_layout_load_all(struct spdk_ftl_dev *dev);
int ftl_superblock_store_blob_area(struct spdk_ftl_dev *dev);

int ftl_superblock_load_blob_area(struct spdk_ftl_dev *dev);

int ftl_superblock_md_layout_upgrade_region(struct spdk_ftl_dev *dev,
		struct ftl_layout_region *reg, uint32_t new_version);

int ftl_superblock_md_layout_apply(struct spdk_ftl_dev *dev);

void ftl_superblock_md_layout_dump(struct spdk_ftl_dev *dev);

#endif /* FTL_SB_H */
Loading