From 4a24a7b3e06a7292936c74488c8144b6b3229780 Mon Sep 17 00:00:00 2001 From: Kozlowski Mateusz Date: Mon, 13 Jun 2022 11:07:48 +0200 Subject: [PATCH] FTL: Add helper L2P set/get functions for nv_cache Signed-off-by: Kozlowski Mateusz Signed-off-by: Artur Paszkiewicz Change-Id: I61ed4434283c21d7dc62b70898f920e66b595a4f Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13321 Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins Reviewed-by: Jim Harris Reviewed-by: Ben Walker --- lib/ftl/ftl_core.h | 3 -- lib/ftl/ftl_l2p.c | 69 +++++++++++++++++++++++++++++++++--------- lib/ftl/ftl_nv_cache.c | 56 ++++++++++++++++++++++++++++++++++ lib/ftl/ftl_nv_cache.h | 9 ++++++ 4 files changed, 120 insertions(+), 17 deletions(-) diff --git a/lib/ftl/ftl_core.h b/lib/ftl/ftl_core.h index 5b5526d46..df576555c 100644 --- a/lib/ftl/ftl_core.h +++ b/lib/ftl/ftl_core.h @@ -83,9 +83,6 @@ struct spdk_ftl_dev { /* Logical -> physical table */ void *l2p; - /* l2p deferred pins list */ - TAILQ_HEAD(, ftl_l2p_pin_ctx) l2p_deferred_pins; - /* Size of the l2p table */ uint64_t num_lbas; diff --git a/lib/ftl/ftl_l2p.c b/lib/ftl/ftl_l2p.c index 315c473f2..e221845e6 100644 --- a/lib/ftl/ftl_l2p.c +++ b/lib/ftl/ftl_l2p.c @@ -16,7 +16,6 @@ int ftl_l2p_init(struct spdk_ftl_dev *dev) { - TAILQ_INIT(&dev->l2p_deferred_pins); return FTL_L2P_OP(init)(dev); } @@ -79,24 +78,12 @@ ftl_l2p_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx) void ftl_l2p_process(struct spdk_ftl_dev *dev) { - struct ftl_l2p_pin_ctx *pin_ctx; - - pin_ctx = TAILQ_FIRST(&dev->l2p_deferred_pins); - if (pin_ctx) { - TAILQ_REMOVE(&dev->l2p_deferred_pins, pin_ctx, link); - FTL_L2P_OP(pin)(dev, pin_ctx); - } - FTL_L2P_OP(process)(dev); } bool ftl_l2p_is_halted(struct spdk_ftl_dev *dev) { - if (!TAILQ_EMPTY(&dev->l2p_deferred_pins)) { - return false; - } - return FTL_L2P_OP(is_halted)(dev); } @@ -106,6 +93,59 @@ ftl_l2p_halt(struct spdk_ftl_dev *dev) return FTL_L2P_OP(halt)(dev); } +void +ftl_l2p_update_cache(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr new_addr, ftl_addr old_addr) +{ + struct ftl_nv_cache_chunk *current_chunk, *new_chunk; + ftl_addr current_addr; + /* Updating L2P for data in cache device - used by user writes. + * Split off from updating L2P in base due to extra edge cases for handling dirty shutdown in the cache case, + * namely keeping two simultaneous writes to same LBA consistent before/after shutdown - on base device we + * can simply ignore the L2P update, here we need to keep the address with more advanced write pointer + */ + assert(ftl_check_core_thread(dev)); + assert(new_addr != FTL_ADDR_INVALID); + assert(ftl_addr_in_nvc(dev, new_addr)); + + current_addr = ftl_l2p_get(dev, lba); + + if (current_addr != FTL_ADDR_INVALID) { + + /* Check if write-after-write happened (two simultaneous user writes to the same LBA) */ + if (spdk_unlikely(current_addr != old_addr + && ftl_addr_in_nvc(dev, current_addr))) { + + current_chunk = ftl_nv_cache_get_chunk_from_addr(dev, current_addr); + new_chunk = ftl_nv_cache_get_chunk_from_addr(dev, new_addr); + + /* To keep data consistency after recovery skip oldest block */ + /* If both user writes are to the same chunk, the highest address should 'win', to keep data after + * dirty shutdown recovery consistent. If they're on different chunks, then higher seq_id chunk 'wins' */ + if (current_chunk == new_chunk) { + if (new_addr < current_addr) { + return; + } + } + } + + /* For recovery from SHM case valid maps need to be set before l2p set and + * invalidated after it */ + + /* DO NOT CHANGE ORDER - START */ + ftl_nv_cache_set_addr(dev, lba, new_addr); + ftl_l2p_set(dev, lba, new_addr); + ftl_invalidate_addr(dev, current_addr); + /* DO NOT CHANGE ORDER - END */ + return; + } + + /* If current address doesn't have any value (ie. it was never set, or it was trimmed), then we can just set L2P */ + /* DO NOT CHANGE ORDER - START (need to set P2L maps/valid map first) */ + ftl_nv_cache_set_addr(dev, lba, new_addr); + ftl_l2p_set(dev, lba, new_addr); + /* DO NOT CHANGE ORDER - END */ +} + void ftl_l2p_update_base(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr new_addr, ftl_addr old_addr) { @@ -142,7 +182,8 @@ void ftl_l2p_pin_complete(struct spdk_ftl_dev *dev, int status, struct ftl_l2p_pin_ctx *pin_ctx) { if (spdk_unlikely(status == -EAGAIN)) { - TAILQ_INSERT_TAIL(&dev->l2p_deferred_pins, pin_ctx, link); + /* Path updated in later patch */ + assert(false); } else { pin_ctx->cb(dev, status, pin_ctx); } diff --git a/lib/ftl/ftl_nv_cache.c b/lib/ftl/ftl_nv_cache.c index 51da8eea1..b352ad258 100644 --- a/lib/ftl/ftl_nv_cache.c +++ b/lib/ftl/ftl_nv_cache.c @@ -283,6 +283,62 @@ ftl_nv_cache_is_halted(struct ftl_nv_cache *nv_cache) return true; } +void +ftl_chunk_map_set_lba(struct ftl_nv_cache_chunk *chunk, + uint64_t offset, uint64_t lba) +{ + struct spdk_ftl_dev *dev = SPDK_CONTAINEROF(chunk->nv_cache, struct spdk_ftl_dev, nv_cache); + struct ftl_p2l_map *p2l_map = &chunk->p2l_map; + + ftl_lba_store(dev, p2l_map->chunk_map, offset, lba); +} + +uint64_t +ftl_chunk_map_get_lba(struct ftl_nv_cache_chunk *chunk, uint64_t offset) +{ + struct spdk_ftl_dev *dev = SPDK_CONTAINEROF(chunk->nv_cache, struct spdk_ftl_dev, nv_cache); + struct ftl_p2l_map *p2l_map = &chunk->p2l_map; + + return ftl_lba_load(dev, p2l_map->chunk_map, offset); +} + +static void +ftl_chunk_set_addr(struct ftl_nv_cache_chunk *chunk, uint64_t lba, ftl_addr addr) +{ + struct spdk_ftl_dev *dev = SPDK_CONTAINEROF(chunk->nv_cache, struct spdk_ftl_dev, nv_cache); + uint64_t cache_offset = ftl_addr_to_nvc_offset(dev, addr); + uint64_t offset; + + offset = (cache_offset - chunk->offset) % chunk->nv_cache->chunk_blocks; + ftl_chunk_map_set_lba(chunk, offset, lba); +} + +struct ftl_nv_cache_chunk * +ftl_nv_cache_get_chunk_from_addr(struct spdk_ftl_dev *dev, ftl_addr addr) +{ + struct ftl_nv_cache_chunk *chunk = dev->nv_cache.chunks; + uint64_t chunk_idx; + uint64_t cache_offset = ftl_addr_to_nvc_offset(dev, addr); + + assert(chunk != NULL); + chunk_idx = (cache_offset - chunk->offset) / chunk->nv_cache->chunk_blocks; + chunk += chunk_idx; + + return chunk; +} + +void +ftl_nv_cache_set_addr(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr addr) +{ + struct ftl_nv_cache_chunk *chunk; + + chunk = ftl_nv_cache_get_chunk_from_addr(dev, addr); + + assert(lba != FTL_LBA_INVALID); + + ftl_chunk_set_addr(chunk, lba, addr); +} + static void ftl_chunk_open(struct ftl_nv_cache_chunk *chunk); void diff --git a/lib/ftl/ftl_nv_cache.h b/lib/ftl/ftl_nv_cache.h index dd082130b..5ee941067 100644 --- a/lib/ftl/ftl_nv_cache.h +++ b/lib/ftl/ftl_nv_cache.h @@ -137,6 +137,12 @@ int ftl_nv_cache_read(struct ftl_io *io, ftl_addr addr, uint32_t num_blocks, bool ftl_nv_cache_full(struct ftl_nv_cache *nv_cache); void ftl_nv_cache_process(struct spdk_ftl_dev *dev); +void ftl_chunk_map_set_lba(struct ftl_nv_cache_chunk *chunk, + uint64_t offset, uint64_t lba); +uint64_t ftl_chunk_map_get_lba(struct ftl_nv_cache_chunk *chunk, uint64_t offset); + +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); void ftl_nv_cache_halt(struct ftl_nv_cache *nv_cache); @@ -157,4 +163,7 @@ uint64_t chunk_tail_md_offset(struct ftl_nv_cache *nv_cache); typedef int (*ftl_chunk_md_cb)(struct ftl_nv_cache_chunk *chunk, void *cntx); +struct ftl_nv_cache_chunk *ftl_nv_cache_get_chunk_from_addr(struct spdk_ftl_dev *dev, + ftl_addr addr); + #endif /* FTL_NV_CACHE_H */