Commit f968b954 authored by Mateusz Kozlowski's avatar Mateusz Kozlowski Committed by Tomasz Zawadzki
Browse files

lib/ftl: Superblock v5 introduction



Add the definition of the new superblock layout.
Add functions for manipulating the description of metadata regions within
the new superblock format.

Change-Id: I983a2609c21cd1f2c0ffa3a795cb35301d15e7b7
Signed-off-by: default avatarMateusz Kozlowski <mateusz.kozlowski@solidigm.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/20525


Reviewed-by: default avatarBen Walker <ben@nvidia.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Tested-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
parent e8cbab9e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ C_SRCS += utils/ftl_conf.c utils/ftl_md.c utils/ftl_mempool.c utils/ftl_bitmap.c
C_SRCS += utils/ftl_layout_tracker_bdev.c
C_SRCS += upgrade/ftl_layout_upgrade.c upgrade/ftl_sb_upgrade.c upgrade/ftl_p2l_upgrade.c
C_SRCS += upgrade/ftl_band_upgrade.c upgrade/ftl_chunk_upgrade.c
C_SRCS += upgrade/ftl_sb_v3.c
C_SRCS += upgrade/ftl_sb_v3.c upgrade/ftl_sb_v5.c
C_SRCS += nvc/ftl_nvc_dev.c nvc/ftl_nvc_bdev_vss.c
C_SRCS += base/ftl_base_dev.c base/ftl_base_bdev.c

