ftl: Add metadata upgrade framework

Added the ability for minor metadata upgrade - updating the internal
fields of metadata structures, without changing the overall layout.

Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com>
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
Change-Id: Iec98c62b45b099d6d476d486ba7e4ff6b648bb95
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13384
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Kozlowski Mateusz 2022-05-27 14:57:35 +02:00 committed by Jim Harris
parent 44b6d585ca
commit 7ff285193f
8 changed files with 675 additions and 2 deletions

View File

@ -23,7 +23,7 @@ endif
CFLAGS += -I. CFLAGS += -I.
FTL_SUBDIRS := mngt utils FTL_SUBDIRS := mngt utils upgrade
C_SRCS = ftl_core.c ftl_init.c ftl_layout.c ftl_debug.c ftl_io.c ftl_sb.c ftl_l2p.c ftl_l2p_flat.c C_SRCS = ftl_core.c ftl_init.c ftl_layout.c ftl_debug.c ftl_io.c ftl_sb.c ftl_l2p.c ftl_l2p_flat.c
C_SRCS += ftl_nv_cache.c ftl_band.c ftl_band_ops.c ftl_writer.c ftl_rq.c ftl_reloc.c ftl_l2p_cache.c C_SRCS += ftl_nv_cache.c ftl_band.c ftl_band_ops.c ftl_writer.c ftl_rq.c ftl_reloc.c ftl_l2p_cache.c
@ -31,8 +31,9 @@ C_SRCS += ftl_p2l.c
C_SRCS += mngt/ftl_mngt.c mngt/ftl_mngt_bdev.c mngt/ftl_mngt_shutdown.c mngt/ftl_mngt_startup.c C_SRCS += mngt/ftl_mngt.c mngt/ftl_mngt_bdev.c mngt/ftl_mngt_shutdown.c mngt/ftl_mngt_startup.c
C_SRCS += mngt/ftl_mngt_md.c mngt/ftl_mngt_misc.c mngt/ftl_mngt_ioch.c mngt/ftl_mngt_l2p.c C_SRCS += mngt/ftl_mngt_md.c mngt/ftl_mngt_misc.c mngt/ftl_mngt_ioch.c mngt/ftl_mngt_l2p.c
C_SRCS += mngt/ftl_mngt_band.c mngt/ftl_mngt_self_test.c mngt/ftl_mngt_p2l.c C_SRCS += mngt/ftl_mngt_band.c mngt/ftl_mngt_self_test.c mngt/ftl_mngt_p2l.c
C_SRCS += mngt/ftl_mngt_recovery.c C_SRCS += mngt/ftl_mngt_recovery.c mngt/ftl_mngt_upgrade.c
C_SRCS += utils/ftl_conf.c utils/ftl_md.c utils/ftl_mempool.c utils/ftl_bitmap.c C_SRCS += utils/ftl_conf.c utils/ftl_md.c utils/ftl_mempool.c utils/ftl_bitmap.c
C_SRCS += upgrade/ftl_layout_upgrade.c
SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_ftl.map) SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_ftl.map)

View File

