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

lib/ftl: Upgrade band metadata



The upgrade band metadata includes the band version. Previously,
the band version was stored in the VSS, now VSS for the band metadata
is not used.

Change-Id: I7f9ef9396d308e23bdf9238f93b44582746a2ead
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/+/19602


Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Community-CI: Mellanox Build Bot
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: default avatarArtur Paszkiewicz <artur.paszkiewicz@intel.com>
parent a5c04e6d
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
/*   SPDX-License-Identifier: BSD-3-Clause
 *   Copyright (C) 2018 Intel Corporation.
 *   Copyright 2023 Solidigm All Rights Reserved
 *   All rights reserved.
 */

@@ -693,7 +694,7 @@ ftl_band_initialize_free_state(struct ftl_band *band)
	_ftl_band_set_free(band);
}

void
int
ftl_bands_load_state(struct spdk_ftl_dev *dev)
{
	uint64_t i;
@@ -702,8 +703,16 @@ ftl_bands_load_state(struct spdk_ftl_dev *dev)
	for (i = 0; i < dev->num_bands; i++) {
		band = &dev->bands[i];

		if (band->md->version != FTL_BAND_VERSION_CURRENT) {
			FTL_ERRLOG(dev, "Invalid band version detected, %"PRIu64" (expected %d)\n",
				   band->md->version, FTL_BAND_VERSION_CURRENT);
			return -1;
		}

		if (band->md->state == FTL_BAND_STATE_FREE) {
			ftl_band_initialize_free_state(band);
		}
	}

	return 0;
}
+11 −4
Original line number Diff line number Diff line
/*   SPDX-License-Identifier: BSD-3-Clause
 *   Copyright (C) 2018 Intel Corporation.
 *   Copyright 2023 Solidigm All Rights Reserved
 *   All rights reserved.
 */

@@ -21,8 +22,9 @@

#define FTL_BAND_VERSION_0	0
#define FTL_BAND_VERSION_1	1
#define FTL_BAND_VERSION_2	2

#define FTL_BAND_VERSION_CURRENT FTL_BAND_VERSION_1
#define FTL_BAND_VERSION_CURRENT FTL_BAND_VERSION_2