+12 −0
Original line number Diff line number Diff line
@@ -55,6 +55,18 @@ struct ftl_superblock_v3_md_region {
SPDK_STATIC_ASSERT(sizeof(struct ftl_superblock_v3_md_region) == 32,
		   "ftl_superblock_v3_md_region incorrect size");

struct ftl_superblock_v5_md_blob_hdr {
	/* Blob size in bytes */
	uint16_t		blob_sz;
	/* Reserved */
	uint16_t		reserved1;
	uint32_t		reserved2;
	/* DF pointer to the blob in a SB buf */
	ftl_df_obj_id	df_id;
} __attribute__((packed));
SPDK_STATIC_ASSERT(sizeof(struct ftl_superblock_v5_md_blob_hdr) == 16,
		   "ftl_superblock_v5_md_blob_hdr incorrect size");

struct ftl_superblock_shm {
	/* SHM initialization completed */
	bool				shm_ready;
+56 −0
Original line number Diff line number Diff line
@@ -103,4 +103,60 @@ SPDK_STATIC_ASSERT(offsetof(struct ftl_superblock_v3, header) == 0,
SPDK_STATIC_ASSERT(FTL_SUPERBLOCK_SIZE >= sizeof(struct ftl_superblock_v3),
		   "FTL SB metadata size is invalid");

struct ftl_superblock_v5 {
	struct ftl_superblock_header	header;

	struct spdk_uuid		uuid;

	/* Current sequence number */
	uint64_t			seq_id;

	/* Flag describing clean shutdown */
	uint64_t			clean;

	/* Number of surfaced LBAs */
	uint64_t			lba_cnt;

	/* Percentage of base device blocks not exposed to the user */
	uint64_t			overprovisioning;

	/* Maximum IO depth per band relocate */
	uint64_t			max_reloc_qdepth;

	/* Reserved field */
	uint8_t				reserved3[16];

	/* Last L2P checkpoint +1 (i.e. min_seq_id, 0:no ckpt) */
	uint64_t			ckpt_seq_id;

	struct ftl_superblock_gc_info	gc_info;

	/* Points to the end of blob area */
	ftl_df_obj_id			blob_area_end;

	/* NVC device name */
	char				nvc_dev_name[16];

	/* NVC-stored MD layout tracking info */
	struct ftl_superblock_v5_md_blob_hdr	md_layout_nvc;

	/* Base device name */
	char					base_dev_name[16];

	/* Base dev-stored MD layout tracking info */
	struct ftl_superblock_v5_md_blob_hdr	md_layout_base;

	/* FTL layout params */
	struct ftl_superblock_v5_md_blob_hdr	layout_params;

	/* Start of the blob area */
	char blob_area[0];
} __attribute__((packed));

SPDK_STATIC_ASSERT(offsetof(struct ftl_superblock_v5, header) == 0,
		   "Invalid placement of header");

SPDK_STATIC_ASSERT(FTL_SUPERBLOCK_SIZE >= sizeof(struct ftl_superblock_v5),
		   "FTL SB metadata size is invalid");

#endif /* FTL_SB_PREV_H */
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ union ftl_superblock_ver {
	struct ftl_superblock_header header;
	struct ftl_superblock_v2 v2;
	struct ftl_superblock_v3 v3;
	struct ftl_superblock_v5 v5;
	struct ftl_superblock current;
} __attribute__((packed));

+444 −0
Original line number Diff line number Diff line
/*   SPDX-License-Identifier: BSD-3-Clause
 *   Copyright 2023 Solidigm All Rights Reserved
 *   All rights reserved.
 */

#include "spdk/string.h"

#include "ftl_sb_v5.h"
#include "ftl_core.h"
#include "ftl_layout.h"
#include "ftl_band.h"
#include "upgrade/ftl_sb_prev.h"
#include "upgrade/ftl_sb_upgrade.h"
#include "upgrade/ftl_layout_upgrade.h"
#include "utils/ftl_layout_tracker_bdev.h"

typedef size_t (*blob_store_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz);
typedef int (*blob_load_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz);

bool
ftl_superblock_v5_is_blob_area_empty(union ftl_superblock_ver *sb_ver)
{
	return sb_ver->v5.blob_area_end == 0;
}

static bool
validate_blob_area(struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr,
		   ftl_df_obj_id sb_blob_area_end)
{
	return sb_blob_hdr->df_id <= sb_blob_area_end &&
	       (sb_blob_hdr->df_id + sb_blob_hdr->blob_sz) <= sb_blob_area_end;
}

bool
ftl_superblock_v5_validate_blob_area(struct spdk_ftl_dev *dev)
{
	union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)dev->sb;

	return validate_blob_area(&sb_ver->v5.md_layout_nvc, sb_ver->v5.blob_area_end) &&
	       validate_blob_area(&sb_ver->v5.md_layout_base, sb_ver->v5.blob_area_end) &&
	       validate_blob_area(&sb_ver->v5.layout_params, sb_ver->v5.blob_area_end);
}

static size_t
sb_blob_store(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr,
	      blob_store_fn blob_store, void *sb_blob_area)
{
	struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;
	uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE;
	size_t blob_sz = sb_end - (uintptr_t)sb_blob_area;

	/* Test SB blob area overflow */
	if ((uintptr_t)sb_blob_area < (uintptr_t)sb->blob_area) {
		ftl_bug(true);
		return 0;
	}
	if ((uintptr_t)sb_blob_area >= sb_end) {
		ftl_bug(true);
		return 0;
	}

	blob_sz = blob_store(dev, sb_blob_area, blob_sz);
	sb_blob_hdr->blob_sz = blob_sz;
	sb_blob_hdr->df_id = ftl_df_get_obj_id(sb->blob_area, sb_blob_area);
	return blob_sz;
}

static size_t
base_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz)
{
	return ftl_layout_tracker_bdev_blob_store(dev->base_layout_tracker, blob_buf, blob_buf_sz);
}

static size_t
nvc_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz)
{
	return ftl_layout_tracker_bdev_blob_store(dev->nvc_layout_tracker, blob_buf, blob_buf_sz);
}

