FTL: Band L2P recovery
Recovers L2P based on all non-free bands' P2L. Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com> Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Change-Id: Ice9e77b00161b031c795570baf3ed8c92dfecef0 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13372 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Mellanox Build Bot Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
40f556ca38
commit
ca53f5a6df
@ -248,6 +248,75 @@ ftl_mngt_recovery_restore_band_state(struct spdk_ftl_dev *dev, struct ftl_mngt_p
|
|||||||
ftl_md_restore(md);
|
ftl_md_restore(md);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct band_md_ctx {
|
||||||
|
int status;
|
||||||
|
uint64_t qd;
|
||||||
|
uint64_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
ftl_mngt_recovery_walk_band_tail_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
|
||||||
|
ftl_band_md_cb cb)
|
||||||
|
{
|
||||||
|
struct band_md_ctx *sctx = ftl_mngt_get_step_ctx(mngt);
|
||||||
|
uint64_t num_bands = ftl_get_num_bands(dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function generates a high queue depth and will utilize ftl_mngt_continue_step during completions to make sure all bands
|
||||||
|
* are processed before returning an error (if any were found) or continuing on.
|
||||||
|
*/
|
||||||
|
if (0 == sctx->qd && sctx->id == num_bands) {
|
||||||
|
if (sctx->status) {
|
||||||
|
ftl_mngt_fail_step(mngt);
|
||||||
|
} else {
|
||||||
|
ftl_mngt_next_step(mngt);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (sctx->id < num_bands) {
|
||||||
|
struct ftl_band *band = &dev->bands[sctx->id];
|
||||||
|
|
||||||
|
if (FTL_BAND_STATE_FREE == band->md->state) {
|
||||||
|
sctx->id++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FTL_BAND_STATE_OPEN == band->md->state || FTL_BAND_STATE_FULL == band->md->state) {
|
||||||
|
/* This band is already open and has valid P2L map */
|
||||||
|
sctx->id++;
|
||||||
|
sctx->qd++;
|
||||||
|
ftl_band_acquire_p2l_map(band);
|
||||||
|
cb(band, mngt, FTL_MD_SUCCESS);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
if (dev->sb->ckpt_seq_id && (band->md->close_seq_id <= dev->sb->ckpt_seq_id)) {
|
||||||
|
sctx->id++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
|
||||||
|
if (ftl_band_alloc_p2l_map(band)) {
|
||||||
|
/* No more free P2L map, try later */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sctx->id++;
|
||||||
|
ftl_band_read_tail_brq_md(band, cb, mngt);
|
||||||
|
sctx->qd++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == sctx->qd) {
|
||||||
|
/*
|
||||||
|
* No QD could happen due to all leftover bands being in free state.
|
||||||
|
* For streamlining of all potential error handling (since many bands are reading P2L at the same time),
|
||||||
|
* we're using ftl_mngt_continue_step to arrive at the same spot of checking for mngt step end (see beginning of function).
|
||||||
|
*/
|
||||||
|
ftl_mngt_continue_step(mngt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ftl_mngt_recovery_iteration_init_seq_ids(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
ftl_mngt_recovery_iteration_init_seq_ids(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||||
{
|
{
|
||||||
@ -304,6 +373,105 @@ ftl_mngt_recovery_iteration_save_l2p(struct spdk_ftl_dev *dev, struct ftl_mngt_p
|
|||||||
ftl_md_persist(md);
|
ftl_md_persist(md);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
restore_band_l2p_cb(struct ftl_band *band, void *cntx, enum ftl_md_status status)
|
||||||
|
{
|
||||||
|
struct ftl_mngt_process *mngt = cntx;
|
||||||
|
struct ftl_mngt_recovery_ctx *pctx = ftl_mngt_get_caller_ctx(mngt);
|
||||||
|
struct band_md_ctx *sctx = ftl_mngt_get_step_ctx(mngt);
|
||||||
|
struct spdk_ftl_dev *dev = band->dev;
|
||||||
|
ftl_addr addr, curr_addr;
|
||||||
|
uint64_t i, lba, seq_id, num_blks_in_band;
|
||||||
|
uint32_t band_map_crc;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (status != FTL_MD_SUCCESS) {
|
||||||
|
FTL_ERRLOG(dev, "L2P band restore error, failed to read P2L map\n");
|
||||||
|
rc = -EIO;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
band_map_crc = spdk_crc32c_update(band->p2l_map.band_map,
|
||||||
|
ftl_tail_md_num_blocks(band->dev) * FTL_BLOCK_SIZE, 0);
|
||||||
|
|
||||||
|
/* P2L map is only valid if the band state is closed */
|
||||||
|
if (FTL_BAND_STATE_CLOSED == band->md->state && band->md->p2l_map_checksum != band_map_crc) {
|
||||||
|
FTL_ERRLOG(dev, "L2P band restore error, inconsistent P2L map CRC\n");
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_blks_in_band = ftl_get_num_blocks_in_band(dev);
|
||||||
|
for (i = 0; i < num_blks_in_band; ++i) {
|
||||||
|
uint64_t lba_off;
|
||||||
|
lba = band->p2l_map.band_map[i].lba;
|
||||||
|
seq_id = band->p2l_map.band_map[i].seq_id;
|
||||||
|
|
||||||
|
if (lba == FTL_LBA_INVALID) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (lba >= dev->num_lbas) {
|
||||||
|
FTL_ERRLOG(dev, "L2P band restore ERROR, LBA out of range\n");
|
||||||
|
rc = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (lba < pctx->iter.lba_first || lba >= pctx->iter.lba_last) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lba_off = lba - pctx->iter.lba_first;
|
||||||
|
if (seq_id < pctx->l2p_snippet.seq_id[lba_off]) {
|
||||||
|
|
||||||
|
/* Overlapped band/chunk has newer data - invalidate P2L map on open/full band */
|
||||||
|
if (FTL_BAND_STATE_OPEN == band->md->state || FTL_BAND_STATE_FULL == band->md->state) {
|
||||||
|
addr = ftl_band_addr_from_block_offset(band, i);
|
||||||
|
ftl_band_set_p2l(band, FTL_LBA_INVALID, addr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Newer data already recovered */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = ftl_band_addr_from_block_offset(band, i);
|
||||||
|
|
||||||
|
curr_addr = ftl_addr_load(dev, pctx->l2p_snippet.l2p, lba_off);
|
||||||
|
|
||||||
|
/* Overlapped band/chunk has newer data - invalidate P2L map on open/full band */
|
||||||
|
if (curr_addr != FTL_ADDR_INVALID && !ftl_addr_in_nvc(dev, curr_addr) && curr_addr != addr) {
|
||||||
|
struct ftl_band *curr_band = ftl_band_from_addr(dev, curr_addr);
|
||||||
|
|
||||||
|
if (FTL_BAND_STATE_OPEN == curr_band->md->state || FTL_BAND_STATE_FULL == curr_band->md->state) {
|
||||||
|
size_t prev_offset = ftl_band_block_offset_from_addr(curr_band, curr_addr);
|
||||||
|
if (curr_band->p2l_map.band_map[prev_offset].lba == lba &&
|
||||||
|
seq_id >= curr_band->p2l_map.band_map[prev_offset].seq_id) {
|
||||||
|
ftl_band_set_p2l(curr_band, FTL_LBA_INVALID, curr_addr, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ftl_addr_store(dev, pctx->l2p_snippet.l2p, lba_off, addr);
|
||||||
|
pctx->l2p_snippet.seq_id[lba_off] = seq_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
ftl_band_release_p2l_map(band);
|
||||||
|
|
||||||
|
sctx->qd--;
|
||||||
|
if (rc) {
|
||||||
|
sctx->status = rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ftl_mngt_continue_step(mngt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ftl_mngt_recovery_iteration_restore_band_l2p(struct spdk_ftl_dev *dev,
|
||||||
|
struct ftl_mngt_process *mngt)
|
||||||
|
{
|
||||||
|
ftl_mngt_recovery_walk_band_tail_md(dev, mngt, restore_band_l2p_cb);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ftl_mngt_recovery_iteration_restore_valid_map(struct spdk_ftl_dev *dev,
|
ftl_mngt_recovery_iteration_restore_valid_map(struct spdk_ftl_dev *dev,
|
||||||
struct ftl_mngt_process *mngt)
|
struct ftl_mngt_process *mngt)
|
||||||
@ -418,7 +586,7 @@ ftl_mngt_recovery_open_bands_p2l(struct spdk_ftl_dev *dev, struct ftl_mngt_proce
|
|||||||
TAILQ_FOREACH(band, &pctx->open_bands, queue_entry) {
|
TAILQ_FOREACH(band, &pctx->open_bands, queue_entry) {
|
||||||
band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
|
band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
|
||||||
if (ftl_band_alloc_p2l_map(band)) {
|
if (ftl_band_alloc_p2l_map(band)) {
|
||||||
FTL_ERRLOG(dev, "Open band recovery ERROR, Cannot allocate LBA map\n");
|
FTL_ERRLOG(dev, "Open band recovery ERROR, Cannot allocate P2L map\n");
|
||||||
ftl_mngt_fail_step(mngt);
|
ftl_mngt_fail_step(mngt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -493,6 +661,11 @@ static const struct ftl_mngt_process_desc g_desc_recovery_iteration = {
|
|||||||
.name = "Initialize sequence IDs",
|
.name = "Initialize sequence IDs",
|
||||||
.action = ftl_mngt_recovery_iteration_init_seq_ids,
|
.action = ftl_mngt_recovery_iteration_init_seq_ids,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "Restore band L2P",
|
||||||
|
.ctx_size = sizeof(struct band_md_ctx),
|
||||||
|
.action = ftl_mngt_recovery_iteration_restore_band_l2p,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "Restore valid map",
|
.name = "Restore valid map",
|
||||||
.action = ftl_mngt_recovery_iteration_restore_valid_map,
|
.action = ftl_mngt_recovery_iteration_restore_valid_map,
|
||||||
|
Loading…
Reference in New Issue
Block a user