From 36049672a3e420ca17fd55a474f7569749b750f4 Mon Sep 17 00:00:00 2001 From: Artur Paszkiewicz Date: Wed, 1 Jun 2022 10:49:48 +0200 Subject: [PATCH] ftl: sequence id tracking Track the relative sequence of opening and closing bands and chunks. Necessary for detecting the most recent user data during dirty shutdown recovery. Signed-off-by: Artur Paszkiewicz Signed-off-by: Kozlowski Mateusz Change-Id: I682030e58284d7b090667e4e5a9f4bbc7615708a Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13366 Tested-by: SPDK CI Jenkins Community-CI: Mellanox Build Bot Reviewed-by: Ben Walker Reviewed-by: Jim Harris --- lib/ftl/ftl_band.c | 8 +- lib/ftl/ftl_band.h | 6 ++ lib/ftl/ftl_band_ops.c | 2 + lib/ftl/ftl_core.c | 3 +- lib/ftl/ftl_core.h | 12 ++- lib/ftl/ftl_debug.c | 4 +- lib/ftl/ftl_internal.h | 11 ++- lib/ftl/ftl_io.h | 3 + lib/ftl/ftl_l2p.c | 4 + lib/ftl/ftl_nv_cache.c | 86 +++++++++++++++++++++- lib/ftl/ftl_nv_cache.h | 17 +++++ lib/ftl/ftl_reloc.c | 5 +- lib/ftl/ftl_rq.c | 1 + lib/ftl/ftl_sb_common.h | 1 + lib/ftl/ftl_sb_current.h | 7 +- lib/ftl/ftl_writer.c | 1 + lib/ftl/ftl_writer.h | 2 + lib/ftl/mngt/ftl_mngt_band.c | 42 +++++++++++ lib/ftl/mngt/ftl_mngt_misc.c | 3 +- lib/ftl/utils/ftl_md.h | 2 + test/unit/lib/ftl/ftl_band.c/ftl_band_ut.c | 4 +- 21 files changed, 208 insertions(+), 16 deletions(-) diff --git a/lib/ftl/ftl_band.c b/lib/ftl/ftl_band.c index 0dd538db8..691bb159e 100644 --- a/lib/ftl/ftl_band.c +++ b/lib/ftl/ftl_band.c @@ -68,6 +68,7 @@ _ftl_band_set_free(struct ftl_band *band) /* Add the band to the free band list */ TAILQ_INSERT_TAIL(&dev->free_bands, band, queue_entry); + band->md->close_seq_id = 0; band->reloc = false; dev->num_free++; @@ -192,7 +193,7 @@ ftl_band_set_addr(struct ftl_band *band, uint64_t lba, ftl_addr addr) offset = ftl_band_block_offset_from_addr(band, addr); - p2l_map->band_map[offset] = lba; + p2l_map->band_map[offset].lba = lba; p2l_map->num_valid++; ftl_bitmap_set(band->dev->valid_map, addr); } @@ -387,12 +388,17 @@ ftl_band_p2l_map_addr(struct ftl_band *band) int ftl_band_write_prep(struct ftl_band *band) { + struct spdk_ftl_dev *dev = band->dev; + if (ftl_band_alloc_p2l_map(band)) { return -1; } ftl_band_iter_init(band); + band->md->seq = ftl_get_next_seq_id(dev); + + FTL_DEBUGLOG(dev, "Band to write, id %u seq %"PRIu64"\n", band->id, band->md->seq); return 0; } diff --git a/lib/ftl/ftl_band.h b/lib/ftl/ftl_band.h index 8fa06f728..b344ddccb 100644 --- a/lib/ftl/ftl_band.h +++ b/lib/ftl/ftl_band.h @@ -61,6 +61,12 @@ struct ftl_band_md { /* Band type set during opening */ enum ftl_band_type type; + /* Sequence ID when band was opened */ + uint64_t seq; + + /* Sequence ID when band was closed */ + uint64_t close_seq_id; + /* Number of times band was fully written (ie. number of free -> closed state cycles) */ uint64_t wr_cnt; diff --git a/lib/ftl/ftl_band_ops.c b/lib/ftl/ftl_band_ops.c index fbcac8c84..ca9b09d36 100644 --- a/lib/ftl/ftl_band_ops.c +++ b/lib/ftl/ftl_band_ops.c @@ -341,6 +341,7 @@ ftl_band_close(struct ftl_band *band) uint64_t num_blocks = ftl_tail_md_num_blocks(dev); /* Write P2L map first, after completion, set the state to close on nvcache, then internally */ + band->md->close_seq_id = ftl_get_next_seq_id(dev); ftl_band_set_state(band, FTL_BAND_STATE_CLOSING); ftl_basic_rq_init(dev, &band->metadata_rq, metadata, num_blocks); ftl_basic_rq_set_owner(&band->metadata_rq, band_map_write_cb, band); @@ -374,6 +375,7 @@ ftl_band_free(struct ftl_band *band) memcpy(p2l_map->band_dma_md, band->md, region->entry_size * FTL_BLOCK_SIZE); p2l_map->band_dma_md->state = FTL_BAND_STATE_FREE; + p2l_map->band_dma_md->close_seq_id = 0; p2l_map->band_dma_md->p2l_map_checksum = 0; ftl_md_persist_entry(md, band->id, p2l_map->band_dma_md, NULL, diff --git a/lib/ftl/ftl_core.c b/lib/ftl/ftl_core.c index 04cd8c343..30f316b51 100644 --- a/lib/ftl/ftl_core.c +++ b/lib/ftl/ftl_core.c @@ -151,7 +151,8 @@ ftl_invalidate_addr(struct spdk_ftl_dev *dev, ftl_addr addr) /* Invalidate open/full band p2l_map entry to keep p2l and l2p * consistency when band is going to close state */ if (FTL_BAND_STATE_OPEN == band->md->state || FTL_BAND_STATE_FULL == band->md->state) { - p2l_map->band_map[ftl_band_block_offset_from_addr(band, addr)] = FTL_LBA_INVALID; + p2l_map->band_map[ftl_band_block_offset_from_addr(band, addr)].lba = FTL_LBA_INVALID; + p2l_map->band_map[ftl_band_block_offset_from_addr(band, addr)].seq_id = 0; } } diff --git a/lib/ftl/ftl_core.h b/lib/ftl/ftl_core.h index 0e670a63c..81976c975 100644 --- a/lib/ftl/ftl_core.h +++ b/lib/ftl/ftl_core.h @@ -183,6 +183,8 @@ bool ftl_needs_reloc(struct spdk_ftl_dev *dev); struct ftl_band *ftl_band_get_next_free(struct spdk_ftl_dev *dev); +void ftl_recover_max_seq(struct spdk_ftl_dev *dev); + static inline uint64_t ftl_get_num_blocks_in_band(const struct spdk_ftl_dev *dev) { @@ -250,11 +252,17 @@ ftl_addr_from_nvc_offset(const struct spdk_ftl_dev *dev, uint64_t cache_offset) return cache_offset + dev->layout.base.total_blocks; } +static inline uint64_t +ftl_get_next_seq_id(struct spdk_ftl_dev *dev) +{ + return ++dev->sb->seq_id; +} + static inline size_t ftl_p2l_map_num_blocks(const struct spdk_ftl_dev *dev) { - return spdk_divide_round_up(ftl_get_num_blocks_in_band(dev) * sizeof(uint64_t), - FTL_BLOCK_SIZE); + return spdk_divide_round_up(ftl_get_num_blocks_in_band(dev) * + sizeof(struct ftl_p2l_map_entry), FTL_BLOCK_SIZE); } static inline size_t diff --git a/lib/ftl/ftl_debug.c b/lib/ftl/ftl_debug.c index 426e24851..cbafe013b 100644 --- a/lib/ftl/ftl_debug.c +++ b/lib/ftl/ftl_debug.c @@ -59,10 +59,10 @@ ftl_band_validate_md_pin(struct ftl_band_validate_ctx *ctx) continue; } - assert(p2l_map->band_map[i] != FTL_LBA_INVALID); + assert(p2l_map->band_map[i].lba != FTL_LBA_INVALID); ctx->remaining++; ctx->pin_cnt++; - ftl_l2p_pin(dev, p2l_map->band_map[i], 1, ftl_band_validate_md_l2p_pin_cb, ctx, + ftl_l2p_pin(dev, p2l_map->band_map[i].lba, 1, ftl_band_validate_md_l2p_pin_cb, ctx, &ctx->l2p_pin_ctx[i]); } diff --git a/lib/ftl/ftl_internal.h b/lib/ftl/ftl_internal.h index d87ceba74..1130ec90b 100644 --- a/lib/ftl/ftl_internal.h +++ b/lib/ftl/ftl_internal.h @@ -52,8 +52,13 @@ enum ftl_md_status { FTL_MD_INVALID_SIZE }; +struct ftl_p2l_map_entry { + uint64_t lba; + uint64_t seq_id; +}; + /* Number of LBAs that could be stored in a single block */ -#define FTL_NUM_LBA_IN_BLOCK (FTL_BLOCK_SIZE / sizeof(uint64_t)) +#define FTL_NUM_LBA_IN_BLOCK (FTL_BLOCK_SIZE / sizeof(struct ftl_p2l_map_entry)) /* * Mapping of physical (actual location on disk) to logical (user's POV) addresses. Used in two main scenarios: @@ -75,8 +80,8 @@ struct ftl_p2l_map { /* P2L map (only valid for open/relocating bands) */ union { - uint64_t *band_map; - void *chunk_map; + struct ftl_p2l_map_entry *band_map; + void *chunk_map; }; /* DMA buffer for region's metadata entry */ diff --git a/lib/ftl/ftl_io.h b/lib/ftl/ftl_io.h index 4375de305..cf38717a3 100644 --- a/lib/ftl/ftl_io.h +++ b/lib/ftl/ftl_io.h @@ -144,6 +144,9 @@ struct ftl_rq_entry { /* Logical block address */ uint64_t lba; + /* Sequence id of original chunk where this user data was written to */ + uint64_t seq_id; + /* Index of this entry within FTL request */ const uint64_t index; diff --git a/lib/ftl/ftl_l2p.c b/lib/ftl/ftl_l2p.c index 57c3dea6c..060ecc0da 100644 --- a/lib/ftl/ftl_l2p.c +++ b/lib/ftl/ftl_l2p.c @@ -155,6 +155,10 @@ ftl_l2p_update_cache(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr new_addr, if (new_addr < current_addr) { return; } + } else { + if (new_chunk->md->seq_id < current_chunk->md->seq_id) { + return; + } } } diff --git a/lib/ftl/ftl_nv_cache.c b/lib/ftl/ftl_nv_cache.c index e0e29fa0f..0e88c6ce6 100644 --- a/lib/ftl/ftl_nv_cache.c +++ b/lib/ftl/ftl_nv_cache.c @@ -307,12 +307,14 @@ ftl_nv_cache_get_wr_buffer(struct ftl_nv_cache *nv_cache, struct ftl_io *io) void ftl_nv_cache_fill_md(struct ftl_io *io) { + struct ftl_nv_cache_chunk *chunk = io->nv_cache_chunk; uint64_t i; union ftl_md_vss *metadata = io->md; uint64_t lba = ftl_io_get_lba(io, 0); for (i = 0; i < io->num_blocks; ++i, lba++, metadata++) { metadata->nv_cache.lba = lba; + metadata->nv_cache.seq_id = chunk->md->seq_id; } } @@ -433,6 +435,7 @@ chunk_free_cb(int status, void *ctx) nv_cache->chunk_free_count++; nv_cache->chunk_full_count--; chunk->md->state = FTL_CHUNK_STATE_FREE; + chunk->md->close_seq_id = 0; ftl_chunk_free_chunk_free_entry(chunk); } else { ftl_md_persist_entry_retry(&chunk->md_persist_entry_ctx); @@ -460,6 +463,7 @@ ftl_chunk_persist_free_state(struct ftl_nv_cache *nv_cache) memcpy(p2l_map->chunk_dma_md, chunk->md, region->entry_size * FTL_BLOCK_SIZE); p2l_map->chunk_dma_md->state = FTL_CHUNK_STATE_FREE; + p2l_map->chunk_dma_md->close_seq_id = 0; p2l_map->chunk_dma_md->p2l_map_checksum = 0; ftl_md_persist_entry(md, get_chunk_idx(chunk), p2l_map->chunk_dma_md, NULL, @@ -539,6 +543,7 @@ static void compaction_process_pin_lba(struct ftl_nv_cache_compactor *comp) { union ftl_md_vss *md; + struct ftl_nv_cache_chunk *chunk = comp->rd->owner.priv; struct spdk_ftl_dev *dev = comp->rd->dev; uint64_t i; uint32_t count = comp->rd->iter.count; @@ -553,7 +558,7 @@ compaction_process_pin_lba(struct ftl_nv_cache_compactor *comp) entry = &comp->rd->entries[i]; pin_ctx = &entry->l2p_pin_ctx; md = entry->io_md; - if (md->nv_cache.lba == FTL_LBA_INVALID) { + if (md->nv_cache.lba == FTL_LBA_INVALID || md->nv_cache.seq_id != chunk->md->seq_id) { ftl_l2p_pin_skip(dev, compaction_process_pin_lba_cb, comp, pin_ctx); } else { ftl_l2p_pin(dev, md->nv_cache.lba, 1, compaction_process_pin_lba_cb, comp, pin_ctx); @@ -697,6 +702,7 @@ compaction_process_pad(struct ftl_nv_cache_compactor *compactor) iter->addr = FTL_ADDR_INVALID; iter->owner.priv = NULL; iter->lba = FTL_LBA_INVALID; + iter->seq_id = 0; iter++; wr->iter.idx++; } @@ -858,7 +864,7 @@ compaction_process_finish_read(struct ftl_nv_cache_compactor *compactor) while (wr->iter.idx < num_entries && rd->iter.idx < rd->iter.count) { /* Get metadata */ md = rd->entries[rd->iter.idx].io_md; - if (md->nv_cache.lba == FTL_LBA_INVALID) { + if (md->nv_cache.lba == FTL_LBA_INVALID || md->nv_cache.seq_id != chunk->md->seq_id) { cache_addr++; rd->iter.idx++; chunk_compaction_advance(chunk, 1); @@ -878,6 +884,7 @@ compaction_process_finish_read(struct ftl_nv_cache_compactor *compactor) iter->addr = current_addr; iter->owner.priv = chunk; iter->lba = md->nv_cache.lba; + iter->seq_id = chunk->md->seq_id; /* Advance within batch */ iter++; @@ -1214,6 +1221,7 @@ ftl_nv_cache_process(struct spdk_ftl_dev *dev) TAILQ_REMOVE(&nv_cache->chunk_free_list, chunk, entry); TAILQ_INSERT_TAIL(&nv_cache->chunk_open_list, chunk, entry); nv_cache->chunk_free_count--; + chunk->md->seq_id = ftl_get_next_seq_id(dev); ftl_chunk_open(chunk); } @@ -1316,6 +1324,52 @@ ftl_nv_cache_save_state(struct ftl_nv_cache *nv_cache) return status; } +static int +sort_chunks_cmp(const void *a, const void *b) +{ + struct ftl_nv_cache_chunk *a_chunk = *(struct ftl_nv_cache_chunk **)a; + struct ftl_nv_cache_chunk *b_chunk = *(struct ftl_nv_cache_chunk **)b; + + return a_chunk->md->seq_id - b_chunk->md->seq_id; +} + +static int +sort_chunks(struct ftl_nv_cache *nv_cache) +{ + struct ftl_nv_cache_chunk **chunks_list; + struct ftl_nv_cache_chunk *chunk; + uint32_t i; + + if (TAILQ_EMPTY(&nv_cache->chunk_full_list)) { + return 0; + } + + chunks_list = calloc(nv_cache->chunk_full_count, + sizeof(chunks_list[0])); + if (!chunks_list) { + return -ENOMEM; + } + + i = 0; + TAILQ_FOREACH(chunk, &nv_cache->chunk_full_list, entry) { + chunks_list[i] = chunk; + i++; + } + assert(i == nv_cache->chunk_full_count); + + qsort(chunks_list, nv_cache->chunk_full_count, sizeof(chunks_list[0]), + sort_chunks_cmp); + + TAILQ_INIT(&nv_cache->chunk_full_list); + for (i = 0; i < nv_cache->chunk_full_count; i++) { + chunk = chunks_list[i]; + TAILQ_INSERT_TAIL(&nv_cache->chunk_full_list, chunk, entry); + } + + free(chunks_list); + return 0; +} + static int chunk_alloc_p2l_map(struct ftl_nv_cache_chunk *chunk) { @@ -1398,6 +1452,11 @@ ftl_nv_cache_load_state(struct ftl_nv_cache *nv_cache) goto error; } + status = sort_chunks(nv_cache); + if (status) { + FTL_ERRLOG(dev, "FTL NV Cache: sorting chunks ERROR\n"); + } + FTL_NOTICELOG(dev, "FTL NV Cache: full chunks = %lu, empty chunks = %lu\n", nv_cache->chunk_full_count, nv_cache->chunk_free_count); @@ -1411,6 +1470,26 @@ error: return status; } +void +ftl_nv_cache_get_max_seq_id(struct ftl_nv_cache *nv_cache, uint64_t *open_seq_id, + uint64_t *close_seq_id) +{ + uint64_t i, o_seq_id = 0, c_seq_id = 0; + struct ftl_nv_cache_chunk *chunk; + + chunk = nv_cache->chunks; + assert(chunk); + + /* Iterate over chunks and get their max open and close seq id */ + for (i = 0; i < nv_cache->chunk_count; i++, chunk++) { + o_seq_id = spdk_max(o_seq_id, chunk->md->seq_id); + c_seq_id = spdk_max(c_seq_id, chunk->md->close_seq_id); + } + + *open_seq_id = o_seq_id; + *close_seq_id = c_seq_id; +} + typedef void (*ftl_chunk_ops_cb)(struct ftl_nv_cache_chunk *chunk, void *cntx, bool status); static void @@ -1530,6 +1609,8 @@ chunk_close_cb(int status, void *ctx) TAILQ_INSERT_TAIL(&chunk->nv_cache->chunk_full_list, chunk, entry); chunk->nv_cache->chunk_full_count++; + chunk->nv_cache->last_seq_id = chunk->md->close_seq_id; + chunk->md->state = FTL_CHUNK_STATE_CLOSED; } else { ftl_md_persist_entry_retry(&chunk->md_persist_entry_ctx); @@ -1569,6 +1650,7 @@ ftl_chunk_close(struct ftl_nv_cache_chunk *chunk) struct ftl_basic_rq *brq = &chunk->metadata_rq; void *metadata = chunk->p2l_map.chunk_map; + chunk->md->close_seq_id = ftl_get_next_seq_id(dev); ftl_basic_rq_init(dev, brq, metadata, chunk->nv_cache->tail_md_chunk_blocks); ftl_basic_rq_set_owner(brq, chunk_map_write_cb, chunk); diff --git a/lib/ftl/ftl_nv_cache.h b/lib/ftl/ftl_nv_cache.h index 91e6a6a01..cd99cecc0 100644 --- a/lib/ftl/ftl_nv_cache.h +++ b/lib/ftl/ftl_nv_cache.h @@ -39,6 +39,12 @@ enum ftl_chunk_state { }; struct ftl_nv_cache_chunk_md { + /* Sequence id of writing */ + uint64_t seq_id; + + /* Sequence ID when chunk was closed */ + uint64_t close_seq_id; + /* Current lba to write */ uint32_t write_pointer; @@ -161,6 +167,8 @@ struct ftl_nv_cache { uint64_t chunk_compaction_threshold; struct ftl_nv_cache_chunk *chunks; + + uint64_t last_seq_id; }; int ftl_nv_cache_init(struct spdk_ftl_dev *dev); @@ -197,6 +205,15 @@ bool ftl_nv_cache_is_halted(struct ftl_nv_cache *nv_cache); size_t ftl_nv_cache_chunk_tail_md_num_blocks(const struct ftl_nv_cache *nv_cache); uint64_t chunk_tail_md_offset(struct ftl_nv_cache *nv_cache); +/** + * @brief Iterates over NV caches chunks and returns the max open and closed sequence id + * + * @param nv_cache FLT NV cache + * @param[out] open_seq_id Max detected open sequence id + * @param[out] close_seq_id Max detected close sequence id + */ +void ftl_nv_cache_get_max_seq_id(struct ftl_nv_cache *nv_cache, uint64_t *open_seq_id, + uint64_t *close_seq_id); typedef int (*ftl_chunk_md_cb)(struct ftl_nv_cache_chunk *chunk, void *cntx); diff --git a/lib/ftl/ftl_reloc.c b/lib/ftl/ftl_reloc.c index a2381639a..334d4935d 100644 --- a/lib/ftl/ftl_reloc.c +++ b/lib/ftl/ftl_reloc.c @@ -294,9 +294,10 @@ move_advance_rq(struct ftl_rq *rq) assert(offset < ftl_get_num_blocks_in_band(band->dev)); assert(ftl_band_block_offset_valid(band, offset)); - entry->lba = band->p2l_map.band_map[offset]; + entry->lba = band->p2l_map.band_map[offset].lba; entry->addr = rq->io.addr; entry->owner.priv = band; + entry->seq_id = band->p2l_map.band_map[offset].seq_id; entry++; rq->io.addr = ftl_band_next_addr(band, rq->io.addr, 1); @@ -323,6 +324,7 @@ move_init_entries(struct ftl_rq *rq, uint64_t idx, uint64_t count) iter->addr = FTL_ADDR_INVALID; iter->owner.priv = NULL; iter->lba = FTL_LBA_INVALID; + iter->seq_id = 0; iter++; i++; } @@ -360,6 +362,7 @@ move_rq_pad(struct ftl_rq *rq, struct ftl_band *band) entry->addr = rq->io.addr; entry->owner.priv = band; entry->lba = FTL_LBA_INVALID; + entry->seq_id = 0; entry++; rq->io.addr = ftl_band_next_addr(band, rq->io.addr, 1); band->owner.cnt++; diff --git a/lib/ftl/ftl_rq.c b/lib/ftl/ftl_rq.c index bc1ead29e..ddc8790fd 100644 --- a/lib/ftl/ftl_rq.c +++ b/lib/ftl/ftl_rq.c @@ -62,6 +62,7 @@ ftl_rq_new(struct spdk_ftl_dev *dev, uint32_t io_md_size) entry->addr = FTL_ADDR_INVALID; entry->lba = FTL_LBA_INVALID; entry->io_payload = io_payload; + entry->seq_id = 0; if (io_md_size) { entry->io_md = io_md; diff --git a/lib/ftl/ftl_sb_common.h b/lib/ftl/ftl_sb_common.h index 82b085520..41e5fa624 100644 --- a/lib/ftl/ftl_sb_common.h +++ b/lib/ftl/ftl_sb_common.h @@ -59,6 +59,7 @@ struct ftl_superblock_shm { bool in_progress; uint64_t start_lba; uint64_t num_blocks; + uint64_t seq_id; } trim; struct ftl_superblock_gc_info gc_info; diff --git a/lib/ftl/ftl_sb_current.h b/lib/ftl/ftl_sb_current.h index 5b745c543..2905c7c7e 100644 --- a/lib/ftl/ftl_sb_current.h +++ b/lib/ftl/ftl_sb_current.h @@ -17,6 +17,9 @@ struct ftl_superblock { struct spdk_uuid uuid; + /* Current sequence number */ + uint64_t seq_id; + /* Flag describing clean shutdown */ uint64_t clean; @@ -29,9 +32,11 @@ struct ftl_superblock { /* Maximum IO depth per band relocate */ uint64_t max_reloc_qdepth; - /* Reserved field */ + /* Reserved fields */ uint64_t reserved; + bool reserved3; + uint32_t reserved2; struct ftl_superblock_gc_info gc_info; diff --git a/lib/ftl/ftl_writer.c b/lib/ftl/ftl_writer.c index 831768ac2..a46953157 100644 --- a/lib/ftl/ftl_writer.c +++ b/lib/ftl/ftl_writer.c @@ -47,6 +47,7 @@ ftl_writer_band_state_change(struct ftl_band *band) assert(writer->num_bands > 0); writer->num_bands--; ftl_band_clear_owner(band, ftl_writer_band_state_change, writer); + writer->last_seq_id = band->md->close_seq_id; break; default: diff --git a/lib/ftl/ftl_writer.h b/lib/ftl/ftl_writer.h index fe6f11e71..79fa1224c 100644 --- a/lib/ftl/ftl_writer.h +++ b/lib/ftl/ftl_writer.h @@ -36,6 +36,8 @@ struct ftl_writer { /* Which type of band the writer uses */ enum ftl_band_type writer_type; + + uint64_t last_seq_id; }; bool ftl_writer_is_halted(struct ftl_writer *writer); diff --git a/lib/ftl/mngt/ftl_mngt_band.c b/lib/ftl/mngt/ftl_mngt_band.c index daaa67df5..016a30cd7 100644 --- a/lib/ftl/mngt/ftl_mngt_band.c +++ b/lib/ftl/mngt/ftl_mngt_band.c @@ -199,6 +199,44 @@ ftl_mngt_decorate_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) ftl_mngt_next_step(mngt); } +void +ftl_recover_max_seq(struct spdk_ftl_dev *dev) +{ + struct ftl_band *band; + size_t band_close_seq_id = 0, band_open_seq_id = 0; + size_t chunk_close_seq_id = 0, chunk_open_seq_id = 0; + size_t max = 0; + + TAILQ_FOREACH(band, &dev->shut_bands, queue_entry) { + band_open_seq_id = spdk_max(band_open_seq_id, band->md->seq); + band_close_seq_id = spdk_max(band_close_seq_id, band->md->close_seq_id); + } + ftl_nv_cache_get_max_seq_id(&dev->nv_cache, &chunk_open_seq_id, &chunk_close_seq_id); + + + dev->nv_cache.last_seq_id = chunk_close_seq_id; + dev->writer_gc.last_seq_id = band_close_seq_id; + dev->writer_user.last_seq_id = band_close_seq_id; + + max = spdk_max(max, band_open_seq_id); + max = spdk_max(max, band_close_seq_id); + max = spdk_max(max, chunk_open_seq_id); + max = spdk_max(max, chunk_close_seq_id); + + dev->sb->seq_id = max; +} + +static int +_band_cmp(const void *_a, const void *_b) +{ + struct ftl_band *a, *b; + + a = *((struct ftl_band **)_a); + b = *((struct ftl_band **)_b); + + return a->md->seq - b->md->seq; +} + static struct ftl_band * next_high_prio_band(struct spdk_ftl_dev *dev) { @@ -267,6 +305,8 @@ ftl_mngt_finalize_init_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process * uint64_t offset; bool fast_startup = ftl_fast_startup(dev); + ftl_recover_max_seq(dev); + TAILQ_FOREACH_SAFE(band, &dev->free_bands, queue_entry, temp_band) { band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID; } @@ -293,6 +333,8 @@ ftl_mngt_finalize_init_bands(struct spdk_ftl_dev *dev, struct ftl_mngt_process * } /* Assign open bands to writers and alloc necessary resources */ + qsort(open_bands, num_open, sizeof(open_bands[0]), _band_cmp); + for (i = 0; i < num_open; ++i) { band = open_bands[i]; diff --git a/lib/ftl/mngt/ftl_mngt_misc.c b/lib/ftl/mngt/ftl_mngt_misc.c index 9dcb52a08..3fb9abd55 100644 --- a/lib/ftl/mngt/ftl_mngt_misc.c +++ b/lib/ftl/mngt/ftl_mngt_misc.c @@ -162,7 +162,8 @@ ftl_mngt_scrub_nv_cache(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) FTL_NOTICELOG(dev, "Scrubbing %lluGiB\n", region->current.blocks * FTL_BLOCK_SIZE / GiB); /* Need to scrub user data, so in case of dirty shutdown the recovery won't - * pull in data during open chunks recovery from any previous instance + * pull in data during open chunks recovery from any previous instance (since during short + * tests it's very likely that chunks seq_id will be in line between new head md and old VSS) */ md->cb = user_clear_cb; md->owner.cb_ctx = mngt; diff --git a/lib/ftl/utils/ftl_md.h b/lib/ftl/utils/ftl_md.h index 47f151d0e..f529f134f 100644 --- a/lib/ftl/utils/ftl_md.h +++ b/lib/ftl/utils/ftl_md.h @@ -119,10 +119,12 @@ union ftl_md_vss { struct { uint64_t start_lba; uint64_t num_blocks; + uint64_t seq_id; } unmap; struct { uint64_t lba; + uint64_t seq_id; } nv_cache; }; diff --git a/test/unit/lib/ftl/ftl_band.c/ftl_band_ut.c b/test/unit/lib/ftl/ftl_band.c/ftl_band_ut.c index dd0d63c1d..9af6973f8 100644 --- a/test/unit/lib/ftl/ftl_band.c/ftl_band_ut.c +++ b/test/unit/lib/ftl/ftl_band.c/ftl_band_ut.c @@ -256,14 +256,14 @@ test_band_set_addr(void) ftl_band_set_addr(g_band, TEST_LBA, addr); CU_ASSERT_EQUAL(p2l_map->num_valid, 1); - CU_ASSERT_EQUAL(p2l_map->band_map[offset], TEST_LBA); + CU_ASSERT_EQUAL(p2l_map->band_map[offset].lba, TEST_LBA); CU_ASSERT_TRUE(ftl_bitmap_get(p2l_map->valid, offset)); addr += g_geo.zone_size / 2; offset = test_offset_from_addr(addr, g_band); ftl_band_set_addr(g_band, TEST_LBA + 1, addr); CU_ASSERT_EQUAL(p2l_map->num_valid, 2); - CU_ASSERT_EQUAL(p2l_map->band_map[offset], TEST_LBA + 1); + CU_ASSERT_EQUAL(p2l_map->band_map[offset].lba, TEST_LBA + 1); CU_ASSERT_TRUE(ftl_bitmap_get(p2l_map->valid, offset)); addr -= g_geo.zone_size / 2; offset = test_offset_from_addr(addr, g_band);