int
ftl_superblock_v5_store_blob_area(struct spdk_ftl_dev *dev)
{
	struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;
	void *sb_blob_area;
	size_t blob_sz;

	/* Store the NVC-backed FTL MD layout info */
	sb_blob_area = ftl_df_get_obj_ptr(sb->blob_area, 0);
	spdk_strcpy_pad(sb->nvc_dev_name, dev->nv_cache.nvc_desc->name,
			SPDK_COUNTOF(sb->nvc_dev_name), '\0');
	blob_sz = sb_blob_store(dev, &sb->md_layout_nvc, nvc_blob_store, sb_blob_area);
	FTL_NOTICELOG(dev, "nvc layout blob store 0x%"PRIx64" bytes\n", blob_sz);
	if (!blob_sz) {
		return -1;
	}

	/* Store the base dev-backed FTL MD layout info */
	sb_blob_area += blob_sz;
	spdk_strcpy_pad(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name), '\0');
	blob_sz = sb_blob_store(dev, &sb->md_layout_base, base_blob_store, sb_blob_area);
	FTL_NOTICELOG(dev, "base layout blob store 0x%"PRIx64" bytes\n", blob_sz);
	if (!blob_sz) {
		return -1;
	}

	/* Store the region props */
	sb_blob_area += blob_sz;
	blob_sz = sb_blob_store(dev, &sb->layout_params, ftl_layout_blob_store, sb_blob_area);
	FTL_NOTICELOG(dev, "layout blob store 0x%"PRIx64" bytes\n", blob_sz);
	if (!blob_sz) {
		return -1;
	}

	/* Update the blob area end */
	sb_blob_area += blob_sz;
	sb->blob_area_end = ftl_df_get_obj_id(sb->blob_area, sb_blob_area);

	return 0;
}

typedef const struct ftl_layout_tracker_bdev_region_props *(*sb_md_layout_find_fn)(
	struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker,
	enum ftl_layout_region_type reg_type, void *find_filter);

static int
sb_blob_load(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr,
	     blob_load_fn blob_load)
{
	struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;
	uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE;
	void *blob_area;

	if (sb_blob_hdr->df_id == FTL_DF_OBJ_ID_INVALID) {
		/* Uninitialized blob */
		return -1;
	}

	blob_area = ftl_df_get_obj_ptr(sb->blob_area, sb_blob_hdr->df_id);

	/* Test SB blob area overflow */
	if ((uintptr_t)blob_area < (uintptr_t)sb->blob_area) {
		ftl_bug(true);
		return -1;
	}
	if ((uintptr_t)blob_area + sb_blob_hdr->blob_sz >= sb_end) {
		ftl_bug(true);
		return -1;
	}

	return blob_load(dev, blob_area, sb_blob_hdr->blob_sz);
}

static int
base_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz)
{
	return ftl_layout_tracker_bdev_blob_load(dev->base_layout_tracker, blob_buf, blob_sz);
}

static int
nvc_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz)
{
	return ftl_layout_tracker_bdev_blob_load(dev->nvc_layout_tracker, blob_buf, blob_sz);
}

