2022-06-20 12:28:58 +00:00
|
|
|
/* SPDX-License-Identifier: BSD-3-Clause
|
2022-11-01 20:26:26 +00:00
|
|
|
* Copyright (C) 2022 Intel Corporation.
|
2022-06-20 12:28:58 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "spdk/thread.h"
|
|
|
|
#include "spdk/crc32.h"
|
|
|
|
|
|
|
|
#include "ftl_core.h"
|
|
|
|
#include "ftl_mngt.h"
|
|
|
|
#include "ftl_mngt_steps.h"
|
|
|
|
#include "ftl_utils.h"
|
2022-06-21 13:05:28 +00:00
|
|
|
#include "ftl_band.h"
|
2022-06-20 12:28:58 +00:00
|
|
|
#include "ftl_internal.h"
|
2022-06-21 13:05:02 +00:00
|
|
|
#include "ftl_sb.h"
|
2022-05-27 12:57:35 +00:00
|
|
|
#include "upgrade/ftl_layout_upgrade.h"
|
2022-05-25 10:13:38 +00:00
|
|
|
#include "upgrade/ftl_sb_upgrade.h"
|
2022-06-20 12:28:58 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (ftl_layout_setup(dev)) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
} else {
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
}
|
2022-06-20 10:31:56 +00:00
|
|
|
|
|
|
|
static bool
|
|
|
|
is_buffer_needed(enum ftl_layout_region_type type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
2022-06-15 08:02:25 +00:00
|
|
|
#ifdef SPDK_FTL_VSS_EMU
|
|
|
|
case FTL_LAYOUT_REGION_TYPE_VSS:
|
|
|
|
#endif
|
2022-06-21 13:05:02 +00:00
|
|
|
case FTL_LAYOUT_REGION_TYPE_SB:
|
|
|
|
case FTL_LAYOUT_REGION_TYPE_SB_BASE:
|
2022-06-20 10:31:56 +00:00
|
|
|
case FTL_LAYOUT_REGION_TYPE_DATA_NVC:
|
|
|
|
case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
|
2022-06-13 09:54:12 +00:00
|
|
|
case FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR:
|
2022-06-21 13:05:28 +00:00
|
|
|
case FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR:
|
2022-06-01 13:18:03 +00:00
|
|
|
#ifndef SPDK_FTL_L2P_FLAT
|
|
|
|
case FTL_LAYOUT_REGION_TYPE_L2P:
|
|
|
|
#endif
|
2022-05-31 09:25:31 +00:00
|
|
|
case FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR:
|
2022-06-20 10:31:56 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
struct ftl_layout *layout = &dev->layout;
|
|
|
|
struct ftl_layout_region *region = layout->region;
|
|
|
|
uint64_t i;
|
2022-06-28 13:53:17 +00:00
|
|
|
int md_flags;
|
2022-06-20 10:31:56 +00:00
|
|
|
|
|
|
|
for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
|
|
|
|
if (layout->md[i]) {
|
|
|
|
/*
|
|
|
|
* Some metadata objects are initialized by other FTL
|
|
|
|
* components. At the moment it's only used by superblock (and its mirror) -
|
|
|
|
* during load time we need to read it earlier in order to get the layout for the
|
|
|
|
* other regions.
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
}
|
2022-08-23 11:52:12 +00:00
|
|
|
md_flags = is_buffer_needed(i) ? ftl_md_create_region_flags(dev,
|
|
|
|
region->type) : FTL_MD_CREATE_NO_MEM;
|
2022-06-20 10:31:56 +00:00
|
|
|
layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name,
|
2022-06-28 13:53:17 +00:00
|
|
|
md_flags, region);
|
2022-06-20 10:31:56 +00:00
|
|
|
if (NULL == layout->md[i]) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
struct ftl_layout *layout = &dev->layout;
|
|
|
|
struct ftl_layout_region *region = layout->region;
|
|
|
|
uint64_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
|
|
|
|
if (layout->md[i]) {
|
2022-06-10 12:15:35 +00:00
|
|
|
ftl_md_destroy(layout->md[i], ftl_md_destroy_region_flags(dev, layout->region[i].type));
|
2022-06-20 10:31:56 +00:00
|
|
|
layout->md[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
2022-06-15 08:02:25 +00:00
|
|
|
|
2022-06-21 13:05:02 +00:00
|
|
|
static void
|
|
|
|
persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
|
|
|
|
{
|
|
|
|
struct ftl_mngt_process *mngt = md->owner.cb_ctx;
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
} else {
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
|
|
|
|
enum ftl_layout_region_type type)
|
|
|
|
{
|
|
|
|
struct ftl_layout *layout = &dev->layout;
|
2022-08-04 01:44:54 +00:00
|
|
|
struct ftl_md *md;
|
2022-06-21 13:05:02 +00:00
|
|
|
|
|
|
|
assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
|
|
|
|
|
2022-08-04 01:44:54 +00:00
|
|
|
md = layout->md[type];
|
2022-06-21 13:05:02 +00:00
|
|
|
if (!md) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
md->owner.cb_ctx = mngt;
|
|
|
|
md->cb = persist_cb;
|
|
|
|
ftl_md_persist(md);
|
|
|
|
}
|
|
|
|
|
2022-05-31 11:48:28 +00:00
|
|
|
static int
|
|
|
|
ftl_md_restore_region(struct spdk_ftl_dev *dev, int region_type)
|
|
|
|
{
|
|
|
|
int status = 0;
|
|
|
|
switch (region_type) {
|
|
|
|
case FTL_LAYOUT_REGION_TYPE_NVC_MD:
|
|
|
|
status = ftl_nv_cache_load_state(&dev->nv_cache);
|
|
|
|
break;
|
|
|
|
case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
|
|
|
|
ftl_valid_map_load_state(dev);
|
|
|
|
break;
|
|
|
|
case FTL_LAYOUT_REGION_TYPE_BAND_MD:
|
|
|
|
ftl_bands_load_state(dev);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
restore_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
|
|
|
|
{
|
|
|
|
struct ftl_mngt_process *mngt = md->owner.cb_ctx;
|
|
|
|
const struct ftl_layout_region *region = ftl_md_get_region(md);
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
/* Restore error, end step */
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(region);
|
|
|
|
status = ftl_md_restore_region(dev, region->type);
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
} else {
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
restore(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt, enum ftl_layout_region_type type)
|
|
|
|
{
|
|
|
|
struct ftl_layout *layout = &dev->layout;
|
|
|
|
assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
|
|
|
|
struct ftl_md *md = layout->md[type];
|
|
|
|
|
|
|
|
if (!md) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
md->owner.cb_ctx = mngt;
|
|
|
|
md->cb = restore_cb;
|
|
|
|
ftl_md_restore(md);
|
|
|
|
}
|
|
|
|
|
2022-06-13 08:59:05 +00:00
|
|
|
void
|
|
|
|
ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (ftl_nv_cache_save_state(&dev->nv_cache)) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
|
|
|
|
}
|
|
|
|
|
2022-06-01 09:03:05 +00:00
|
|
|
static void
|
|
|
|
ftl_mngt_fast_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (ftl_nv_cache_save_state(&dev->nv_cache)) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
|
2022-06-01 09:19:04 +00:00
|
|
|
static void
|
|
|
|
ftl_mngt_persist_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
|
|
|
|
}
|
|
|
|
|
2022-07-07 17:32:30 +00:00
|
|
|
static void
|
|
|
|
ftl_mngt_persist_p2l_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
/* Sync runtime P2L to persist any invalidation that may have happened */
|
|
|
|
|
|
|
|
struct ftl_p2l_sync_ctx *ctx = ftl_mngt_get_step_ctx(mngt);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ftl_mngt_persist_bands_p2l will increment the md_region before the step_continue for next regions
|
|
|
|
*/
|
|
|
|
if (ctx->md_region <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN) {
|
|
|
|
ctx->md_region = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
|
|
|
|
}
|
|
|
|
ftl_mngt_persist_bands_p2l(mngt);
|
|
|
|
}
|
|
|
|
|
2022-06-10 10:04:40 +00:00
|
|
|
void
|
2022-06-01 09:19:04 +00:00
|
|
|
ftl_mngt_persist_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
2022-06-10 10:04:40 +00:00
|
|
|
{
|
|
|
|
persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
|
|
|
|
}
|
|
|
|
|
2022-05-27 11:46:59 +00:00
|
|
|
static void
|
|
|
|
ftl_mngt_persist_trim_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_TRIM_MD);
|
|
|
|
}
|
|
|
|
|
2022-06-21 13:05:02 +00:00
|
|
|
static uint32_t
|
|
|
|
get_sb_crc(struct ftl_superblock *sb)
|
|
|
|
{
|
|
|
|
uint32_t crc = 0;
|
|
|
|
|
|
|
|
/* Calculate CRC excluding CRC field in superblock */
|
|
|
|
void *buffer = sb;
|
|
|
|
size_t offset = offsetof(struct ftl_superblock, header.crc);
|
|
|
|
size_t size = offset;
|
|
|
|
crc = spdk_crc32c_update(buffer, size, crc);
|
|
|
|
|
|
|
|
buffer += offset + sizeof(sb->header.crc);
|
2022-05-25 10:13:38 +00:00
|
|
|
if (sb->header.version > FTL_SB_VERSION_2) {
|
|
|
|
/* whole buf for v3 and on: */
|
|
|
|
size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc);
|
|
|
|
crc = spdk_crc32c_update(buffer, size, crc);
|
|
|
|
} else {
|
|
|
|
/* special for sb v2 only: */
|
|
|
|
size = sizeof(struct ftl_superblock_v2) - offset - sizeof(sb->header.crc);
|
|
|
|
sb->header.crc = spdk_crc32c_update(buffer, size, crc);
|
|
|
|
}
|
2022-06-21 13:05:02 +00:00
|
|
|
|
|
|
|
return crc;
|
|
|
|
}
|
|
|
|
|
2022-06-01 09:19:04 +00:00
|
|
|
static void
|
|
|
|
ftl_mngt_persist_super_block(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
dev->sb->overprovisioning = dev->conf.overprovisioning;
|
|
|
|
dev->sb->gc_info = dev->sb_shm->gc_info;
|
|
|
|
dev->sb->header.crc = get_sb_crc(dev->sb);
|
|
|
|
persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SPDK_FTL_VSS_EMU
|
|
|
|
static void
|
|
|
|
ftl_mngt_persist_vss(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_VSS);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Persists all necessary metadata (band state, P2L, etc) during FTL's clean shutdown.
|
|
|
|
*/
|
|
|
|
static const struct ftl_mngt_process_desc desc_persist = {
|
|
|
|
.name = "Persist metadata",
|
|
|
|
.steps = {
|
|
|
|
{
|
|
|
|
.name = "Persist NV cache metadata",
|
|
|
|
.action = ftl_mngt_persist_nv_cache_metadata,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Persist valid map metadata",
|
|
|
|
.action = ftl_mngt_persist_vld_map_metadata,
|
|
|
|
},
|
2022-07-07 17:32:30 +00:00
|
|
|
{
|
|
|
|
.name = "Persist P2L metadata",
|
|
|
|
.action = ftl_mngt_persist_p2l_metadata,
|
|
|
|
.ctx_size = sizeof(struct ftl_p2l_sync_ctx),
|
|
|
|
},
|
2022-06-01 09:19:04 +00:00
|
|
|
{
|
|
|
|
.name = "persist band info metadata",
|
|
|
|
.action = ftl_mngt_persist_band_info_metadata,
|
|
|
|
},
|
2022-05-27 11:46:59 +00:00
|
|
|
{
|
|
|
|
.name = "persist trim metadata",
|
|
|
|
.action = ftl_mngt_persist_trim_metadata,
|
|
|
|
},
|
2022-06-01 09:19:04 +00:00
|
|
|
{
|
|
|
|
.name = "Persist superblock",
|
|
|
|
.action = ftl_mngt_persist_super_block,
|
|
|
|
},
|
|
|
|
#ifdef SPDK_FTL_VSS_EMU
|
|
|
|
{
|
|
|
|
.name = "Persist VSS metadata",
|
|
|
|
.action = ftl_mngt_persist_vss,
|
|
|
|
},
|
|
|
|
#endif
|
|
|
|
{}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
ftl_mngt_call_process(mngt, &desc_persist);
|
|
|
|
}
|
|
|
|
|
2022-06-01 09:03:05 +00:00
|
|
|
/*
|
|
|
|
* Fast clean shutdown path - skips the persistance of most metadata regions and
|
|
|
|
* relies on their shared memory state instead.
|
|
|
|
*/
|
|
|
|
static const struct ftl_mngt_process_desc desc_fast_persist = {
|
|
|
|
.name = "Fast persist metadata",
|
|
|
|
.steps = {
|
|
|
|
{
|
|
|
|
.name = "Fast persist NV cache metadata",
|
|
|
|
.action = ftl_mngt_fast_persist_nv_cache_metadata,
|
|
|
|
},
|
|
|
|
#ifdef SPDK_FTL_VSS_EMU
|
|
|
|
{
|
|
|
|
.name = "Persist VSS metadata",
|
|
|
|
.action = ftl_mngt_persist_vss,
|
|
|
|
},
|
|
|
|
#endif
|
|
|
|
{}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_fast_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
ftl_mngt_call_process(mngt, &desc_fast_persist);
|
|
|
|
}
|
|
|
|
|
2022-06-21 13:05:02 +00:00
|
|
|
void
|
|
|
|
ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
struct ftl_superblock *sb = dev->sb;
|
|
|
|
|
|
|
|
sb->header.magic = FTL_SUPERBLOCK_MAGIC;
|
2022-05-25 10:13:38 +00:00
|
|
|
sb->header.version = FTL_SB_VERSION_CURRENT;
|
2022-06-21 13:05:02 +00:00
|
|
|
sb->uuid = dev->conf.uuid;
|
|
|
|
sb->clean = 0;
|
2022-06-09 12:51:45 +00:00
|
|
|
dev->sb_shm->shm_clean = false;
|
2022-07-07 17:32:30 +00:00
|
|
|
sb->ckpt_seq_id = 0;
|
2022-06-21 13:05:02 +00:00
|
|
|
|
|
|
|
/* Max 16 IO depth per band relocate */
|
|
|
|
sb->max_reloc_qdepth = 16;
|
|
|
|
|
|
|
|
sb->overprovisioning = dev->conf.overprovisioning;
|
|
|
|
|
2022-06-03 09:16:39 +00:00
|
|
|
ftl_band_init_gc_iter(dev);
|
|
|
|
|
2022-06-21 13:05:02 +00:00
|
|
|
/* md layout isn't initialized yet.
|
|
|
|
* empty region list => all regions in the default location */
|
|
|
|
sb->md_layout_head.type = FTL_LAYOUT_REGION_TYPE_INVALID;
|
2022-06-28 14:26:04 +00:00
|
|
|
sb->md_layout_head.df_next = FTL_DF_OBJ_ID_INVALID;
|
2022-06-21 13:05:02 +00:00
|
|
|
|
|
|
|
sb->header.crc = get_sb_crc(sb);
|
|
|
|
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
struct ftl_superblock *sb = dev->sb;
|
|
|
|
|
|
|
|
sb->clean = 0;
|
2022-06-09 12:51:45 +00:00
|
|
|
dev->sb_shm->shm_clean = false;
|
2022-06-21 13:05:02 +00:00
|
|
|
sb->header.crc = get_sb_crc(sb);
|
|
|
|
persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
|
|
|
|
}
|
|
|
|
|
2022-06-01 09:19:04 +00:00
|
|
|
void
|
|
|
|
ftl_mngt_set_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
struct ftl_superblock *sb = dev->sb;
|
|
|
|
|
|
|
|
sb->clean = 1;
|
|
|
|
dev->sb_shm->shm_clean = false;
|
|
|
|
sb->header.crc = get_sb_crc(sb);
|
|
|
|
persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
|
|
|
|
|
|
|
|
dev->sb_shm->shm_ready = false;
|
|
|
|
}
|
|
|
|
|
2022-06-01 09:03:05 +00:00
|
|
|
void
|
|
|
|
ftl_mngt_set_shm_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
struct ftl_superblock *sb = dev->sb;
|
|
|
|
|
|
|
|
sb->clean = 1;
|
|
|
|
dev->sb_shm->shm_clean = true;
|
|
|
|
sb->header.crc = get_sb_crc(sb);
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
|
2022-05-31 11:48:28 +00:00
|
|
|
void
|
|
|
|
ftl_mngt_load_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
FTL_NOTICELOG(dev, "SHM: clean %"PRIu64", shm_clean %d\n", dev->sb->clean, dev->sb_shm->shm_clean);
|
|
|
|
|
|
|
|
if (!ftl_fast_startup(dev)) {
|
|
|
|
restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FTL_DEBUGLOG(dev, "SHM: found SB\n");
|
|
|
|
if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_SB)) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_validate_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
struct ftl_superblock *sb = dev->sb;
|
|
|
|
|
|
|
|
if (!ftl_superblock_check_magic(sb)) {
|
|
|
|
FTL_ERRLOG(dev, "Invalid FTL superblock magic\n");
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sb->header.crc != get_sb_crc(sb)) {
|
|
|
|
FTL_ERRLOG(dev, "Invalid FTL superblock CRC\n");
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-09-12 08:14:29 +00:00
|
|
|
if (ftl_superblock_upgrade(dev)) {
|
|
|
|
FTL_ERRLOG(dev, "FTL superblock dirty or invalid version\n");
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-31 11:48:28 +00:00
|
|
|
if (spdk_uuid_compare(&sb->uuid, &dev->conf.uuid) != 0) {
|
|
|
|
FTL_ERRLOG(dev, "Invalid FTL superblock UUID\n");
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sb->lba_cnt == 0) {
|
|
|
|
FTL_ERRLOG(dev, "Invalid FTL superblock lba_cnt\n");
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dev->num_lbas = sb->lba_cnt;
|
|
|
|
|
|
|
|
/* The sb has just been read. Validate and update the conf */
|
|
|
|
if (sb->overprovisioning == 0 || sb->overprovisioning >= 100) {
|
|
|
|
FTL_ERRLOG(dev, "Invalid FTL superblock lba_rsvd\n");
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dev->conf.overprovisioning = sb->overprovisioning;
|
|
|
|
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loads and verifies superblock contents - utilized during the load of an FTL
|
|
|
|
* instance (both from a clean and dirty shutdown).
|
|
|
|
*/
|
|
|
|
static const struct ftl_mngt_process_desc desc_restore_sb = {
|
|
|
|
.name = "SB restore",
|
|
|
|
.steps = {
|
|
|
|
{
|
|
|
|
.name = "Load super block",
|
|
|
|
.action = ftl_mngt_load_sb
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Validate super block",
|
|
|
|
.action = ftl_mngt_validate_sb
|
|
|
|
},
|
|
|
|
{}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-06-21 13:05:02 +00:00
|
|
|
/*
|
|
|
|
* Initializes the superblock fields during first startup of FTL
|
|
|
|
*/
|
|
|
|
static const struct ftl_mngt_process_desc desc_init_sb = {
|
|
|
|
.name = "SB initialize",
|
|
|
|
.steps = {
|
|
|
|
{
|
|
|
|
.name = "Default-initialize superblock",
|
|
|
|
.action = ftl_mngt_init_default_sb,
|
|
|
|
},
|
|
|
|
{}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-06-15 08:02:25 +00:00
|
|
|
#ifdef SPDK_FTL_VSS_EMU
|
|
|
|
void
|
|
|
|
ftl_mngt_md_init_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
struct ftl_layout *layout = &dev->layout;
|
|
|
|
struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS];
|
|
|
|
|
|
|
|
/* Initialize VSS layout */
|
|
|
|
ftl_layout_setup_vss_emu(dev);
|
|
|
|
|
|
|
|
/* Allocate md buf */
|
|
|
|
layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = ftl_md_create(dev, region->current.blocks,
|
2022-07-08 23:14:11 +00:00
|
|
|
region->vss_blksz, NULL, FTL_MD_CREATE_HEAP, region);
|
2022-06-15 08:02:25 +00:00
|
|
|
if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_md_deinit_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
struct ftl_layout *layout = &dev->layout;
|
|
|
|
|
|
|
|
if (layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
|
2022-06-10 12:15:35 +00:00
|
|
|
ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_VSS], 0);
|
2022-06-15 08:02:25 +00:00
|
|
|
layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
#endif
|
2022-06-21 13:05:02 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
struct ftl_layout *layout = &dev->layout;
|
|
|
|
struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
|
|
|
|
char uuid[SPDK_UUID_STRING_LEN];
|
2022-06-28 13:58:29 +00:00
|
|
|
int md_create_flags = ftl_md_create_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB);
|
2022-06-21 13:05:02 +00:00
|
|
|
|
|
|
|
/* Must generate UUID before MD create on SHM for the SB */
|
|
|
|
if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
|
|
|
|
spdk_uuid_generate(&dev->conf.uuid);
|
|
|
|
spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
|
|
|
|
FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid);
|
|
|
|
}
|
|
|
|
|
2022-06-28 13:58:29 +00:00
|
|
|
shm_retry:
|
2022-06-09 12:51:45 +00:00
|
|
|
/* Allocate md buf */
|
|
|
|
dev->sb_shm = NULL;
|
|
|
|
dev->sb_shm_md = ftl_md_create(dev, spdk_divide_round_up(sizeof(*dev->sb_shm), FTL_BLOCK_SIZE),
|
|
|
|
0, "sb_shm",
|
|
|
|
md_create_flags, NULL);
|
|
|
|
if (dev->sb_shm_md == NULL) {
|
2022-06-28 13:58:29 +00:00
|
|
|
/* The first attempt may fail when trying to open SHM - try to create new */
|
|
|
|
if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
|
|
|
|
md_create_flags |= FTL_MD_CREATE_SHM_NEW;
|
|
|
|
goto shm_retry;
|
|
|
|
}
|
|
|
|
if (dev->sb_shm_md == NULL) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
2022-06-09 12:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dev->sb_shm = ftl_md_get_buffer(dev->sb_shm_md);
|
|
|
|
|
2022-06-21 13:05:02 +00:00
|
|
|
/* Setup the layout of a superblock */
|
|
|
|
if (ftl_layout_setup_superblock(dev)) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate md buf */
|
|
|
|
layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
|
2022-06-28 13:53:17 +00:00
|
|
|
region->vss_blksz, region->name,
|
|
|
|
md_create_flags, region);
|
2022-06-21 13:05:02 +00:00
|
|
|
if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
|
2022-06-28 13:58:29 +00:00
|
|
|
/* The first attempt may fail when trying to open SHM - try to create new */
|
|
|
|
if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
|
|
|
|
md_create_flags |= FTL_MD_CREATE_SHM_NEW;
|
|
|
|
ftl_md_destroy(dev->sb_shm_md, 0);
|
|
|
|
goto shm_retry;
|
|
|
|
}
|
2022-06-21 13:05:02 +00:00
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Link the md buf to the device */
|
|
|
|
dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
|
|
|
|
|
|
|
|
/* Setup superblock mirror to QLC */
|
|
|
|
region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
|
|
|
|
layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
|
2022-06-28 13:53:17 +00:00
|
|
|
region->vss_blksz, NULL, FTL_MD_CREATE_HEAP, region);
|
2022-06-21 13:05:02 +00:00
|
|
|
if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the superblock */
|
|
|
|
if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
|
|
|
|
ftl_mngt_call_process(mngt, &desc_init_sb);
|
|
|
|
} else {
|
2022-05-31 11:48:28 +00:00
|
|
|
ftl_mngt_call_process(mngt, &desc_restore_sb);
|
2022-06-21 13:05:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
struct ftl_layout *layout = &dev->layout;
|
|
|
|
|
|
|
|
if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
|
2022-06-10 12:15:35 +00:00
|
|
|
ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB],
|
|
|
|
ftl_md_destroy_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB));
|
2022-06-21 13:05:02 +00:00
|
|
|
layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
|
2022-06-10 12:15:35 +00:00
|
|
|
ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE], 0);
|
2022-06-21 13:05:02 +00:00
|
|
|
layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL;
|
|
|
|
}
|
|
|
|
|
2022-06-10 12:15:35 +00:00
|
|
|
ftl_md_destroy(dev->sb_shm_md, ftl_md_destroy_shm_flags(dev));
|
2022-06-09 12:51:45 +00:00
|
|
|
dev->sb_shm_md = NULL;
|
|
|
|
dev->sb_shm = NULL;
|
|
|
|
|
2022-06-21 13:05:02 +00:00
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
2022-05-31 11:48:28 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
ftl_mngt_restore_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (ftl_fast_startup(dev)) {
|
|
|
|
FTL_DEBUGLOG(dev, "SHM: found nv cache md\n");
|
|
|
|
if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD)) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ftl_mngt_restore_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (ftl_fast_startup(dev)) {
|
|
|
|
FTL_DEBUGLOG(dev, "SHM: found vldmap\n");
|
|
|
|
if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP)) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ftl_mngt_restore_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (ftl_fast_startup(dev)) {
|
|
|
|
FTL_DEBUGLOG(dev, "SHM: found band md\n");
|
|
|
|
if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD)) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
|
|
|
|
}
|
|
|
|
|
2022-05-27 11:46:59 +00:00
|
|
|
static void
|
|
|
|
ftl_mngt_restore_trim_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (ftl_fast_startup(dev)) {
|
|
|
|
FTL_DEBUGLOG(dev, "SHM: found trim md\n");
|
|
|
|
if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD)) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_TRIM_MD);
|
|
|
|
}
|
|
|
|
|
2022-05-31 11:48:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef SPDK_FTL_VSS_EMU
|
|
|
|
static void
|
|
|
|
ftl_mngt_restore_vss_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_VSS);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loads metadata after a clean shutdown.
|
|
|
|
*/
|
|
|
|
static const struct ftl_mngt_process_desc desc_restore = {
|
|
|
|
.name = "Restore metadata",
|
|
|
|
.steps = {
|
|
|
|
#ifdef SPDK_FTL_VSS_EMU
|
|
|
|
{
|
|
|
|
.name = "Restore VSS metadata",
|
|
|
|
.action = ftl_mngt_restore_vss_metadata,
|
|
|
|
},
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
.name = "Restore NV cache metadata",
|
|
|
|
.action = ftl_mngt_restore_nv_cache_metadata,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Restore valid map metadata",
|
|
|
|
.action = ftl_mngt_restore_vld_map_metadata,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "Restore band info metadata",
|
|
|
|
.action = ftl_mngt_restore_band_info_metadata,
|
|
|
|
},
|
2022-05-27 11:46:59 +00:00
|
|
|
{
|
|
|
|
.name = "Restore trim metadata",
|
|
|
|
.action = ftl_mngt_restore_trim_metadata,
|
|
|
|
},
|
2022-05-31 11:48:28 +00:00
|
|
|
{}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_restore_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
ftl_mngt_call_process(mngt, &desc_restore);
|
|
|
|
}
|
2022-05-27 12:57:35 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|