struct spdk_ftl_dev;
struct ftl_band;
@@ -46,6 +48,9 @@ typedef void (*ftl_band_md_cb)(struct ftl_band *band, void *ctx, enum ftl_md_sta
typedef void (*ftl_band_validate_md_cb)(struct ftl_band *band, bool valid);

struct ftl_band_md {
	/* Band metadata version */
	uint64_t version;

	/* Band iterator for writing */
	struct {
		/* Current physical address of the write pointer */
@@ -83,10 +88,12 @@ struct ftl_band_md {
	uint32_t			p2l_map_checksum;

	/* Reserved */
	uint8_t				reserved2[4028];
	uint8_t				reserved2[4020];
} __attribute__((packed));

SPDK_STATIC_ASSERT(sizeof(struct ftl_band_md) == FTL_BLOCK_SIZE, "Incorrect metadata size");
SPDK_STATIC_ASSERT(sizeof(struct ftl_band_md) == FTL_BLOCK_SIZE, "Incorrect band metadata size");
SPDK_STATIC_ASSERT(offsetof(struct ftl_band_md, version) == 0,
		   "Incorrect band metadata version offset");

struct ftl_band {
	/* Device this band belongs to */
@@ -178,7 +185,7 @@ struct ftl_band *ftl_band_search_next_to_reloc(struct spdk_ftl_dev *dev);
void ftl_band_init_gc_iter(struct spdk_ftl_dev *dev);
ftl_addr ftl_band_p2l_map_addr(struct ftl_band *band);
void ftl_valid_map_load_state(struct spdk_ftl_dev *dev);
void ftl_bands_load_state(struct spdk_ftl_dev *dev);
int ftl_bands_load_state(struct spdk_ftl_dev *dev);
void ftl_band_open(struct ftl_band *band, enum ftl_band_type type);
void ftl_band_close(struct ftl_band *band);
void ftl_band_free(struct ftl_band *band);
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ ftl_band_init_md(struct ftl_band *band)
	}

	band->md = &band_md[band->id];
	band->md->version = FTL_BAND_VERSION_CURRENT;
	if (!ftl_fast_startup(dev)) {
		band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
	}
+1 −1
Original line number Diff line number Diff line
@@ -177,7 +177,7 @@ ftl_md_restore_region(struct spdk_ftl_dev *dev, int region_type)
		ftl_valid_map_load_state(dev);
		break;
	case FTL_LAYOUT_REGION_TYPE_BAND_MD:
		ftl_bands_load_state(dev);
		status = ftl_bands_load_state(dev);
		break;
	default:
		break;
+152 −0
Original line number Diff line number Diff line
/*   SPDX-License-Identifier: BSD-3-Clause
 *   Copyright 2023 Solidigm All Rights Reserved
 *   Copyright (C) 2022 Intel Corporation.
 *   All rights reserved.
 */
@@ -6,10 +7,161 @@
#include "ftl_band.h"
#include "ftl_layout_upgrade.h"

struct upgrade_ctx {
	struct ftl_md			*md;
	struct ftl_layout_region	reg;
};

static void
v2_upgrade_cleanup(struct ftl_layout_upgrade_ctx *lctx)
{
	struct upgrade_ctx *ctx = lctx->ctx;

	if (ctx->md) {
		ftl_md_destroy(ctx->md, 0);
		ctx->md = NULL;
	}
}

static void
v2_upgrade_finish(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx, int status)
{
	struct upgrade_ctx *ctx = lctx->ctx;

	v2_upgrade_cleanup(lctx);
	ftl_region_upgrade_completed(dev, lctx, ctx->reg.entry_size, ctx->reg.num_entries, status);
}

static void
v2_upgrade_md_persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
{
	struct ftl_layout_upgrade_ctx *lctx = md->owner.cb_ctx;

	v2_upgrade_finish(dev, lctx, status);
}

static void
v2_upgrade_md_restore_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
{
	struct ftl_layout_upgrade_ctx *lctx = md->owner.cb_ctx;
	struct upgrade_ctx *ctx = lctx->ctx;
	struct ftl_band_md *band = ftl_md_get_buffer(md);
	uint64_t move = sizeof(band->version);

	if (status) {
		v2_upgrade_finish(dev, lctx, status);
		return;
	}

	/* If the upgrade process is interrupted while only part of the update persisted,
	 * then the V1 version will be read from again and this section will rewrite the whole band md.
	 */
	for (uint64_t i = 0; i < dev->num_bands; i++, band++) {
		char *buffer = (char *)band;

		memmove(buffer + move, buffer, sizeof(*band) - move);
		band->version = FTL_BAND_VERSION_2;

		if (band->state != FTL_BAND_STATE_CLOSED && band->state != FTL_BAND_STATE_FREE) {
			v2_upgrade_finish(dev, lctx, -EINVAL);
			return;
		}
	}

	ctx->md->cb = v2_upgrade_md_persist_cb;
	ftl_md_set_region(ctx->md, &ctx->reg);
	ftl_md_persist(ctx->md);
}

static int
v2_upgrade_setup_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx)
{
	struct upgrade_ctx *ctx = lctx->ctx;
	const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;

	assert(sizeof(struct ftl_band_md) == FTL_BLOCK_SIZE);

	if (lctx->reg->num_entries != dev->num_bands) {
		return -1;
	}

	/* Open metadata region */
	if (md_ops->region_open(dev, lctx->reg->type, FTL_BAND_VERSION_2, sizeof(struct ftl_band_md),
				dev->num_bands, &ctx->reg)) {
		return -1;
	}

	if (lctx->reg->current.blocks != ctx->reg.current.blocks) {
		return -1;
	}

	ctx->md = ftl_md_create(dev, lctx->reg->current.blocks, 0, ctx->reg.name, FTL_MD_CREATE_HEAP,
				lctx->reg);
	if (!ctx->md) {
		return -1;
	}

	ctx->md->owner.cb_ctx = lctx;
	ctx->md->cb = v2_upgrade_md_restore_cb;

	return 0;
}

static int
v2_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *lctx)
{
	struct upgrade_ctx *ctx = lctx->ctx;

	if (v2_upgrade_setup_ctx(dev, lctx)) {
		goto error;
	}
	/* At this point we're reading the contents of the v1 md */
	ftl_md_restore(ctx->md);
	return 0;
error:
	v2_upgrade_cleanup(lctx);
	return -1;
}

static int
v1_to_v2_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
{
	const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;

	if (ftl_region_major_upgrade_enabled(dev, region)) {
		return -1;
	}

	/* Create the new band metadata region (v2) up front - this allocates a separate entry in the superblock and
	 * area on the cache for us. This is to reserve space for other region upgrades allocating new regions and it
	 * allows us to do an atomic upgrade of the whole region.
	 *
	 * If the upgrade is stopped by power failure/crash after the V2 region has been added, then the upgrade process
	 * will start again (since V1 still exists), but region_create will fail (since the v2 region has already been
	 * created). In such a case only verification of the region length by region_open is needed.
	 *
	 * Once the upgrade is fully done, the old v1 region entry will be removed from the SB and its area on the cache
	 * freed.
	 */
	if (md_ops->region_create(dev, region->type, FTL_BAND_VERSION_2, dev->num_bands) &&
	    md_ops->region_open(dev, region->type, FTL_BAND_VERSION_2, sizeof(struct ftl_band_md),
				dev->num_bands, NULL)) {
		return -1;
	}

	return 0;
}

struct ftl_region_upgrade_desc band_upgrade_desc[] = {
	[FTL_BAND_VERSION_0] = {
		.verify = ftl_region_upgrade_disabled,
	},
	[FTL_BAND_VERSION_1] = {
		.verify = v1_to_v2_upgrade_enabled,
		.ctx_size = sizeof(struct upgrade_ctx),
		.new_version = FTL_BAND_VERSION_2,
		.upgrade = v2_upgrade,
	},
};

SPDK_STATIC_ASSERT(SPDK_COUNTOF(band_upgrade_desc) == FTL_BAND_VERSION_CURRENT,
Loading