diff --git a/lib/ftl/Makefile b/lib/ftl/Makefile index 2bd8cc0ef..99b94ba10 100644 --- a/lib/ftl/Makefile +++ b/lib/ftl/Makefile @@ -29,7 +29,7 @@ C_SRCS = ftl_core.c ftl_init.c ftl_layout.c ftl_debug.c ftl_io.c ftl_sb.c ftl_l2 C_SRCS += ftl_nv_cache.c ftl_band.c ftl_band_ops.c ftl_writer.c ftl_rq.c ftl_reloc.c ftl_l2p_cache.c C_SRCS += mngt/ftl_mngt.c mngt/ftl_mngt_bdev.c mngt/ftl_mngt_shutdown.c mngt/ftl_mngt_startup.c C_SRCS += mngt/ftl_mngt_md.c mngt/ftl_mngt_misc.c mngt/ftl_mngt_ioch.c mngt/ftl_mngt_l2p.c -C_SRCS += mngt/ftl_mngt_band.c +C_SRCS += mngt/ftl_mngt_band.c mngt/ftl_mngt_self_test.c C_SRCS += utils/ftl_conf.c utils/ftl_md.c utils/ftl_mempool.c utils/ftl_bitmap.c SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_ftl.map) diff --git a/lib/ftl/mngt/ftl_mngt_self_test.c b/lib/ftl/mngt/ftl_mngt_self_test.c new file mode 100644 index 000000000..b9452e5bf --- /dev/null +++ b/lib/ftl/mngt/ftl_mngt_self_test.c @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) Intel Corporation. + * All rights reserved. + */ + +#include "ftl_mngt.h" +#include "ftl_mngt_steps.h" +#include "ftl_internal.h" +#include "ftl_core.h" +#include "ftl_band.h" + +struct ftl_validate_ctx { + struct { + struct ftl_bitmap *bitmap; + void *buffer; + uint64_t buffer_size; + uint64_t bit_count; + uint64_t base_valid_count; + uint64_t cache_valid_count; + } valid_map; + + int status; +}; + +static void +ftl_mngt_test_prepare(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) +{ + struct ftl_validate_ctx *cntx = ftl_mngt_get_process_ctx(mngt); + + cntx->valid_map.bit_count = dev->layout.base.total_blocks + + dev->layout.nvc.total_blocks; + cntx->valid_map.buffer_size = spdk_divide_round_up(cntx->valid_map.bit_count, 8); + cntx->valid_map.buffer_size = SPDK_ALIGN_CEIL(cntx->valid_map.buffer_size, + ftl_bitmap_buffer_alignment); + + cntx->valid_map.buffer = calloc(cntx->valid_map.buffer_size, 1); + if (!cntx->valid_map.buffer) { + ftl_mngt_fail_step(mngt); + return; + } + + cntx->valid_map.bitmap = ftl_bitmap_create(cntx->valid_map.buffer, + cntx->valid_map.buffer_size); + if (!cntx->valid_map.bitmap) { + ftl_mngt_fail_step(mngt); + return; + } + + ftl_mngt_next_step(mngt); +} + +static void +ftl_mngt_test_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) +{ + struct ftl_validate_ctx *cntx = ftl_mngt_get_process_ctx(mngt); + + ftl_bitmap_destroy(cntx->valid_map.bitmap); + cntx->valid_map.bitmap = NULL; + + free(cntx->valid_map.buffer); + cntx->valid_map.buffer = NULL; + + ftl_mngt_next_step(mngt); +} + +static void +test_valid_map_pin_cb(struct spdk_ftl_dev *dev, int status, + struct ftl_l2p_pin_ctx *pin_ctx) +{ + struct ftl_mngt_process *mngt = pin_ctx->cb_ctx; + struct ftl_validate_ctx *ctx = ftl_mngt_get_process_ctx(mngt); + uint64_t lba, end; + + if (status) { + FTL_ERRLOG(dev, "L2P pin ERROR when testing valid map\n"); + ftl_mngt_fail_step(mngt); + return; + } + + lba = pin_ctx->lba; + end = pin_ctx->lba + pin_ctx->count; + + for (; lba < end; ++lba) { + ftl_addr addr = ftl_l2p_get(dev, lba); + bool valid; + + if (FTL_ADDR_INVALID == addr) { + continue; + } + + if (ftl_bitmap_get(ctx->valid_map.bitmap, addr)) { + status = -EINVAL; + FTL_ERRLOG(dev, "L2P mapping ERROR, double reference, " + "address 0x%.16"PRIX64"\n", addr); + break; + } else { + ftl_bitmap_set(ctx->valid_map.bitmap, addr); + } + + if (ftl_addr_in_nvc(dev, addr)) { + ctx->valid_map.cache_valid_count++; + } else { + ctx->valid_map.base_valid_count++; + } + + valid = ftl_bitmap_get(dev->valid_map, addr); + if (!valid) { + status = -EINVAL; + FTL_ERRLOG(dev, "L2P and valid map mismatch" + ", LBA 0x%.16"PRIX64 + ", address 0x%.16"PRIX64" unset\n", + lba, addr); + break; + } + } + + ftl_l2p_unpin(dev, pin_ctx->lba, pin_ctx->count); + pin_ctx->lba += pin_ctx->count; + + if (!status) { + ftl_mngt_continue_step(mngt); + } else { + ftl_mngt_fail_step(mngt); + } +} + +static void +ftl_mngt_test_valid_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) +{ + struct ftl_l2p_pin_ctx *pin_ctx; + struct ftl_validate_ctx *ctx = ftl_mngt_get_process_ctx(mngt); + uint64_t left; + + pin_ctx = ftl_mngt_get_step_ctx(mngt); + if (!pin_ctx) { + if (ftl_mngt_alloc_step_ctx(mngt, sizeof(*pin_ctx))) { + ftl_mngt_fail_step(mngt); + return; + } + pin_ctx = ftl_mngt_get_step_ctx(mngt); + assert(pin_ctx); + + pin_ctx->lba = 0; + memset(ctx->valid_map.buffer, 0, ctx->valid_map.buffer_size); + } + + left = dev->num_lbas - pin_ctx->lba; + pin_ctx->count = spdk_min(left, 4096); + + if (pin_ctx->count) { + ftl_l2p_pin(dev, pin_ctx->lba, pin_ctx->count, + test_valid_map_pin_cb, mngt, pin_ctx); + } else { + if (!ctx->status) { + uint64_t valid = ctx->valid_map.base_valid_count + + ctx->valid_map.cache_valid_count; + + if (ftl_bitmap_count_set(dev->valid_map) != valid) { + ctx->status = -EINVAL; + } + } + + /* All done */ + if (ctx->status) { + ftl_mngt_fail_step(mngt); + } else { + ftl_mngt_next_step(mngt); + } + } +} + +/* + * Verifies the contents of L2P versus valid map. Makes sure any physical addresses in the L2P + * have their corresponding valid bits set and that two different logical addresses don't point + * to the same physical address. + * + * For debugging purposes only, directed via environment variable - whole L2P needs to be loaded in + * and checked. + */ +static const struct ftl_mngt_process_desc desc_self_test = { + .name = "[Test] Startup Test", + .ctx_size = sizeof(struct ftl_validate_ctx), + .steps = { + { + .name = "[TEST] Initialize selftest", + + .action = ftl_mngt_test_prepare, + .cleanup = ftl_mngt_test_cleanup + }, + { + .name = "[TEST] Validate map and L2P consistency", + .action = ftl_mngt_test_valid_map + }, + { + .name = "[TEST] Deinitialize cleanup", + .action = ftl_mngt_test_cleanup + }, + {} + } +}; + +void +ftl_mngt_self_test(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) +{ + if (getenv("FTL_SELF_TEST")) { + ftl_mngt_call_process(mngt, &desc_self_test); + } else { + FTL_NOTICELOG(dev, "Self test skipped\n"); + ftl_mngt_next_step(mngt); + } +} diff --git a/lib/ftl/mngt/ftl_mngt_steps.h b/lib/ftl/mngt/ftl_mngt_steps.h index ae7c008e0..f49011abe 100644 --- a/lib/ftl/mngt/ftl_mngt_steps.h +++ b/lib/ftl/mngt/ftl_mngt_steps.h @@ -110,6 +110,8 @@ void ftl_mngt_init_vld_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mn void ftl_mngt_deinit_vld_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); +void ftl_mngt_self_test(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); + void ftl_mngt_persist_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt); void ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);