FTL: Add metadata restore functionality

Adds necessary functions for setting up the state of FTL components
based on loaded in metadata.

Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com>
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
Change-Id: I3a4c05230c877850e61d4f31d495d38121d27b3f
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13362
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>
This commit is contained in:
Kozlowski Mateusz 2022-05-31 13:48:28 +02:00 committed by Ben Walker
parent 55147295d7
commit cbd7ae6df7
7 changed files with 337 additions and 3 deletions

View File

@ -72,6 +72,8 @@ _ftl_band_set_free(struct ftl_band *band)
dev->num_free++; dev->num_free++;
ftl_apply_limits(dev); ftl_apply_limits(dev);
band->md->p2l_map_checksum = 0;
} }
static void static void
@ -137,8 +139,6 @@ ftl_band_set_state(struct ftl_band *band, enum ftl_band_state state)
case FTL_BAND_STATE_FREE: case FTL_BAND_STATE_FREE:
assert(band->md->state == FTL_BAND_STATE_CLOSED); assert(band->md->state == FTL_BAND_STATE_CLOSED);
_ftl_band_set_free(band); _ftl_band_set_free(band);
band->md->p2l_map_checksum = 0;
break; break;
case FTL_BAND_STATE_PREP: case FTL_BAND_STATE_PREP:
@ -626,3 +626,32 @@ ftl_band_init_gc_iter(struct spdk_ftl_dev *dev)
/* We lost GC state due to dirty shutdown, reset GC state to start over */ /* We lost GC state due to dirty shutdown, reset GC state to start over */
ftl_band_reset_gc_iter(dev); ftl_band_reset_gc_iter(dev);
} }
void
ftl_valid_map_load_state(struct spdk_ftl_dev *dev)
{
uint64_t i;
struct ftl_band *band;
for (i = 0; i < dev->num_bands; i++) {
band = &dev->bands[i];
band->p2l_map.num_valid = ftl_bitmap_count_set(band->p2l_map.valid);
}
}
void
ftl_bands_load_state(struct spdk_ftl_dev *dev)
{
uint64_t i;
struct ftl_band *band;
for (i = 0; i < dev->num_bands; i++) {
band = &dev->bands[i];
if (band->md->state == FTL_BAND_STATE_FREE) {
/* All bands start on the shut list during startup, removing it manually here */
TAILQ_REMOVE(&dev->shut_bands, band, queue_entry);
_ftl_band_set_free(band);
}
}
}

View File

@ -160,6 +160,8 @@ size_t ftl_p2l_map_pool_elem_size(struct spdk_ftl_dev *dev);
struct ftl_band *ftl_band_search_next_to_reloc(struct spdk_ftl_dev *dev); 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); void ftl_band_init_gc_iter(struct spdk_ftl_dev *dev);
ftl_addr ftl_band_p2l_map_addr(struct ftl_band *band); 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);
void ftl_band_open(struct ftl_band *band, enum ftl_band_type type); void ftl_band_open(struct ftl_band *band, enum ftl_band_type type);
void ftl_band_close(struct ftl_band *band); void ftl_band_close(struct ftl_band *band);
void ftl_band_free(struct ftl_band *band); void ftl_band_free(struct ftl_band *band);

View File