int
ftl_superblock_v5_load_blob_area(struct spdk_ftl_dev *dev)
{
	struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb;

	/* Load the NVC-backed FTL MD layout info */
	if (strncmp(sb->nvc_dev_name, dev->nv_cache.nvc_desc->name, SPDK_COUNTOF(sb->nvc_dev_name))) {
		return -1;
	}
	FTL_NOTICELOG(dev, "nvc layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->md_layout_nvc.blob_sz);
	if (sb_blob_load(dev, &sb->md_layout_nvc, nvc_blob_load)) {
		return -1;
	}

	/* Load the base dev-backed FTL MD layout info */
	if (strncmp(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name))) {
		return -1;
	}
	FTL_NOTICELOG(dev, "base layout blob load 0x%"PRIx64" bytes\n",
		      (uint64_t)sb->md_layout_base.blob_sz);
	if (sb_blob_load(dev, &sb->md_layout_base, base_blob_load)) {
		return -1;
	}

	/* Load the region props */
	FTL_NOTICELOG(dev, "layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->layout_params.blob_sz);
	if (sb_blob_load(dev, &sb->layout_params, ftl_layout_blob_load)) {
		return -1;
	}

	return 0;
}

void
ftl_superblock_v5_md_layout_dump(struct spdk_ftl_dev *dev)
{
	struct ftl_layout_tracker_bdev *nvc_layout_tracker = dev->nvc_layout_tracker;
	struct ftl_layout_tracker_bdev *base_layout_tracker = dev->base_layout_tracker;
	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;

	FTL_NOTICELOG(dev, "SB metadata layout - nvc:\n");
	while (true) {
		ftl_layout_tracker_bdev_find_next_region(nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID,
				&reg_search_ctx);
		if (!reg_search_ctx) {
			break;
		}

		FTL_NOTICELOG(dev,
			      "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n",
			      reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz);
	}

	reg_search_ctx = NULL;
	FTL_NOTICELOG(dev, "SB metadata layout - base dev:\n");
	while (true) {
		ftl_layout_tracker_bdev_find_next_region(base_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID,
				&reg_search_ctx);
		if (!reg_search_ctx) {
			break;
		}

		FTL_NOTICELOG(dev,
			      "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n",
			      reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz);
	}
}

static int
layout_apply_from_sb_blob(struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker,
			  int (*filter_region_type_fn)(enum ftl_layout_region_type))
{
	struct ftl_layout_region *reg;
	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;

	while (true) {
		ftl_layout_tracker_bdev_find_next_region(layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID,
				&reg_search_ctx);
		if (!reg_search_ctx) {
			break;
		}
		if (reg_search_ctx->type == FTL_LAYOUT_REGION_TYPE_FREE) {
			continue;
		}
		if (filter_region_type_fn(reg_search_ctx->type)) {
			FTL_ERRLOG(dev, "Unknown region found in layout blob: type 0x%"PRIx32"\n", reg_search_ctx->type);
			return -1;
		}

		reg = &dev->layout.region[reg_search_ctx->type];

		/* First region of a given type found */
		if (reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) {
			reg->type = reg_search_ctx->type;
			reg->current.version = reg_search_ctx->ver;
			reg->current.offset = reg_search_ctx->blk_offs;
			reg->current.blocks = reg_search_ctx->blk_sz;
			continue;
		}

		/* Update to the oldest region version found */
		if (reg_search_ctx->ver < reg->current.version) {
			reg->current.version = reg_search_ctx->ver;
			reg->current.offset = reg_search_ctx->blk_offs;
			reg->current.blocks = reg_search_ctx->blk_sz;
			continue;
		}

		/* Skip newer region versions */
		if (reg_search_ctx->ver > reg->current.version) {
			continue;
		}

		/* Current region version already found */
		assert(reg_search_ctx->ver == reg->current.version);
		if (reg->current.offset != reg_search_ctx->blk_offs ||
		    reg->current.blocks != reg_search_ctx->blk_sz) {
			FTL_ERRLOG(dev, "Corrupted layout blob: reg type 0x%"PRIx32"\n", reg_search_ctx->type);
			return -1;
		}
	}
	return 0;
}

static int
layout_region_verify(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
		     uint32_t reg_ver)
{
	struct ftl_layout_region *reg = ftl_layout_region_get(dev, reg_type);

	if (!reg) {
		FTL_ERRLOG(dev, "Region not found in nvc layout blob: reg type 0x%"PRIx32"\n", reg_type);
		return -1;
	}

	/* Unknown version found in the blob */
	if (reg->current.version > reg_ver) {
		FTL_ERRLOG(dev, "Unknown region version found in layout blob: reg type 0x%"PRIx32"\n",
			   reg_type);
		return -1;
	}

	return 0;
}

static int
layout_fixup_base(struct spdk_ftl_dev *dev)
{
	struct ftl_layout_region_descr {
		enum ftl_layout_region_type type;
		uint32_t ver;
		int (*on_reg_miss)(struct spdk_ftl_dev *dev);
	};
	struct ftl_layout_region_descr *reg_descr;
	static struct ftl_layout_region_descr nvc_regs[] = {
		{ .type = FTL_LAYOUT_REGION_TYPE_SB_BASE, .ver = FTL_SB_VERSION_CURRENT },
		{ .type = FTL_LAYOUT_REGION_TYPE_DATA_BASE, .ver = 0 },
		{ .type = FTL_LAYOUT_REGION_TYPE_VALID_MAP, .ver = 0 },
		{ .type = FTL_LAYOUT_REGION_TYPE_INVALID, .ver = 0 },
	};

	for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) {
		struct ftl_layout_region *region;

		if (layout_region_verify(dev, reg_descr->type, reg_descr->ver) &&
		    reg_descr->on_reg_miss && reg_descr->on_reg_miss(dev)) {
			return -1;
		}

		region = &dev->layout.region[reg_descr->type];
		region->type = reg_descr->type;
		region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
		region->name = ftl_md_region_name(reg_descr->type);

		region->bdev_desc = dev->base_bdev_desc;
		region->ioch = dev->base_ioch;
		region->vss_blksz = 0;
	}

	return 0;
}

