Ftl: Open chunk recovery

At the end of the recovery step, all chunks will be transferred to closed state.
Missing write pointer data filled with LBA_INVALID

Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com>
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
Change-Id: Id496e465e46fa24b04b30f2558bdacfdd668e8a4
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13375
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>
Community-CI: Mellanox Build Bot
This commit is contained in:
Kozlowski Mateusz 2022-05-30 10:14:21 +02:00 committed by Jim Harris
parent 5c5587d805
commit c7c9211ee0
3 changed files with 278 additions and 0 deletions

View File

@ -1691,6 +1691,192 @@ ftl_chunk_close(struct ftl_nv_cache_chunk *chunk)
ftl_chunk_basic_rq_write(chunk, brq); ftl_chunk_basic_rq_write(chunk, brq);
} }
static int ftl_chunk_read_tail_md(struct ftl_nv_cache_chunk *chunk, struct ftl_basic_rq *brq,
void (*cb)(struct ftl_basic_rq *brq), void *cb_ctx);
static void read_tail_md_cb(struct ftl_basic_rq *brq);
static void recover_open_chunk_cb(struct ftl_basic_rq *brq);
static void
restore_chunk_close_cb(int status, void *ctx)
{
struct ftl_basic_rq *parent = (struct ftl_basic_rq *)ctx;
struct ftl_nv_cache_chunk *chunk = parent->io.chunk;
struct ftl_p2l_map *p2l_map = &chunk->p2l_map;
if (spdk_unlikely(status)) {
parent->success = false;
} else {
chunk->md->p2l_map_checksum = p2l_map->chunk_dma_md->p2l_map_checksum;
chunk->md->state = FTL_CHUNK_STATE_CLOSED;
}
read_tail_md_cb(parent);
}
static void
restore_fill_p2l_map_cb(struct ftl_basic_rq *parent)
{
struct ftl_nv_cache_chunk *chunk = parent->io.chunk;
struct ftl_p2l_map *p2l_map = &chunk->p2l_map;
struct spdk_ftl_dev *dev = SPDK_CONTAINEROF(chunk->nv_cache, struct spdk_ftl_dev, nv_cache);
struct ftl_md *md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_NVC_MD];
struct ftl_layout_region *region = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_NVC_MD];
uint32_t chunk_map_crc;
/* Set original callback */
ftl_basic_rq_set_owner(parent, recover_open_chunk_cb, parent->owner.priv);
if (spdk_unlikely(!parent->success)) {
read_tail_md_cb(parent);
return;
}
chunk_map_crc = spdk_crc32c_update(p2l_map->chunk_map,
chunk->nv_cache->tail_md_chunk_blocks * FTL_BLOCK_SIZE, 0);
memcpy(p2l_map->chunk_dma_md, chunk->md, region->entry_size * FTL_BLOCK_SIZE);
p2l_map->chunk_dma_md->state = FTL_CHUNK_STATE_CLOSED;
p2l_map->chunk_dma_md->write_pointer = chunk->nv_cache->chunk_blocks;
p2l_map->chunk_dma_md->blocks_written = chunk->nv_cache->chunk_blocks;
p2l_map->chunk_dma_md->p2l_map_checksum = chunk_map_crc;
ftl_md_persist_entry(md, get_chunk_idx(chunk), p2l_map->chunk_dma_md, NULL,
restore_chunk_close_cb, parent, &chunk->md_persist_entry_ctx);
}
static void
restore_fill_tail_md(struct ftl_basic_rq *parent, struct ftl_nv_cache_chunk *chunk)
{
struct spdk_ftl_dev *dev = SPDK_CONTAINEROF(chunk->nv_cache, struct spdk_ftl_dev, nv_cache);
void *metadata;
chunk->md->close_seq_id = ftl_get_next_seq_id(dev);
metadata = chunk->p2l_map.chunk_map;
ftl_basic_rq_init(dev, parent, metadata, chunk->nv_cache->tail_md_chunk_blocks);
ftl_basic_rq_set_owner(parent, restore_fill_p2l_map_cb, parent->owner.priv);
parent->io.addr = chunk->offset + chunk_tail_md_offset(chunk->nv_cache);
parent->io.chunk = chunk;
ftl_chunk_basic_rq_write(chunk, parent);
}
static void
read_open_chunk_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
{
struct ftl_rq *rq = (struct ftl_rq *)cb_arg;
struct ftl_basic_rq *parent = (struct ftl_basic_rq *)rq->owner.priv;
struct ftl_nv_cache_chunk *chunk = parent->io.chunk;
struct ftl_nv_cache *nv_cache = chunk->nv_cache;
struct spdk_ftl_dev *dev = SPDK_CONTAINEROF(chunk->nv_cache, struct spdk_ftl_dev, nv_cache);
union ftl_md_vss *md;
uint64_t cache_offset = bdev_io->u.bdev.offset_blocks;
uint64_t len = bdev_io->u.bdev.num_blocks;
ftl_addr addr = ftl_addr_from_nvc_offset(dev, cache_offset);
int rc;
spdk_bdev_free_io(bdev_io);
if (!success) {
parent->success = false;
read_tail_md_cb(parent);
return;
}
while (rq->iter.idx < rq->iter.count) {
/* Get metadata */
md = rq->entries[rq->iter.idx].io_md;
if (md->nv_cache.seq_id != chunk->md->seq_id) {
md->nv_cache.lba = FTL_LBA_INVALID;
}
/*
* The p2l map contains effectively random data at this point (since it contains arbitrary
* blocks from potentially not even filled tail md), so even LBA_INVALID needs to be set explicitly
*/
ftl_chunk_set_addr(chunk, md->nv_cache.lba, addr + rq->iter.idx);
rq->iter.idx++;
}
if (cache_offset + len < chunk->offset + chunk_tail_md_offset(nv_cache)) {
cache_offset += len;
len = spdk_min(dev->xfer_size, chunk->offset + chunk_tail_md_offset(nv_cache) - cache_offset);
rq->iter.idx = 0;
rq->iter.count = len;
rc = ftl_nv_cache_bdev_readv_blocks_with_md(dev, nv_cache->bdev_desc,
nv_cache->cache_ioch,
rq->io_vec, len,
rq->io_md,
cache_offset, len,
read_open_chunk_cb,
rq);
if (rc) {
ftl_rq_del(rq);
parent->success = false;
read_tail_md_cb(parent);
return;
}
} else {
ftl_rq_del(rq);
restore_fill_tail_md(parent, chunk);
}
}
static void
restore_open_chunk(struct ftl_nv_cache_chunk *chunk, struct ftl_basic_rq *parent)
{
struct ftl_nv_cache *nv_cache = chunk->nv_cache;
struct spdk_ftl_dev *dev = SPDK_CONTAINEROF(nv_cache, struct spdk_ftl_dev, nv_cache);
struct ftl_rq *rq;
uint64_t addr;
uint64_t len = dev->xfer_size;
int rc;
/*
* We've just read the p2l map, prefill it with INVALID LBA
* TODO we need to do this because tail md blocks (p2l map) are also represented in the p2l map, instead of just user data region
*/
memset(chunk->p2l_map.chunk_map, -1, FTL_BLOCK_SIZE * nv_cache->tail_md_chunk_blocks);
/* Need to read user data, recalculate chunk's P2L and write tail md with it */
rq = ftl_rq_new(dev, dev->nv_cache.md_size);
if (!rq) {
parent->success = false;
read_tail_md_cb(parent);
return;
}
rq->owner.priv = parent;
rq->iter.idx = 0;
rq->iter.count = len;
addr = chunk->offset;
len = spdk_min(dev->xfer_size, chunk->offset + chunk_tail_md_offset(nv_cache) - addr);
rc = ftl_nv_cache_bdev_readv_blocks_with_md(dev, nv_cache->bdev_desc,
nv_cache->cache_ioch,
rq->io_vec, len,
rq->io_md,
addr, len,
read_open_chunk_cb,
rq);
if (rc) {
ftl_rq_del(rq);
parent->success = false;
read_tail_md_cb(parent);
}
}
static void
read_tail_md_cb(struct ftl_basic_rq *brq)
{
brq->owner.cb(brq);
}
static int static int
ftl_chunk_read_tail_md(struct ftl_nv_cache_chunk *chunk, struct ftl_basic_rq *brq, ftl_chunk_read_tail_md(struct ftl_nv_cache_chunk *chunk, struct ftl_basic_rq *brq,
void (*cb)(struct ftl_basic_rq *brq), void *cb_ctx) void (*cb)(struct ftl_basic_rq *brq), void *cb_ctx)
@ -1903,6 +2089,92 @@ ftl_mngt_nv_cache_restore_chunk_state(struct spdk_ftl_dev *dev, struct ftl_mngt_
ftl_md_restore(md); ftl_md_restore(md);
} }
static void
recover_open_chunk_cb(struct ftl_basic_rq *brq)
{
struct ftl_mngt_process *mngt = brq->owner.priv;
struct ftl_nv_cache_chunk *chunk = brq->io.chunk;
struct ftl_nv_cache *nvc = chunk->nv_cache;
struct spdk_ftl_dev *dev = ftl_mngt_get_dev(mngt);
chunk_free_p2l_map(chunk);
if (!brq->success) {
FTL_ERRLOG(dev, "Recovery chunk ERROR, offset = %"PRIu64", seq id %"PRIu64"\n", chunk->offset,
chunk->md->seq_id);
ftl_mngt_fail_step(mngt);
return;
}
FTL_NOTICELOG(dev, "Recovered chunk, offset = %"PRIu64", seq id %"PRIu64"\n", chunk->offset,
chunk->md->seq_id);
TAILQ_REMOVE(&nvc->chunk_open_list, chunk, entry);
nvc->chunk_open_count--;
TAILQ_INSERT_TAIL(&nvc->chunk_full_list, chunk, entry);
nvc->chunk_full_count++;
/* This is closed chunk */
chunk->md->write_pointer = nvc->chunk_blocks;
chunk->md->blocks_written = nvc->chunk_blocks;
ftl_mngt_continue_step(mngt);
}
void
ftl_mngt_nv_cache_recover_open_chunk(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
struct ftl_nv_cache *nvc = &dev->nv_cache;
struct ftl_nv_cache_chunk *chunk;
struct ftl_basic_rq *brq = ftl_mngt_get_step_ctx(mngt);
if (!brq) {
if (TAILQ_EMPTY(&nvc->chunk_open_list)) {
FTL_NOTICELOG(dev, "No open chunks to recover P2L\n");
ftl_mngt_next_step(mngt);
return;
}
if (ftl_mngt_alloc_step_ctx(mngt, sizeof(*brq))) {
ftl_mngt_fail_step(mngt);
return;
}
brq = ftl_mngt_get_step_ctx(mngt);
ftl_basic_rq_set_owner(brq, recover_open_chunk_cb, mngt);
}
if (TAILQ_EMPTY(&nvc->chunk_open_list)) {
if (!is_chunk_count_valid(nvc)) {
FTL_ERRLOG(dev, "Recovery ERROR, invalid number of chunk\n");
ftl_mngt_fail_step(mngt);
return;
}
/*
* Now all chunks loaded and closed, do final step of restoring
* chunks state
*/
if (ftl_nv_cache_load_state(nvc)) {
ftl_mngt_fail_step(mngt);
} else {
ftl_mngt_next_step(mngt);
}
} else {
chunk = TAILQ_FIRST(&nvc->chunk_open_list);
if (chunk_alloc_p2l_map(chunk)) {
ftl_mngt_fail_step(mngt);
return;
}
brq->io.chunk = chunk;
FTL_NOTICELOG(dev, "Start recovery open chunk, offset = %"PRIu64", seq id %"PRIu64"\n",
chunk->offset, chunk->md->seq_id);
restore_open_chunk(chunk, brq);
}
}
int int
ftl_nv_cache_chunks_busy(struct ftl_nv_cache *nv_cache) ftl_nv_cache_chunks_busy(struct ftl_nv_cache *nv_cache)
{ {

View File

@ -217,6 +217,8 @@ void ftl_nv_cache_get_max_seq_id(struct ftl_nv_cache *nv_cache, uint64_t *open_s
void ftl_mngt_nv_cache_restore_chunk_state(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_nv_cache_restore_chunk_state(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
void ftl_mngt_nv_cache_recover_open_chunk(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
typedef int (*ftl_chunk_md_cb)(struct ftl_nv_cache_chunk *chunk, void *cntx); typedef int (*ftl_chunk_md_cb)(struct ftl_nv_cache_chunk *chunk, void *cntx);
void ftl_mngt_nv_cache_restore_l2p(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt, void ftl_mngt_nv_cache_restore_l2p(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,

View File

@ -780,6 +780,10 @@ static const struct ftl_mngt_process_desc g_desc_recovery = {
.name = "Recover max seq ID", .name = "Recover max seq ID",
.action = ftl_mngt_recover_seq_id .action = ftl_mngt_recover_seq_id
}, },
{
.name = "Recover open chunks P2L",
.action = ftl_mngt_nv_cache_recover_open_chunk
},
{ {
.name = "Recovery iterations", .name = "Recovery iterations",
.action = ftl_mngt_recovery_run_iteration, .action = ftl_mngt_recovery_run_iteration,