@ -1343,6 +1343,74 @@ chunk_alloc_p2l_map(struct ftl_nv_cache_chunk *chunk)
return 0; return 0;
} }
int
ftl_nv_cache_load_state(struct ftl_nv_cache *nv_cache)
{
struct ftl_nv_cache_chunk *chunk;
uint64_t chunks_number, offset, i;
int status = 0;
struct spdk_ftl_dev *dev = SPDK_CONTAINEROF(nv_cache, struct spdk_ftl_dev, nv_cache);
nv_cache->chunk_current = NULL;
TAILQ_INIT(&nv_cache->chunk_free_list);
TAILQ_INIT(&nv_cache->chunk_full_list);
nv_cache->chunk_full_count = nv_cache->chunk_free_count = 0;
assert(nv_cache->chunk_open_count == 0);
offset = nvc_data_offset(nv_cache);
chunk = nv_cache->chunks;
if (!chunk) {
FTL_ERRLOG(dev, "No NV cache metadata\n");
return -1;
}
for (i = 0; i < nv_cache->chunk_count; i++, chunk++) {
chunk->nv_cache = nv_cache;
nvc_validate_md(nv_cache, chunk->md);
if (offset != chunk->offset) {
status = -EINVAL;
goto error;
}
if (chunk->md->blocks_written == nv_cache->chunk_blocks) {
/* Chunk full, move it on full list */
TAILQ_INSERT_TAIL(&nv_cache->chunk_full_list, chunk, entry);
nv_cache->chunk_full_count++;
} else if (0 == chunk->md->blocks_written) {
/* Chunk empty, move it on empty list */
TAILQ_INSERT_TAIL(&nv_cache->chunk_free_list, chunk, entry);
nv_cache->chunk_free_count++;
} else {
status = -EINVAL;
goto error;
}
offset += nv_cache->chunk_blocks;
}
chunks_number = nv_cache->chunk_free_count + nv_cache->chunk_full_count;
assert(nv_cache->chunk_current == NULL);
if (chunks_number != nv_cache->chunk_count) {
FTL_ERRLOG(dev, "Inconsistent NV cache metadata\n");
status = -EINVAL;
goto error;
}
FTL_NOTICELOG(dev, "FTL NV Cache: full chunks = %lu, empty chunks = %lu\n",
nv_cache->chunk_full_count, nv_cache->chunk_free_count);
if (0 == status) {
FTL_NOTICELOG(dev, "FTL NV Cache: state loaded successfully\n");
} else {
FTL_ERRLOG(dev, "FTL NV Cache: loading state ERROR\n");
}
error:
return status;
}
typedef void (*ftl_chunk_ops_cb)(struct ftl_nv_cache_chunk *chunk, void *cntx, bool status); typedef void (*ftl_chunk_ops_cb)(struct ftl_nv_cache_chunk *chunk, void *cntx, bool status);
static void static void

View File

@ -180,6 +180,8 @@ void ftl_nv_cache_set_addr(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr addr
int ftl_nv_cache_save_state(struct ftl_nv_cache *nv_cache); int ftl_nv_cache_save_state(struct ftl_nv_cache *nv_cache);
int ftl_nv_cache_load_state(struct ftl_nv_cache *nv_cache);
void ftl_nv_cache_halt(struct ftl_nv_cache *nv_cache); void ftl_nv_cache_halt(struct ftl_nv_cache *nv_cache);
int ftl_nv_cache_chunks_busy(struct ftl_nv_cache *nv_cache); int ftl_nv_cache_chunks_busy(struct ftl_nv_cache *nv_cache);

View File

@ -127,6 +127,65 @@ persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
ftl_md_persist(md); ftl_md_persist(md);
} }
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);
}
void void
ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{ {
@ -322,6 +381,84 @@ ftl_mngt_set_shm_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
ftl_mngt_next_step(mngt); ftl_mngt_next_step(mngt);
} }
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;
}
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
},
{}
}
};
/* /*
* Initializes the superblock fields during first startup of FTL * Initializes the superblock fields during first startup of FTL
*/ */
@ -442,7 +579,7 @@ shm_retry:
if (dev->conf.mode & SPDK_FTL_MODE_CREATE) { if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
ftl_mngt_call_process(mngt, &desc_init_sb); ftl_mngt_call_process(mngt, &desc_init_sb);
} else { } else {
ftl_mngt_fail_step(mngt); ftl_mngt_call_process(mngt, &desc_restore_sb);
} }
} }
@ -468,3 +605,92 @@ ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mn
ftl_mngt_next_step(mngt); ftl_mngt_next_step(mngt);
} }
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);
}
#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,
},
{}
}
};
void
ftl_mngt_restore_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
ftl_mngt_call_process(mngt, &desc_restore);
}

View File

@ -100,6 +100,12 @@ void ftl_mngt_set_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
void ftl_mngt_set_shm_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_set_shm_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_load_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_validate_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_restore_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_init_vld_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_init_vld_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_deinit_vld_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_deinit_vld_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);

View File

@ -122,6 +122,7 @@ DEFINE_STUB_V(ftl_writer_run, (struct ftl_writer *writer));
DEFINE_STUB(ftl_writer_is_halted, bool, (struct ftl_writer *writer), true); DEFINE_STUB(ftl_writer_is_halted, bool, (struct ftl_writer *writer), true);
DEFINE_STUB(ftl_mempool_claim_df, void *, (struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id), DEFINE_STUB(ftl_mempool_claim_df, void *, (struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id),
NULL); NULL);
DEFINE_STUB(ftl_bitmap_count_set, uint64_t, (struct ftl_bitmap *bitmap), 0);
static void static void
adjust_bitmap(struct ftl_bitmap **bitmap, uint64_t *bit) adjust_bitmap(struct ftl_bitmap **bitmap, uint64_t *bit)