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:
parent
55147295d7
commit
cbd7ae6df7
@ -72,6 +72,8 @@ _ftl_band_set_free(struct ftl_band *band)
|
||||
|
||||
dev->num_free++;
|
||||
ftl_apply_limits(dev);
|
||||
|
||||
band->md->p2l_map_checksum = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -137,8 +139,6 @@ ftl_band_set_state(struct ftl_band *band, enum ftl_band_state state)
|
||||
case FTL_BAND_STATE_FREE:
|
||||
assert(band->md->state == FTL_BAND_STATE_CLOSED);
|
||||
_ftl_band_set_free(band);
|
||||
|
||||
band->md->p2l_map_checksum = 0;
|
||||
break;
|
||||
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
void ftl_band_init_gc_iter(struct spdk_ftl_dev *dev);
|
||||
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_close(struct ftl_band *band);
|
||||
void ftl_band_free(struct ftl_band *band);
|
||||
|
@ -1343,6 +1343,74 @@ chunk_alloc_p2l_map(struct ftl_nv_cache_chunk *chunk)
|
||||
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);
|
||||
|
||||
static void
|
||||
|
@ -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_load_state(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);
|
||||
|
@ -127,6 +127,65 @@ persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
@ -442,7 +579,7 @@ shm_retry:
|
||||
if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
|
||||
ftl_mngt_call_process(mngt, &desc_init_sb);
|
||||
} 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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_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_deinit_vld_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||
|
@ -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_mempool_claim_df, void *, (struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id),
|
||||
NULL);
|
||||
DEFINE_STUB(ftl_bitmap_count_set, uint64_t, (struct ftl_bitmap *bitmap), 0);
|
||||
|
||||
static void
|
||||
adjust_bitmap(struct ftl_bitmap **bitmap, uint64_t *bit)
|
||||
|
Loading…
Reference in New Issue
Block a user