static int
layout_fixup_nvc(struct spdk_ftl_dev *dev)
{
	struct ftl_layout_region_descr {
		enum ftl_layout_region_type type;
		uint32_t ver;
		enum ftl_layout_region_type mirror_type;
	};
	struct ftl_layout_region_descr *reg_descr;
	static struct ftl_layout_region_descr nvc_regs[] = {
		{ .type = FTL_LAYOUT_REGION_TYPE_SB, .ver = FTL_SB_VERSION_CURRENT, .mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE },
		{ .type = FTL_LAYOUT_REGION_TYPE_L2P, .ver = 0 },
		{ .type = FTL_LAYOUT_REGION_TYPE_BAND_MD, .ver = FTL_BAND_VERSION_CURRENT, .mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR },
		{ .type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, .ver = FTL_BAND_VERSION_CURRENT },
		{ .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD, .ver = 0, .mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR },
		{ .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, .ver = 0 },
		{ .type = FTL_LAYOUT_REGION_TYPE_NVC_MD, .ver = FTL_NVC_VERSION_CURRENT, .mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR },
		{ .type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, .ver = FTL_NVC_VERSION_CURRENT },
		{ .type = FTL_LAYOUT_REGION_TYPE_DATA_NVC, .ver = 0 },
		{ .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC, .ver = FTL_P2L_VERSION_CURRENT },
		{ .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT, .ver = FTL_P2L_VERSION_CURRENT },
		{ .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP, .ver = FTL_P2L_VERSION_CURRENT },
		{ .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT, .ver = FTL_P2L_VERSION_CURRENT },
		{ .type = FTL_LAYOUT_REGION_TYPE_INVALID, .ver = 0 },
	};

	for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) {
		struct ftl_layout_region *region;

		if (layout_region_verify(dev, reg_descr->type, reg_descr->ver)) {
			return -1;
		}

		region = &dev->layout.region[reg_descr->type];
		region->type = reg_descr->type;
		region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
		region->name = ftl_md_region_name(reg_descr->type);

		region->bdev_desc = dev->nv_cache.bdev_desc;
		region->ioch = dev->nv_cache.cache_ioch;
		region->vss_blksz = dev->nv_cache.md_size;

		if (reg_descr->mirror_type) {
			dev->layout.region[reg_descr->type].mirror_type = reg_descr->mirror_type;
		}
	}

	return 0;
}

static int
filter_region_type_base(enum ftl_layout_region_type reg_type)
{
	switch (reg_type) {
	case FTL_LAYOUT_REGION_TYPE_SB_BASE:
	case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
	case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
		return 0;

	default:
		return 1;
	}
}

static int
filter_region_type_nvc(enum ftl_layout_region_type reg_type)
{
	return filter_region_type_base(reg_type) ? 0 : 1;
}

static int
layout_apply_nvc(struct spdk_ftl_dev *dev)
{
	if (layout_apply_from_sb_blob(dev, dev->nvc_layout_tracker, filter_region_type_nvc) ||
	    layout_fixup_nvc(dev)) {
		return -1;
	}
	return 0;
}

static int
layout_apply_base(struct spdk_ftl_dev *dev)
{
	if (layout_apply_from_sb_blob(dev, dev->base_layout_tracker, filter_region_type_base) ||
	    layout_fixup_base(dev)) {
		return -1;
	}
	return 0;
}

int
ftl_superblock_v5_md_layout_apply(struct spdk_ftl_dev *dev)
{
	if (layout_apply_nvc(dev) || layout_apply_base(dev)) {
		return -1;
	}
	return 0;
}
Loading