Spdk/lib/ftl/mngt/ftl_mngt_self_test.c

212 lines
5.0 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (C) 2022 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);
}
}