Spdk/lib/ftl/mngt/ftl_mngt_p2l.c
Artur Paszkiewicz 1738488e41 ftl: p2l checkpointing
Since base device doesn't require VSS, FTL introduces a mechanism that
will allow for recovering both the P2L and write pointer of open bands
after a dirty shutdown. After writing 1MiB of data to a band, a 4KiB
block describing the P2L will be persisted to cache device, effectively
emulating VSS for the base device.

Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com>
Change-Id: Ic6be52dc09b237297a5cda3e752d6c038e98b70e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13367
Community-CI: Mellanox Build Bot
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>
2022-09-07 00:08:34 +00:00

155 lines
3.5 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) Intel Corporation.
* All rights reserved.
*/
#include "ftl_mngt.h"
#include "ftl_mngt_steps.h"
#include "ftl_internal.h"
#include "ftl_core.h"
struct ftl_mngt_p2l_md_ctx {
struct ftl_mngt_process *mngt;
int md_region;
int status;
};
static void ftl_p2l_wipe_md_region(struct spdk_ftl_dev *dev, struct ftl_mngt_p2l_md_ctx *ctx);
void
ftl_mngt_p2l_init_ckpt(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
if (!ftl_p2l_ckpt_init(dev)) {
ftl_mngt_next_step(mngt);
} else {
ftl_mngt_fail_step(mngt);
}
}
void
ftl_mngt_p2l_deinit_ckpt(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
ftl_p2l_ckpt_deinit(dev);
ftl_mngt_next_step(mngt);
}
static void
ftl_p2l_wipe_md_region_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
{
struct ftl_mngt_p2l_md_ctx *ctx = md->owner.cb_ctx;
if (status) {
ftl_mngt_fail_step(ctx->mngt);
return;
}
if (ctx->md_region == FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX) {
ftl_mngt_next_step(ctx->mngt);
return;
}
ctx->md_region++;
ftl_p2l_wipe_md_region(dev, ctx);
}
static void
ftl_p2l_wipe_md_region(struct spdk_ftl_dev *dev, struct ftl_mngt_p2l_md_ctx *ctx)
{
struct ftl_layout *layout = &dev->layout;
struct ftl_md *md = layout->md[ctx->md_region];
assert(ctx->md_region >= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN);
assert(ctx->md_region <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX);
if (!md) {
ftl_mngt_fail_step(ctx->mngt);
return;
}
md->owner.cb_ctx = ctx;
md->cb = ftl_p2l_wipe_md_region_cb;
ftl_md_persist(md);
}
void
ftl_mngt_p2l_wipe(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
struct ftl_mngt_p2l_md_ctx *ctx;
if (ftl_mngt_alloc_step_ctx(mngt, sizeof(struct ftl_mngt_p2l_md_ctx))) {
ftl_mngt_fail_step(mngt);
return;
}
ctx = ftl_mngt_get_step_ctx(mngt);
ctx->mngt = mngt;
ctx->md_region = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
ftl_p2l_wipe_md_region(dev, ctx);
}
void
ftl_mngt_p2l_free_bufs(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
struct ftl_md *md;
int region_type;
for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX;
region_type++) {
md = dev->layout.md[region_type];
assert(md);
ftl_md_free_buf(md, ftl_md_destroy_region_flags(dev, dev->layout.region[region_type].type));
}
ftl_mngt_next_step(mngt);
}
static void
ftl_mngt_p2l_restore_ckpt_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
{
struct ftl_mngt_p2l_md_ctx *ctx = md->owner.cb_ctx;
assert(ctx);
if (status) {
ctx->status = status;
}
if (++ctx->md_region == FTL_LAYOUT_REGION_TYPE_P2L_COUNT) {
if (!ctx->status) {
ftl_mngt_next_step(ctx->mngt);
} else {
ftl_mngt_fail_step(ctx->mngt);
}
}
}
void
ftl_mngt_p2l_restore_ckpt(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
struct ftl_layout *layout = &dev->layout;
struct ftl_md *md;
struct ftl_mngt_p2l_md_ctx *ctx;
int md_region;
if (ftl_fast_startup(dev)) {
FTL_NOTICELOG(dev, "SHM: skipping p2l ckpt restore\n");
ftl_mngt_next_step(mngt);
return;
}
if (ftl_mngt_alloc_step_ctx(mngt, sizeof(struct ftl_mngt_p2l_md_ctx))) {
ftl_mngt_fail_step(mngt);
return;
}
ctx = ftl_mngt_get_step_ctx(mngt);
ctx->mngt = mngt;
ctx->md_region = 0;
ctx->status = 0;
for (md_region = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
md_region <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX; md_region++) {
md = layout->md[md_region];
assert(md);
md->owner.cb_ctx = ctx;
md->cb = ftl_mngt_p2l_restore_ckpt_cb;
ftl_md_restore(md);
}
}