@ -273,6 +273,80 @@ next_sb_reg:
return 0; return 0;
} }
static void
ftl_superblock_md_layout_free_region(struct spdk_ftl_dev *dev,
struct ftl_superblock_md_region *sb_reg)
{
/* TODO: major upgrades: implement */
sb_reg->type = FTL_LAYOUT_REGION_TYPE_FREE_NVC;
}
int
ftl_superblock_md_layout_upgrade_region(struct spdk_ftl_dev *dev,
struct ftl_superblock_md_region *sb_reg, uint32_t new_version)
{
struct ftl_superblock *sb = dev->sb;
struct ftl_superblock_md_region *sb_reg_iter = &sb->md_layout_head;
struct ftl_layout *layout = &dev->layout;
struct ftl_layout_region *reg = &layout->region[sb_reg->type];
uint32_t old_version = sb_reg->version;
assert(sb_reg);
assert(reg->prev.sb_md_reg == sb_reg);
assert(new_version > old_version);
while (sb_reg_iter->type != FTL_LAYOUT_REGION_TYPE_INVALID) {
if (sb_reg_iter->type != sb_reg->type) {
goto next_sb_reg_iter;
}
/* Verify all region versions up to new_version are updated: */
if (sb_reg_iter->version != old_version && sb_reg_iter->version < new_version) {
FTL_ERRLOG(dev, "Region upgrade skipped\n");
return -1;
}
if (sb_reg_iter->version == new_version) {
/* Major upgrades: update region prev version to the new version region found */
assert(sb_reg != sb_reg_iter);
reg->prev.offset = sb_reg_iter->blk_offs;
reg->prev.blocks = sb_reg_iter->blk_sz;
reg->prev.version = sb_reg_iter->version;
reg->prev.sb_md_reg = sb_reg_iter;
ftl_superblock_md_layout_free_region(dev, sb_reg);
goto exit;
}
next_sb_reg_iter:
if (sb_reg_iter->df_next == FTL_DF_OBJ_ID_INVALID) {
break;
}
sb_reg_iter = ftl_df_get_obj_ptr(sb, sb_reg_iter->df_next);
if (superblock_md_region_overflow(dev, sb_reg_iter)) {
FTL_ERRLOG(dev, "Buffer overflow\n");
return -EOVERFLOW;
}
}
/* Minor upgrades: update the region in place (only the new version) */
assert(sb_reg == reg->prev.sb_md_reg);
sb_reg->version = new_version;
reg->prev.version = new_version;
exit:
/* Update the region current version */
if (new_version == reg->current.version) {
reg->current.offset = sb_reg->blk_offs;
reg->current.blocks = sb_reg->blk_sz;
reg->current.version = sb_reg->version;
reg->current.sb_md_reg = sb_reg;
}
return 0;
}
void void
ftl_superblock_md_layout_dump(struct spdk_ftl_dev *dev) ftl_superblock_md_layout_dump(struct spdk_ftl_dev *dev)
{ {

View File

@ -20,6 +20,9 @@ int ftl_superblock_md_layout_build(struct spdk_ftl_dev *dev);
int ftl_superblock_md_layout_load_all(struct spdk_ftl_dev *dev); int ftl_superblock_md_layout_load_all(struct spdk_ftl_dev *dev);
int ftl_superblock_md_layout_upgrade_region(struct spdk_ftl_dev *dev,
struct ftl_superblock_md_region *sb_reg, uint32_t new_version);
void ftl_superblock_md_layout_dump(struct spdk_ftl_dev *dev); void ftl_superblock_md_layout_dump(struct spdk_ftl_dev *dev);
#endif /* FTL_SB_H */ #endif /* FTL_SB_H */

View File

@ -13,6 +13,7 @@
#include "ftl_band.h" #include "ftl_band.h"
#include "ftl_internal.h" #include "ftl_internal.h"
#include "ftl_sb.h" #include "ftl_sb.h"
#include "upgrade/ftl_layout_upgrade.h"
void void
ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
@ -747,3 +748,10 @@ ftl_mngt_restore_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{ {
ftl_mngt_call_process(mngt, &desc_restore); ftl_mngt_call_process(mngt, &desc_restore);
} }
void
ftl_mngt_persist_superblock(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
dev->sb->header.crc = get_sb_crc(dev->sb);
persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
}

View File

@ -82,6 +82,10 @@ void ftl_mngt_persist_l2p(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mng
void ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_layout_verify(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_layout_upgrade(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
@ -136,4 +140,6 @@ void ftl_mngt_persist_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mn
void ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_persist_superblock(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
#endif /* FTL_MNGT_STEPS_H */ #endif /* FTL_MNGT_STEPS_H */

View File

@ -0,0 +1,153 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) Intel Corporation.
* All rights reserved.
*/
#include "ftl_core.h"
#include "ftl_mngt.h"
#include "ftl_mngt_steps.h"
#include "upgrade/ftl_layout_upgrade.h"
struct ftl_mngt_upgrade_ctx {
struct ftl_mngt_process *parent;
struct ftl_mngt_process *mngt;
struct ftl_layout_upgrade_ctx upgrade_ctx;
};
static void
region_upgrade_cb(struct spdk_ftl_dev *dev, void *_ctx, int status)
{
struct ftl_mngt_upgrade_ctx *ctx = _ctx;
free(ctx->upgrade_ctx.ctx);
ctx->upgrade_ctx.ctx = NULL;
if (status) {
FTL_ERRLOG(dev, "Upgrade failed for region %d (rc=%d)\n", ctx->upgrade_ctx.reg->type, status);
ftl_mngt_fail_step(ctx->mngt);
} else {
ftl_mngt_next_step(ctx->mngt);
}
}
static void
region_upgrade(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
struct ftl_mngt_upgrade_ctx *ctx = ftl_mngt_get_caller_ctx(mngt);
struct ftl_layout_upgrade_ctx *upgrade_ctx = &ctx->upgrade_ctx;
size_t ctx_size = upgrade_ctx->upgrade->desc[upgrade_ctx->reg->prev.version].ctx_size;
int rc = -1;
assert(upgrade_ctx->ctx == NULL);
if (ctx_size) {
upgrade_ctx->ctx = calloc(1, ctx_size);
if (!upgrade_ctx->ctx) {
goto exit;
}
}
upgrade_ctx->cb = region_upgrade_cb;
upgrade_ctx->cb_ctx = ctx;
ctx->mngt = mngt;
rc = ftl_region_upgrade(dev, upgrade_ctx);
exit:
if (rc) {
region_upgrade_cb(dev, ctx, rc);
}
}
static const struct ftl_mngt_process_desc desc_region_upgrade = {
.name = "FTL region upgrade",
.steps = {
{
.name = "Region upgrade",
.action = region_upgrade,
},
{
.name = "Persist superblock",
.action = ftl_mngt_persist_superblock,
},
{}
}
};
static void
layout_upgrade_cb(struct spdk_ftl_dev *dev, void *_ctx, int status)
{
struct ftl_mngt_upgrade_ctx *ctx = _ctx;
if (status) {
free(ctx->upgrade_ctx.ctx);
ctx->upgrade_ctx.ctx = NULL;
ftl_mngt_fail_step(ctx->parent);
return;
}
/* go back to ftl_mngt_upgrade() step and select the next region/version to upgrade */
ftl_mngt_continue_step(ctx->parent);
}
static void
layout_upgrade(struct spdk_ftl_dev *dev, struct ftl_mngt_process *parent)
{
struct ftl_mngt_upgrade_ctx *ctx = ftl_mngt_get_process_ctx(parent);
int rc;
ctx->parent = parent;
rc = ftl_layout_upgrade_init_ctx(dev, &ctx->upgrade_ctx);
switch (rc) {
case FTL_LAYOUT_UPGRADE_CONTINUE:
if (!ftl_mngt_process_execute(dev, &desc_region_upgrade, layout_upgrade_cb, ctx)) {
return;
}
ftl_mngt_fail_step(parent);
break;
case FTL_LAYOUT_UPGRADE_DONE:
if (ftl_upgrade_layout_dump(dev)) {
FTL_ERRLOG(dev, "MD layout verification failed after upgrade.\n");
ftl_mngt_fail_step(parent);
} else {
ftl_mngt_next_step(parent);
}
break;
case FTL_LAYOUT_UPGRADE_FAULT:
ftl_mngt_fail_step(parent);
break;
}
if (ctx->upgrade_ctx.ctx) {
free(ctx->upgrade_ctx.ctx);
}
}
static const struct ftl_mngt_process_desc desc_layout_upgrade = {
.name = "FTL layout upgrade",
.ctx_size = sizeof(struct ftl_mngt_upgrade_ctx),
.steps = {
{
.name = "Layout upgrade",
.action = layout_upgrade,
},
{}
}
};
void
ftl_mngt_layout_verify(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
if (ftl_layout_verify(dev)) {
ftl_mngt_fail_step(mngt);
} else {
ftl_mngt_next_step(mngt);
}
}
void
ftl_mngt_layout_upgrade(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
ftl_mngt_call_process(mngt, &desc_layout_upgrade);
}

View File

@ -0,0 +1,250 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) Intel Corporation.
* All rights reserved.
*/
#include "ftl_layout_upgrade.h"
#include "ftl_layout.h"
#include "ftl_sb_current.h"
#include "ftl_core.h"
#include "ftl_band.h"
int
ftl_region_upgrade_disabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
{
return -1;
}
int
ftl_region_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
{
if (!(dev->sb->clean == 1 && dev->sb_shm->shm_clean == 0)) {
FTL_ERRLOG(dev, "FTL region upgrade: SB dirty\n");
return -1;
}
return 0;
}
#ifndef UTEST
extern struct ftl_region_upgrade_desc sb_upgrade_desc[];
extern struct ftl_region_upgrade_desc p2l_upgrade_desc[];
extern struct ftl_region_upgrade_desc nvc_upgrade_desc[];
extern struct ftl_region_upgrade_desc band_upgrade_desc[];
static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = {
#ifdef SPDK_FTL_VSS_EMU
[FTL_LAYOUT_REGION_TYPE_VSS] = {},
#endif
[FTL_LAYOUT_REGION_TYPE_SB] = {},
[FTL_LAYOUT_REGION_TYPE_SB_BASE] = {},
[FTL_LAYOUT_REGION_TYPE_L2P] = {},
[FTL_LAYOUT_REGION_TYPE_BAND_MD] = {},
[FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = {},
[FTL_LAYOUT_REGION_TYPE_VALID_MAP] = {},
[FTL_LAYOUT_REGION_TYPE_NVC_MD] = {},
[FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = {},
[FTL_LAYOUT_REGION_TYPE_DATA_NVC] = {},
[FTL_LAYOUT_REGION_TYPE_DATA_BASE] = {},
[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = {},
[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = {},
[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = {},
[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = {},
[FTL_LAYOUT_REGION_TYPE_TRIM_MD] = {},
[FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = {},
};
SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) ==
FTL_LAYOUT_REGION_TYPE_MAX,
"Missing layout upgrade descriptors");
#endif
static int
region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
{
uint64_t ver;
assert(ctx->reg);
assert(ctx->reg->current.version == ctx->upgrade->count);
ver = ctx->reg->prev.version;
if (ver > ctx->upgrade->count) {
FTL_ERRLOG(dev, "Unknown region version\n");
return -1;
}
while (ver < ctx->reg->current.version) {
int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg);
if (rc) {
return rc;
}
ver = ctx->upgrade->desc[ver].new_version;
}
return 0;
}
int
ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
{
int rc = 0;
uint64_t ver;
assert(ctx->reg);
assert(ctx->reg->prev.version <= ctx->reg->current.version);
assert(ctx->reg->current.version == ctx->upgrade->count);
ver = ctx->reg->prev.version;
if (ver < ctx->upgrade->count) {
ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version;
rc = ctx->upgrade->desc[ver].upgrade(dev, ctx);
}
return rc;
}
void
ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx,
int status)
{
assert(ctx->reg);
assert(ctx->reg->prev.version < ctx->next_reg_ver);
assert(ctx->next_reg_ver <= ctx->reg->current.version);
/* SB MD isn't tracked in SB MD region list */
if (!status) {
if (ctx->reg->prev.sb_md_reg) {
int rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg->prev.sb_md_reg, ctx->next_reg_ver);
ftl_bug(rc != 0);
}
ctx->reg->prev.version = ctx->next_reg_ver;
}
if (ctx->cb) {
ctx->cb(dev, ctx->cb_ctx, status);
}
}
int
ftl_layout_verify(struct spdk_ftl_dev *dev)
{
int rc = 0;
struct ftl_layout *layout = &dev->layout;
struct ftl_layout_upgrade_ctx ctx = {0};
if (ftl_superblock_md_layout_is_empty(dev->sb)) {
rc = ftl_superblock_md_layout_build(dev);
goto exit;
}
if (ftl_superblock_md_layout_load_all(dev)) {
return -1;
}
if (ftl_validate_regions(dev, layout)) {
return -1;
}
ctx.reg = &dev->layout.region[0];
ctx.upgrade = &layout_upgrade_desc[0];
while (true) {
if (region_verify(dev, &ctx)) {
return -1;
}
if (ctx.reg->type == FTL_LAYOUT_REGION_TYPE_MAX - 1) {
break;
}
ctx.reg++;
ctx.upgrade++;
}
exit:
return rc;
}
int
ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev)
{
if (ftl_validate_regions(dev, &dev->layout)) {
return -1;
}
ftl_layout_dump(dev);
ftl_superblock_md_layout_dump(dev);
return 0;
}
int
ftl_superblock_upgrade(struct spdk_ftl_dev *dev)
{
struct ftl_layout_upgrade_ctx ctx = {0};
struct ftl_layout_region *reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB];
int rc;
ctx.reg = reg;
ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB];
reg->prev.version = dev->sb->header.version;
rc = region_verify(dev, &ctx);
if (rc) {
return rc;
}
while (reg->prev.version < reg->current.version) {
rc = ftl_region_upgrade(dev, &ctx);
if (rc) {
return rc;
}
/* SB upgrades are all synchronous */
ftl_region_upgrade_completed(dev, &ctx, rc);
}
dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].prev.version = reg->prev.version;
return 0;
}
static int
layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
{
struct ftl_layout_region *reg;
uint64_t reg_ver;
uint32_t reg_type = ctx->reg->type;
while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) {
assert(ctx->reg);
assert(ctx->upgrade);
reg = ctx->reg;
reg_ver = reg->prev.version;
if (reg_ver < reg->current.version) {
/* qualify region version to upgrade */
return FTL_LAYOUT_UPGRADE_CONTINUE;
} else if (reg_ver == reg->current.version) {
/* select the next region to upgrade */
reg_type++;
if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) {
break;
}
ctx->reg++;
ctx->upgrade++;
} else {
/* unknown version */
assert(reg_ver > reg->current.version);
FTL_ERRLOG(dev, "Region %d upgrade fault: version %"PRIu64"/%"PRIu64"\n", reg_type, reg_ver,
reg->current.version);
return FTL_LAYOUT_UPGRADE_FAULT;
}
}
return FTL_LAYOUT_UPGRADE_DONE;
}
int
ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
{
if (!ctx->reg) {
ctx->reg = &dev->layout.region[0];
ctx->upgrade = &layout_upgrade_desc[0];
}
return layout_upgrade_select_next_region(dev, ctx);
}

