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:
parent
44b6d585ca
commit
7ff285193f
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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 */
|
||||||
|
153
lib/ftl/mngt/ftl_mngt_upgrade.c
Normal file
153
lib/ftl/mngt/ftl_mngt_upgrade.c
Normal 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);
|
||||||
|
}
|
250
lib/ftl/upgrade/ftl_layout_upgrade.c
Normal file
250
lib/ftl/upgrade/ftl_layout_upgrade.c
Normal 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);
|
||||||
|
}
|
178
lib/ftl/upgrade/ftl_layout_upgrade.h
Normal file
178
lib/ftl/upgrade/ftl_layout_upgrade.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user