View File

@ -0,0 +1,178 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) Intel Corporation.
* All rights reserved.
*/
#ifndef FTL_LAYOUT_UPGRADE_H
#define FTL_LAYOUT_UPGRADE_H
#include "ftl_core.h"
#include "ftl_layout.h"
struct spdk_ftl_dev;
struct ftl_layout_region;
struct ftl_layout_upgrade_ctx;
enum ftl_layout_upgrade_result {
/* Continue with the selected region upgrade */
FTL_LAYOUT_UPGRADE_CONTINUE = 0,
/* Layout upgrade done */
FTL_LAYOUT_UPGRADE_DONE,
/* Layout upgrade fault */
FTL_LAYOUT_UPGRADE_FAULT,
};
/* MD region upgrade verify fn: return 0 on success */
typedef int (*ftl_region_upgrade_verify_fn)(struct spdk_ftl_dev *dev,
struct ftl_layout_region *region);
/* MD region upgrade fn: return 0 on success */
typedef int (*ftl_region_upgrade_fn)(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx);
/* MD region upgrade descriptor */
struct ftl_region_upgrade_desc {
/* Qualifies the region for upgrade */
ftl_region_upgrade_verify_fn verify;
/* Upgrades the region */
ftl_region_upgrade_fn upgrade;
/* New region version (i.e. after the upgrade) */
uint32_t new_version;
/* Context buffer allocated for upgrade() */
size_t ctx_size;
};
/* MD layout upgrade descriptor - one instance contains information about the upgrade steps necessary
* for updating to latest metadata version. For example version 0 of metadata region will have no descriptors
* (as it's by definition up to date and there's no need to upgrade it), while version 2 will have 2 (0 -> 1
* and 1 -> 2).
*/
struct ftl_layout_upgrade_desc_list {
/* # of entries in the region upgrade descriptor */
size_t count;
/* Region upgrade descriptor */
struct ftl_region_upgrade_desc *desc;
};
/* Region upgrade callback */
typedef void (*ftl_region_upgrade_cb)(struct spdk_ftl_dev *dev, void *ctx, int status);
/* MD layout upgrade context */
struct ftl_layout_upgrade_ctx {
/* MD region being upgraded */
struct ftl_layout_region *reg;
/* MD region upgrade descriptor */
struct ftl_layout_upgrade_desc_list *upgrade;
/* New region version (i.e. after the upgrade) */
uint64_t next_reg_ver;
/* Context buffer for the region upgrade */
void *ctx;
/* Region upgrade callback */
ftl_region_upgrade_cb cb;
/* Ctx for the region upgrade callback */
void *cb_ctx;
};
/**
* @brief Disable region upgrade for particular version.
*
* @param dev FTL device
* @param region FTL layout region descriptor
* @return int -1
*/
int ftl_region_upgrade_disabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region);
/**
* @brief Enable region upgrade for particular version.
*
* @param dev FTL device
* @param region FTL layout region descriptor
* @return int -1 (i.e. disable) if SB is dirty or SHM clean, 0 otherwise (i.e. enable)
*/
int ftl_region_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region);
/**
* @brief Upgrade the superblock.
*
* This call is sychronous.
*
* @param dev FTL device
* @return int 0: success, error code otherwise
*/
int ftl_superblock_upgrade(struct spdk_ftl_dev *dev);
/**
* @brief Qualify the MD layout for upgrade.
*
* The SB MD layout is built or loaded.
* If loaded, walk through all MD layout and filter out all MD regions that need an upgrade.
* Call .verify() on region upgrade descriptors for all such regions.
*
* @param dev FTL device
* @return int 0: success, error code otherwise
*/
int ftl_layout_verify(struct spdk_ftl_dev *dev);
/**
* @brief Dump the FTL layout
*
* Verify MD layout in terms of region overlaps.
*
* @param dev FTL device
* @return int 0: success, error code otherwise
*/
int ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev);
/**
* @brief Upgrade the MD region.
*
* Call .upgrade() on the selected region upgrade descriptor.
* When returned 0, this call is asynchronous.
* The .upgrade() is expected to convert and persist the metadata.
* When that's done, the call to ftl_region_upgrade_completed() is expected
* to continue with the layout upgrade.
*
* When returned an error code, the caller is responsible to abort the mngt pipeline.
*
* @param dev FTL device
* @param ctx Layout upgrade context
* @return int 0: upgrade in progress, error code otherwise
*/
int ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx);
/**
* @brief Called when MD region upgrade is completed - see ftl_region_upgrade().
*
* Upgrades the SB MD layout and region's prev version descriptor to the just upgraded version.
* Executes the layout upgrade owner's callback (mngt region_upgrade_cb()) to continue
* with the layout upgrade.
*
* @param dev FTL device
* @param ctx Layout upgrade context
* @param status Region upgrade status: 0: success, error code otherwise
*/
void ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx,
int status);
/**
* @brief Initialize the layout upgrade context.
*
* Select the next region to be upgraded.
*
* @param dev FTL device
* @param ctx Layout upgrade context
* @return int see enum ftl_layout_upgrade_result
*/
int ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx);
#endif /* FTL_LAYOUT_UPGRADE_H */