From c8ab874d7c2be6199c15dd17686c0c1c394ddd39 Mon Sep 17 00:00:00 2001 From: Kozlowski Mateusz Date: Wed, 25 May 2022 12:13:38 +0200 Subject: [PATCH] ftl: Add upgrade of superblock from version 2 to version 3 Layout of metadata will be part of the superblock at the end of the upgrade. Signed-off-by: Kozlowski Mateusz Signed-off-by: Artur Paszkiewicz Change-Id: If888866806e948ee07f0777612da73ab8b7548b1 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13385 Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins Reviewed-by: Jim Harris Reviewed-by: Ben Walker --- lib/ftl/Makefile | 2 +- lib/ftl/ftl_layout.c | 8 +- lib/ftl/ftl_sb.c | 20 +- lib/ftl/ftl_sb_current.h | 4 +- lib/ftl/mngt/ftl_mngt_md.c | 14 +- lib/ftl/upgrade/ftl_layout_upgrade.c | 11 +- lib/ftl/upgrade/ftl_sb_prev.h | 68 ++++ lib/ftl/upgrade/ftl_sb_upgrade.c | 19 ++ lib/ftl/upgrade/ftl_sb_upgrade.h | 23 ++ test/unit/lib/ftl/Makefile | 2 +- .../lib/ftl/ftl_layout_upgrade/.gitignore | 1 + test/unit/lib/ftl/ftl_layout_upgrade/Makefile | 12 + .../ftl_layout_upgrade_ut.c | 303 ++++++++++++++++ test/unit/lib/ftl/ftl_sb/.gitignore | 1 + test/unit/lib/ftl/ftl_sb/Makefile | 12 + test/unit/lib/ftl/ftl_sb/ftl_sb_ut.c | 322 ++++++++++++++++++ test/unit/unittest.sh | 2 + 17 files changed, 806 insertions(+), 18 deletions(-) create mode 100644 lib/ftl/upgrade/ftl_sb_prev.h create mode 100644 lib/ftl/upgrade/ftl_sb_upgrade.c create mode 100644 lib/ftl/upgrade/ftl_sb_upgrade.h create mode 100644 test/unit/lib/ftl/ftl_layout_upgrade/.gitignore create mode 100644 test/unit/lib/ftl/ftl_layout_upgrade/Makefile create mode 100644 test/unit/lib/ftl/ftl_layout_upgrade/ftl_layout_upgrade_ut.c create mode 100644 test/unit/lib/ftl/ftl_sb/.gitignore create mode 100644 test/unit/lib/ftl/ftl_sb/Makefile create mode 100644 test/unit/lib/ftl/ftl_sb/ftl_sb_ut.c diff --git a/lib/ftl/Makefile b/lib/ftl/Makefile index 851805e2d..c1a8a86fb 100644 --- a/lib/ftl/Makefile +++ b/lib/ftl/Makefile @@ -33,7 +33,7 @@ C_SRCS += mngt/ftl_mngt_md.c mngt/ftl_mngt_misc.c mngt/ftl_mngt_ioch.c mngt/ftl_ C_SRCS += mngt/ftl_mngt_band.c mngt/ftl_mngt_self_test.c mngt/ftl_mngt_p2l.c C_SRCS += mngt/ftl_mngt_recovery.c mngt/ftl_mngt_upgrade.c C_SRCS += utils/ftl_conf.c utils/ftl_md.c utils/ftl_mempool.c utils/ftl_bitmap.c -C_SRCS += upgrade/ftl_layout_upgrade.c +C_SRCS += upgrade/ftl_layout_upgrade.c upgrade/ftl_sb_upgrade.c SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_ftl.map) diff --git a/lib/ftl/ftl_layout.c b/lib/ftl/ftl_layout.c index 4315a41db..f3f040fec 100644 --- a/lib/ftl/ftl_layout.c +++ b/lib/ftl/ftl_layout.c @@ -503,8 +503,8 @@ ftl_layout_setup_superblock(struct spdk_ftl_dev *dev) region->type = FTL_LAYOUT_REGION_TYPE_SB; region->mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE; region->name = "sb"; - region->current.version = FTL_METADATA_VERSION_CURRENT; - region->prev.version = FTL_METADATA_VERSION_CURRENT; + region->current.version = FTL_SB_VERSION_CURRENT; + region->prev.version = FTL_SB_VERSION_CURRENT; region->current.offset = 0; /* @@ -527,8 +527,8 @@ ftl_layout_setup_superblock(struct spdk_ftl_dev *dev) region->type = FTL_LAYOUT_REGION_TYPE_SB_BASE; region->mirror_type = FTL_LAYOUT_REGION_TYPE_MAX; region->name = "sb_mirror"; - region->current.version = FTL_METADATA_VERSION_CURRENT; - region->prev.version = FTL_METADATA_VERSION_CURRENT; + region->current.version = FTL_SB_VERSION_CURRENT; + region->prev.version = FTL_SB_VERSION_CURRENT; /* TODO: This should really be at offset 0 - think how best to upgrade between the two layouts * This is an issue if some other metadata appears at block 0 of base device (most likely GPT or blobstore) */ diff --git a/lib/ftl/ftl_sb.c b/lib/ftl/ftl_sb.c index 76d5a9213..591534019 100644 --- a/lib/ftl/ftl_sb.c +++ b/lib/ftl/ftl_sb.c @@ -6,11 +6,16 @@ #include "ftl_sb.h" #include "ftl_core.h" #include "ftl_layout.h" +#include "upgrade/ftl_sb_prev.h" bool ftl_superblock_check_magic(struct ftl_superblock *sb) { - return sb->header.magic == FTL_SUPERBLOCK_MAGIC; + if (sb->header.version >= FTL_SB_VERSION_3) { + return sb->header.magic == FTL_SUPERBLOCK_MAGIC; + } else { + return sb->header.magic == FTL_SUPERBLOCK_MAGIC_V2; + } } bool ftl_superblock_md_layout_is_empty(struct ftl_superblock *sb) @@ -58,13 +63,13 @@ superblock_md_region_overflow(struct spdk_ftl_dev *dev, struct ftl_superblock_md return true; } - /* There's only a finite (FTL_SUPERBLOCK_SIZE) amount of space in the superblock. Make sure the region wholly fits in that space. */ - if ((uintptr_t)(sb_reg + 1) > ((uintptr_t)(dev->sb) + FTL_SUPERBLOCK_SIZE)) { + /* Make sure the entry doesn't overflow the pointer value (probably overkill to check) */ + if (UINT64_MAX - (uintptr_t)sb_reg < sizeof(*sb_reg)) { return true; } - /* Make sure the entry doesn't overflow the pointer value (probably overkill to check) */ - if ((uintptr_t)(sb_reg + 1) < (uintptr_t)sb_reg) { + /* There's only a finite (FTL_SUPERBLOCK_SIZE) amount of space in the superblock. Make sure the region wholly fits in that space. */ + if ((uintptr_t)(sb_reg + 1) > ((uintptr_t)(dev->sb) + FTL_SUPERBLOCK_SIZE)) { return true; } @@ -258,6 +263,11 @@ next_sb_reg: break; } + if (UINT64_MAX - (uintptr_t)sb <= sb_reg->df_next) { + FTL_ERRLOG(dev, "Buffer overflow\n"); + return -EOVERFLOW; + } + sb_reg = ftl_df_get_obj_ptr(sb, sb_reg->df_next); if (superblock_md_region_overflow(dev, sb_reg)) { FTL_ERRLOG(dev, "Buffer overflow\n"); diff --git a/lib/ftl/ftl_sb_current.h b/lib/ftl/ftl_sb_current.h index 02f984a6c..b4ab2f656 100644 --- a/lib/ftl/ftl_sb_current.h +++ b/lib/ftl/ftl_sb_current.h @@ -9,8 +9,8 @@ #include "spdk/uuid.h" #include "ftl_sb_common.h" -#define FTL_METADATA_VERSION_4 4 -#define FTL_METADATA_VERSION_CURRENT FTL_METADATA_VERSION_4 +#define FTL_SB_VERSION_4 4 +#define FTL_SB_VERSION_CURRENT FTL_SB_VERSION_4 struct ftl_superblock { struct ftl_superblock_header header; diff --git a/lib/ftl/mngt/ftl_mngt_md.c b/lib/ftl/mngt/ftl_mngt_md.c index c03b801e1..1faac1a7f 100644 --- a/lib/ftl/mngt/ftl_mngt_md.c +++ b/lib/ftl/mngt/ftl_mngt_md.c @@ -14,6 +14,7 @@ #include "ftl_internal.h" #include "ftl_sb.h" #include "upgrade/ftl_layout_upgrade.h" +#include "upgrade/ftl_sb_upgrade.h" void ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) @@ -255,8 +256,15 @@ get_sb_crc(struct ftl_superblock *sb) crc = spdk_crc32c_update(buffer, size, crc); buffer += offset + sizeof(sb->header.crc); - size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc); - crc = spdk_crc32c_update(buffer, size, crc); + if (sb->header.version > FTL_SB_VERSION_2) { + /* whole buf for v3 and on: */ + size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc); + crc = spdk_crc32c_update(buffer, size, crc); + } else { + /* special for sb v2 only: */ + size = sizeof(struct ftl_superblock_v2) - offset - sizeof(sb->header.crc); + sb->header.crc = spdk_crc32c_update(buffer, size, crc); + } return crc; } @@ -358,7 +366,7 @@ ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt struct ftl_superblock *sb = dev->sb; sb->header.magic = FTL_SUPERBLOCK_MAGIC; - sb->header.version = FTL_METADATA_VERSION_CURRENT; + sb->header.version = FTL_SB_VERSION_CURRENT; sb->uuid = dev->conf.uuid; sb->clean = 0; dev->sb_shm->shm_clean = false; diff --git a/lib/ftl/upgrade/ftl_layout_upgrade.c b/lib/ftl/upgrade/ftl_layout_upgrade.c index 7a68b2156..24b92f3eb 100644 --- a/lib/ftl/upgrade/ftl_layout_upgrade.c +++ b/lib/ftl/upgrade/ftl_layout_upgrade.c @@ -6,6 +6,7 @@ #include "ftl_layout_upgrade.h" #include "ftl_layout.h" #include "ftl_sb_current.h" +#include "ftl_sb_prev.h" #include "ftl_core.h" #include "ftl_band.h" @@ -35,8 +36,14 @@ static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = { #ifdef SPDK_FTL_VSS_EMU [FTL_LAYOUT_REGION_TYPE_VSS] = {}, #endif - [FTL_LAYOUT_REGION_TYPE_SB] = {}, - [FTL_LAYOUT_REGION_TYPE_SB_BASE] = {}, + [FTL_LAYOUT_REGION_TYPE_SB] = { + .count = FTL_SB_VERSION_CURRENT, + .desc = sb_upgrade_desc, + }, + [FTL_LAYOUT_REGION_TYPE_SB_BASE] = { + .count = FTL_SB_VERSION_CURRENT, + .desc = sb_upgrade_desc, + }, [FTL_LAYOUT_REGION_TYPE_L2P] = {}, [FTL_LAYOUT_REGION_TYPE_BAND_MD] = {}, [FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = {}, diff --git a/lib/ftl/upgrade/ftl_sb_prev.h b/lib/ftl/upgrade/ftl_sb_prev.h new file mode 100644 index 000000000..0678da270 --- /dev/null +++ b/lib/ftl/upgrade/ftl_sb_prev.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) Intel Corporation. + * All rights reserved. + */ + +#ifndef FTL_SB_PREV_H +#define FTL_SB_PREV_H + +#include "spdk/uuid.h" +#include "ftl_sb_common.h" + +/** + * Magic number identifies FTL superblock + * + * This old (pre v3) version has a bug - it's generating the magic number off 16b numbers, but only utilizing 8b from each + */ +#define FTL_MAGIC_V2(a, b, c, d) \ + ((UINT64_C(a) << 24) | (UINT64_C(b) << 16) | (UINT64_C(c) << 8) | UINT64_C(d)) + +#define FTL_SUPERBLOCK_MAGIC_V2 FTL_MAGIC_V2(0x1410, 0x1683, 0x1920, 0x1989) + +#define FTL_SB_VERSION_0 0 +#define FTL_SB_VERSION_1 1 +#define FTL_SB_VERSION_2 2 +#define FTL_SB_VERSION_3 3 + +struct ftl_superblock_v2 { + struct ftl_superblock_header header; + + struct spdk_uuid uuid; + + /* Current sequence number */ + uint64_t seq_id; + + /* Flag describing clean shutdown */ + uint64_t clean; + + /* Number of surfaced LBAs */ + uint64_t lba_cnt; + /* Number of reserved addresses not exposed to the user */ + size_t lba_rsvd; + + /* Maximum IO depth per band relocate */ + size_t max_reloc_qdepth; + + /* Maximum active band relocates */ + size_t max_active_relocs; + + /* Use append instead of write */ + bool use_append; + + /* Maximum supported number of IO channels */ + uint32_t max_io_channels; + + /* Last L2P checkpoint +1 (i.e. min_seq_id, 0:no ckpt) */ + uint64_t ckpt_seq_id; + + struct ftl_superblock_gc_info gc_info; +}; + + +SPDK_STATIC_ASSERT(offsetof(struct ftl_superblock_v2, header) == 0, + "Invalid placement of header"); + +SPDK_STATIC_ASSERT(FTL_SUPERBLOCK_SIZE >= sizeof(struct ftl_superblock_v2), + "FTL SB metadata size is invalid"); + +#endif /* FTL_SB_PREV_H */ diff --git a/lib/ftl/upgrade/ftl_sb_upgrade.c b/lib/ftl/upgrade/ftl_sb_upgrade.c new file mode 100644 index 000000000..2050e4cef --- /dev/null +++ b/lib/ftl/upgrade/ftl_sb_upgrade.c @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) Intel Corporation. + * All rights reserved. + */ + +#include "ftl_sb_upgrade.h" +#include "ftl_layout_upgrade.h" +#include "ftl_layout.h" +#include "ftl_core.h" + +struct ftl_region_upgrade_desc sb_upgrade_desc[] = { + [FTL_SB_VERSION_0] = {.verify = ftl_region_upgrade_disabled}, + [FTL_SB_VERSION_1] = {.verify = ftl_region_upgrade_disabled}, + [FTL_SB_VERSION_2] = {.verify = ftl_region_upgrade_disabled}, + [FTL_SB_VERSION_3] = {.verify = ftl_region_upgrade_disabled}, +}; + +SPDK_STATIC_ASSERT(SPDK_COUNTOF(sb_upgrade_desc) == FTL_SB_VERSION_CURRENT, + "Missing SB region upgrade descriptors"); diff --git a/lib/ftl/upgrade/ftl_sb_upgrade.h b/lib/ftl/upgrade/ftl_sb_upgrade.h new file mode 100644 index 000000000..5c92697f3 --- /dev/null +++ b/lib/ftl/upgrade/ftl_sb_upgrade.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) Intel Corporation. + * All rights reserved. + */ + +#ifndef FTL_SB_UPGRADE_H +#define FTL_SB_UPGRADE_H + +#include "spdk/uuid.h" +#include "ftl_sb_common.h" +#include "ftl_sb_prev.h" +#include "ftl_sb_current.h" + +struct spdk_ftl_dev; +struct ftl_layout_region; + +union ftl_superblock_ver { + struct ftl_superblock_header header; + struct ftl_superblock_v2 v2; + struct ftl_superblock v3; +}; + +#endif /* FTL_SB_UPGRADE_H */ diff --git a/test/unit/lib/ftl/Makefile b/test/unit/lib/ftl/Makefile index fbe0ca20c..f358fc2bd 100644 --- a/test/unit/lib/ftl/Makefile +++ b/test/unit/lib/ftl/Makefile @@ -7,7 +7,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk DIRS-y = ftl_l2p ftl_band.c ftl_io.c -DIRS-y += ftl_bitmap.c ftl_mempool.c ftl_mngt +DIRS-y += ftl_bitmap.c ftl_mempool.c ftl_mngt ftl_sb ftl_layout_upgrade .PHONY: all clean $(DIRS-y) diff --git a/test/unit/lib/ftl/ftl_layout_upgrade/.gitignore b/test/unit/lib/ftl/ftl_layout_upgrade/.gitignore new file mode 100644 index 000000000..999e89e31 --- /dev/null +++ b/test/unit/lib/ftl/ftl_layout_upgrade/.gitignore @@ -0,0 +1 @@ +ftl_layout_upgrade_ut diff --git a/test/unit/lib/ftl/ftl_layout_upgrade/Makefile b/test/unit/lib/ftl/ftl_layout_upgrade/Makefile new file mode 100644 index 000000000..4cdd661af --- /dev/null +++ b/test/unit/lib/ftl/ftl_layout_upgrade/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) Intel Corporation. +# All rights reserved. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) + +TEST_FILE = ftl_layout_upgrade_ut.c + +include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk + +CFLAGS += -I$(SPDK_ROOT_DIR)/lib/ftl -DUTEST diff --git a/test/unit/lib/ftl/ftl_layout_upgrade/ftl_layout_upgrade_ut.c b/test/unit/lib/ftl/ftl_layout_upgrade/ftl_layout_upgrade_ut.c new file mode 100644 index 000000000..3798f0333 --- /dev/null +++ b/test/unit/lib/ftl/ftl_layout_upgrade/ftl_layout_upgrade_ut.c @@ -0,0 +1,303 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) Intel Corporation. + * All rights reserved. + */ + +#include + +#include "spdk/stdinc.h" + +#include "spdk_cunit.h" +#include "common/lib/test_env.c" + +#include "ftl/ftl_layout.h" +#include "ftl/upgrade/ftl_layout_upgrade.h" +#include "ftl/ftl_sb.c" + +extern struct ftl_region_upgrade_desc sb_upgrade_desc[]; + +int l2p_upgrade_v0_to_v1(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx); +int l2p_upgrade_v1_to_v2(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx); +int l2p_upgrade_v2_to_v3(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx); + +struct ftl_region_upgrade_desc l2p_upgrade_desc[] = { + [0] = {.verify = ftl_region_upgrade_enabled, .upgrade = l2p_upgrade_v0_to_v1, .new_version = 1}, + [1] = {.verify = ftl_region_upgrade_enabled, .upgrade = l2p_upgrade_v1_to_v2, .new_version = 2}, + [2] = {.verify = ftl_region_upgrade_enabled, .upgrade = l2p_upgrade_v2_to_v3, .new_version = 3}, +}; + +static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = { +#ifdef SPDK_FTL_VSS_EMU + [FTL_LAYOUT_REGION_TYPE_VSS] = {}, +#endif + [FTL_LAYOUT_REGION_TYPE_SB] = { + .count = FTL_SB_VERSION_CURRENT, + .desc = sb_upgrade_desc, + }, + [FTL_LAYOUT_REGION_TYPE_SB_BASE] = { + .count = FTL_SB_VERSION_CURRENT, + .desc = sb_upgrade_desc, + }, + [FTL_LAYOUT_REGION_TYPE_L2P] = { + .count = 3, + .desc = l2p_upgrade_desc, + }, + [FTL_LAYOUT_REGION_TYPE_BAND_MD] = {}, + [FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = {}, + [FTL_LAYOUT_REGION_TYPE_VALID_MAP] = {}, + [FTL_LAYOUT_REGION_TYPE_NVC_MD] = {}, + [FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = {}, + [FTL_LAYOUT_REGION_TYPE_DATA_NVC] = {}, + [FTL_LAYOUT_REGION_TYPE_DATA_BASE] = {}, + [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = {}, + [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = {}, + [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = {}, + [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = {}, + [FTL_LAYOUT_REGION_TYPE_TRIM_MD] = {}, + [FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = {}, +}; + +SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) == + FTL_LAYOUT_REGION_TYPE_MAX, + "Missing layout upgrade descriptors"); + +#include "ftl/upgrade/ftl_sb_upgrade.c" +#include "ftl/upgrade/ftl_layout_upgrade.c" +#include "ftl/mngt/ftl_mngt_md.c" + +DEFINE_STUB_V(ftl_mngt_fail_step, (struct ftl_mngt_process *mngt)); +DEFINE_STUB_V(ftl_mngt_next_step, (struct ftl_mngt_process *mngt)); +DEFINE_STUB_V(ftl_md_persist, (struct ftl_md *md)); +DEFINE_STUB(ftl_nv_cache_load_state, int, (struct ftl_nv_cache *nv_cache), 0); +DEFINE_STUB_V(ftl_valid_map_load_state, (struct spdk_ftl_dev *dev)); +DEFINE_STUB_V(ftl_bands_load_state, (struct spdk_ftl_dev *dev)); +DEFINE_STUB(ftl_md_get_region, const struct ftl_layout_region *, (struct ftl_md *md), 0); +DEFINE_STUB_V(ftl_md_restore, (struct ftl_md *md)); +DEFINE_STUB(ftl_nv_cache_save_state, int, (struct ftl_nv_cache *nv_cache), 0); +DEFINE_STUB(ftl_mngt_get_step_ctx, void *, (struct ftl_mngt_process *mngt), 0); +DEFINE_STUB_V(ftl_mngt_persist_bands_p2l, (struct ftl_mngt_process *mngt)); +DEFINE_STUB_V(ftl_band_init_gc_iter, (struct spdk_ftl_dev *dev)); +DEFINE_STUB(ftl_validate_regions, int, (struct spdk_ftl_dev *dev, struct ftl_layout *layout), 0); +DEFINE_STUB_V(ftl_layout_dump, (struct spdk_ftl_dev *dev)); +DEFINE_STUB(ftl_layout_setup, int, (struct spdk_ftl_dev *dev), 0); +DEFINE_STUB(ftl_md_create_region_flags, int, (struct spdk_ftl_dev *dev, int region_type), 0); +DEFINE_STUB(ftl_md_create, struct ftl_md *, (struct spdk_ftl_dev *dev, uint64_t blocks, + uint64_t vss_blksz, const char *name, int flags, const struct ftl_layout_region *region), NULL); +DEFINE_STUB(ftl_md_destroy_region_flags, int, (struct spdk_ftl_dev *dev, int region_type), 0); +DEFINE_STUB(ftl_md_destroy_shm_flags, int, (struct spdk_ftl_dev *dev), 0); +DEFINE_STUB_V(ftl_md_destroy, (struct ftl_md *md, int flags)); +DEFINE_STUB_V(ftl_mngt_call_process, (struct ftl_mngt_process *mngt, + const struct ftl_mngt_process_desc *process)); +DEFINE_STUB(ftl_md_get_buffer, void *, (struct ftl_md *md), NULL); +DEFINE_STUB(ftl_layout_setup_superblock, int, (struct spdk_ftl_dev *dev), 0); + +struct spdk_ftl_dev g_dev; +struct ftl_superblock_shm g_sb_shm = {0}; +static uint8_t g_sb_buf[FTL_SUPERBLOCK_SIZE] = {0}; + +#define TEST_OP 0x1984 +#define TEST_REG_BLKS 0x10000 +#define TEST_NVC_BLKS 0x1000000; +#define TEST_BASE_BLKS 0x1000000000; + +static int +test_setup(void) +{ + /* setup a dummy dev: */ + g_dev.sb = (void *)g_sb_buf; + g_dev.sb_shm = &g_sb_shm; + g_dev.conf.overprovisioning = TEST_OP; + for (uint64_t n = 0; n < sizeof(g_dev.conf.uuid); n++) { + g_dev.conf.uuid.u.raw[n] = n; + } + + g_dev.layout.nvc.total_blocks = TEST_NVC_BLKS; + g_dev.layout.base.total_blocks = TEST_BASE_BLKS; + + for (int regno = 0; regno < FTL_LAYOUT_REGION_TYPE_MAX; regno++) { + struct ftl_layout_region *reg = &g_dev.layout.region[regno]; + uint32_t reg_ver = layout_upgrade_desc[regno].count; + + reg->current.blocks = TEST_REG_BLKS; + reg->current.offset = regno * TEST_REG_BLKS; + reg->current.version = reg_ver; + reg->prev.version = reg_ver; + reg->type = regno; + reg->name = "region_test"; + reg->bdev_desc = 0; + reg->ioch = 0; + } + return 0; +} + +static void +test_setup_sb_v3(uint64_t clean) +{ + struct ftl_superblock *sb = (void *)g_sb_buf; + + memset(&g_sb_buf, 0, sizeof(g_sb_buf)); + ftl_mngt_init_default_sb(&g_dev, NULL); + sb->clean = clean; + sb->header.crc = get_sb_crc(sb); +} + +static void +test_l2p_upgrade(void) +{ + union ftl_superblock_ver *sb = (void *)g_sb_buf; + struct ftl_superblock_md_region *sb_reg; + struct ftl_layout_region *reg; + struct ftl_layout_upgrade_ctx ctx = {0}; + ftl_df_obj_id df_next; + uint32_t md_type; + uint64_t upgrades; + int rc; + + test_setup_sb_v3(true); + CU_ASSERT_EQUAL(ftl_superblock_md_layout_is_empty(&sb->v3), true); + + /* load failed: empty md list: */ + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_NOT_EQUAL(rc, 0); + + /* create md layout: */ + ftl_superblock_md_layout_build(&g_dev); + CU_ASSERT_EQUAL(ftl_superblock_md_layout_is_empty(&sb->v3), false); + + df_next = sb->v3.md_layout_head.df_next; + + /* unsupported/fixed md region: */ + md_type = sb->v3.md_layout_head.type; + reg = &g_dev.layout.region[md_type]; + assert(md_type == FTL_LAYOUT_REGION_TYPE_L2P); + sb->v3.md_layout_head.df_next = FTL_SUPERBLOCK_SIZE - sizeof(sb->v3.md_layout_head); + sb->v3.md_layout_head.version = 0; + sb_reg = ftl_df_get_obj_ptr(sb, sb->v3.md_layout_head.df_next); + rc = superblock_md_layout_add(&g_dev, sb_reg, md_type, 2, sb->v3.md_layout_head.blk_offs, + sb->v3.md_layout_head.blk_sz); + CU_ASSERT_EQUAL(rc, 0); + sb_reg->df_next = df_next; + sb_reg->blk_offs = 0x1984; + sb_reg->blk_sz = 0x0514; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_EQUAL(rc, 0); + CU_ASSERT_EQUAL(reg->current.version, 3); + CU_ASSERT_EQUAL(reg->prev.version, 0); + + ctx.reg = &g_dev.layout.region[0]; + ctx.upgrade = &layout_upgrade_desc[0]; + for (int reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; + reg_type++, ctx.reg++, ctx.upgrade++) { + if (reg_type == FTL_LAYOUT_REGION_TYPE_SB || reg_type == FTL_LAYOUT_REGION_TYPE_SB_BASE) { + ctx.reg->prev.version = g_dev.sb->header.version; + } + rc = region_verify(&g_dev, &ctx); + CU_ASSERT_EQUAL(rc, 0); + } + + ctx.reg = &g_dev.layout.region[0]; + ctx.upgrade = &layout_upgrade_desc[0]; + upgrades = 0; + while (true) { + uint64_t prev_ver; + rc = layout_upgrade_select_next_region(&g_dev, &ctx); + if (rc == FTL_LAYOUT_UPGRADE_DONE) { + break; + } + CU_ASSERT_EQUAL(rc, FTL_LAYOUT_UPGRADE_CONTINUE); + CU_ASSERT_EQUAL(ctx.reg->type, FTL_LAYOUT_REGION_TYPE_L2P); + upgrades++; + + prev_ver = ctx.reg->prev.version; + rc = ftl_region_upgrade(&g_dev, &ctx); + CU_ASSERT_EQUAL(rc, 0); + CU_ASSERT_TRUE(prev_ver < ctx.reg->prev.version); + CU_ASSERT_EQUAL(upgrades, ctx.reg->prev.version); + } + CU_ASSERT_EQUAL(upgrades, 3); + CU_ASSERT_EQUAL(reg->prev.sb_md_reg, reg->current.sb_md_reg); + CU_ASSERT_NOT_EQUAL(reg->current.sb_md_reg, NULL); + CU_ASSERT_EQUAL(reg->current.offset, 0x1984); + CU_ASSERT_EQUAL(reg->current.blocks, 0x0514); + + /* no more upgrades: */ + ctx.reg = &g_dev.layout.region[0]; + ctx.upgrade = &layout_upgrade_desc[0]; + rc = layout_upgrade_select_next_region(&g_dev, &ctx); + CU_ASSERT_EQUAL(rc, FTL_LAYOUT_UPGRADE_DONE); + + /* restore the sb: */ + sb->v3.md_layout_head.df_next = df_next; +} + +int +l2p_upgrade_v0_to_v1(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) +{ + struct ftl_layout_region *region = ctx->reg; + /* minor */ + CU_ASSERT_EQUAL(region->prev.version, 0); + CU_ASSERT_NOT_EQUAL(region->prev.sb_md_reg, NULL); + CU_ASSERT_NOT_EQUAL(region->prev.offset, 0x1984); + CU_ASSERT_NOT_EQUAL(region->prev.blocks, 0x0514); + + CU_ASSERT_EQUAL(region->current.sb_md_reg, NULL); + CU_ASSERT_NOT_EQUAL(region->current.offset, 0x1984); + CU_ASSERT_NOT_EQUAL(region->current.blocks, 0x0514); + ftl_region_upgrade_completed(dev, ctx, 0); + return 0; +} + +int +l2p_upgrade_v1_to_v2(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) +{ + struct ftl_layout_region *region = ctx->reg; + /* major */ + CU_ASSERT_EQUAL(region->prev.version, 1); + CU_ASSERT_NOT_EQUAL(region->prev.sb_md_reg, NULL); + CU_ASSERT_NOT_EQUAL(region->prev.offset, 0x1984); + CU_ASSERT_NOT_EQUAL(region->prev.blocks, 0x0514); + + CU_ASSERT_EQUAL(region->current.sb_md_reg, NULL); + CU_ASSERT_NOT_EQUAL(region->current.offset, 0x1984); + CU_ASSERT_NOT_EQUAL(region->current.blocks, 0x0514); + ftl_region_upgrade_completed(dev, ctx, 0); + return 0; +} + +int +l2p_upgrade_v2_to_v3(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) +{ + struct ftl_layout_region *region = ctx->reg; + /* minor */ + CU_ASSERT_EQUAL(region->prev.version, 2); + CU_ASSERT_NOT_EQUAL(region->prev.sb_md_reg, NULL); + CU_ASSERT_EQUAL(region->prev.offset, 0x1984); + CU_ASSERT_EQUAL(region->prev.blocks, 0x0514); + + CU_ASSERT_EQUAL(region->current.sb_md_reg, NULL); + CU_ASSERT_NOT_EQUAL(region->current.offset, 0x1984); + CU_ASSERT_NOT_EQUAL(region->current.blocks, 0x0514); + ftl_region_upgrade_completed(dev, ctx, 0); + return 0; +} + +int +main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + CU_set_error_action(CUEA_ABORT); + CU_initialize_registry(); + + suite = CU_add_suite("ftl_sb", test_setup, NULL); + + CU_ADD_TEST(suite, test_l2p_upgrade); + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + + return num_failures; +} diff --git a/test/unit/lib/ftl/ftl_sb/.gitignore b/test/unit/lib/ftl/ftl_sb/.gitignore new file mode 100644 index 000000000..73aab6e4c --- /dev/null +++ b/test/unit/lib/ftl/ftl_sb/.gitignore @@ -0,0 +1 @@ +ftl_sb_ut diff --git a/test/unit/lib/ftl/ftl_sb/Makefile b/test/unit/lib/ftl/ftl_sb/Makefile new file mode 100644 index 000000000..eb64910db --- /dev/null +++ b/test/unit/lib/ftl/ftl_sb/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) Intel Corporation. +# All rights reserved. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) + +TEST_FILE = ftl_sb_ut.c + +include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk + +CFLAGS += -I$(SPDK_ROOT_DIR)/lib/ftl diff --git a/test/unit/lib/ftl/ftl_sb/ftl_sb_ut.c b/test/unit/lib/ftl/ftl_sb/ftl_sb_ut.c new file mode 100644 index 000000000..d1722e215 --- /dev/null +++ b/test/unit/lib/ftl/ftl_sb/ftl_sb_ut.c @@ -0,0 +1,322 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) Intel Corporation. + * All rights reserved. + */ + +#include + +#include "spdk/stdinc.h" + +#include "spdk_cunit.h" +#include "common/lib/test_env.c" + +#include "ftl/ftl_sb.c" +#include "ftl/upgrade/ftl_sb_upgrade.c" +#include "ftl/upgrade/ftl_layout_upgrade.c" +#include "ftl/mngt/ftl_mngt_md.c" + +DEFINE_STUB_V(ftl_mngt_fail_step, (struct ftl_mngt_process *mngt)); +DEFINE_STUB_V(ftl_mngt_next_step, (struct ftl_mngt_process *mngt)); +DEFINE_STUB_V(ftl_md_persist, (struct ftl_md *md)); +DEFINE_STUB(ftl_nv_cache_load_state, int, (struct ftl_nv_cache *nv_cache), 0); +DEFINE_STUB_V(ftl_valid_map_load_state, (struct spdk_ftl_dev *dev)); +DEFINE_STUB_V(ftl_bands_load_state, (struct spdk_ftl_dev *dev)); +DEFINE_STUB(ftl_md_get_region, const struct ftl_layout_region *, (struct ftl_md *md), 0); +DEFINE_STUB_V(ftl_md_restore, (struct ftl_md *md)); +DEFINE_STUB(ftl_nv_cache_save_state, int, (struct ftl_nv_cache *nv_cache), 0); +DEFINE_STUB(ftl_mngt_get_step_ctx, void *, (struct ftl_mngt_process *mngt), 0); +DEFINE_STUB_V(ftl_mngt_persist_bands_p2l, (struct ftl_mngt_process *mngt)); +DEFINE_STUB_V(ftl_band_init_gc_iter, (struct spdk_ftl_dev *dev)); +DEFINE_STUB(ftl_validate_regions, int, (struct spdk_ftl_dev *dev, struct ftl_layout *layout), 0); +DEFINE_STUB_V(ftl_layout_dump, (struct spdk_ftl_dev *dev)); +DEFINE_STUB(ftl_layout_setup, int, (struct spdk_ftl_dev *dev), 0); +DEFINE_STUB(ftl_md_create_region_flags, int, (struct spdk_ftl_dev *dev, int region_type), 0); +DEFINE_STUB(ftl_md_create, struct ftl_md *, (struct spdk_ftl_dev *dev, uint64_t blocks, + uint64_t vss_blksz, const char *name, int flags, const struct ftl_layout_region *region), NULL); +DEFINE_STUB(ftl_md_destroy_region_flags, int, (struct spdk_ftl_dev *dev, int region_type), 0); +DEFINE_STUB(ftl_md_destroy_shm_flags, int, (struct spdk_ftl_dev *dev), 0); +DEFINE_STUB_V(ftl_md_destroy, (struct ftl_md *md, int flags)); +DEFINE_STUB_V(ftl_mngt_call_process, (struct ftl_mngt_process *mngt, + const struct ftl_mngt_process_desc *process)); +DEFINE_STUB(ftl_md_get_buffer, void *, (struct ftl_md *md), NULL); +DEFINE_STUB(ftl_layout_setup_superblock, int, (struct spdk_ftl_dev *dev), 0); + +struct spdk_ftl_dev g_dev; +struct ftl_superblock_shm g_sb_shm = {0}; +static uint8_t g_sb_buf[FTL_SUPERBLOCK_SIZE] = {0}; + +struct ftl_region_upgrade_desc p2l_upgrade_desc[0]; +struct ftl_region_upgrade_desc nvc_upgrade_desc[0]; +struct ftl_region_upgrade_desc band_upgrade_desc[0]; + +#define TEST_OP 0x1984 +#define TEST_REG_BLKS 0x10000 +#define TEST_NVC_BLKS 0x1000000; +#define TEST_BASE_BLKS 0x1000000000; + +static int +test_setup(void) +{ + /* setup a dummy dev: */ + g_dev.sb = (void *)g_sb_buf; + g_dev.sb_shm = &g_sb_shm; + g_dev.conf.overprovisioning = TEST_OP; + for (uint64_t n = 0; n < sizeof(g_dev.conf.uuid); n++) { + g_dev.conf.uuid.u.raw[n] = n; + } + + g_dev.layout.nvc.total_blocks = TEST_NVC_BLKS; + g_dev.layout.base.total_blocks = TEST_BASE_BLKS; + + for (int regno = 0; regno < FTL_LAYOUT_REGION_TYPE_MAX; regno++) { + struct ftl_layout_region *reg = &g_dev.layout.region[regno]; + reg->current.blocks = TEST_REG_BLKS; + reg->current.offset = regno * TEST_REG_BLKS; + reg->current.version = FTL_SB_VERSION_CURRENT; + reg->prev.version = FTL_SB_VERSION_CURRENT; + reg->type = regno; + reg->name = "region_test"; + reg->bdev_desc = 0; + reg->ioch = 0; + } + return 0; +} + +static void +test_setup_sb_ver(uint64_t ver, uint64_t clean) +{ + union ftl_superblock_ver *sb = (void *)g_sb_buf; + + memset(&g_sb_buf, 0, sizeof(g_sb_buf)); + ftl_mngt_init_default_sb(&g_dev, NULL); + if (ver <= FTL_SB_VERSION_3) { + sb->header.magic = FTL_SUPERBLOCK_MAGIC_V2; + } + sb->header.version = ver; + sb->v2.clean = clean; + sb->v3.md_layout_head.type = 0; + sb->v3.md_layout_head.df_next = 0; + sb->header.crc = get_sb_crc(&sb->v3); +} + +static void +test_setup_sb_v2(uint64_t clean) +{ + test_setup_sb_ver(FTL_SB_VERSION_2, clean); +} + +static void +test_setup_sb_v3(uint64_t clean) +{ + struct ftl_superblock *sb = (void *)g_sb_buf; + + memset(&g_sb_buf, 0, sizeof(g_sb_buf)); + ftl_mngt_init_default_sb(&g_dev, NULL); + sb->clean = clean; + sb->header.crc = get_sb_crc(sb); +} + +static void +test_sb_crc_v2(void) +{ + union ftl_superblock_ver *sb = (void *)g_sb_buf; + uint64_t crc; + + /* v2-specific crc: it's not really working */ + test_setup_sb_v2(true); + crc = sb->header.crc; + + sb->header.crc++; + sb->header.crc = get_sb_crc(&sb->v3); + CU_ASSERT_EQUAL(crc, sb->header.crc); + + g_sb_buf[sizeof(struct ftl_superblock_v2)]++; + sb->header.crc = get_sb_crc(&sb->v3); + CU_ASSERT_EQUAL(crc, sb->header.crc); + + g_sb_buf[sizeof(g_sb_buf) - 1]++; + sb->header.crc = get_sb_crc(&sb->v3); + CU_ASSERT_EQUAL(crc, sb->header.crc); + + sb->header.version += 0x19840514; + sb->v2.seq_id++; + CU_ASSERT_EQUAL(crc, sb->header.crc); +} + +static void +test_sb_crc_v3(void) +{ + union ftl_superblock_ver *sb = (void *)g_sb_buf; + uint64_t crc; + + /* v3 crc: covers the entire buf */ + test_setup_sb_v3(true); + crc = sb->header.crc; + + sb->header.crc++; + sb->header.crc = get_sb_crc(&sb->v3); + CU_ASSERT_EQUAL(crc, sb->header.crc); + crc = sb->header.crc; + + g_sb_buf[sizeof(struct ftl_superblock_v2)]++; + sb->header.crc = get_sb_crc(&sb->v3); + CU_ASSERT_NOT_EQUAL(crc, sb->header.crc); + crc = sb->header.crc; + + g_sb_buf[sizeof(g_sb_buf) - 1]++; + sb->header.crc = get_sb_crc(&sb->v3); + CU_ASSERT_NOT_EQUAL(crc, sb->header.crc); + crc = sb->header.crc; + + sb->header.version += 500; + sb->v2.seq_id++; + CU_ASSERT_EQUAL(crc, sb->header.crc); + crc = sb->header.crc; +} + +static void +test_sb_v3_md_layout(void) +{ + struct ftl_superblock_md_region *sb_reg, *sb_reg2; + struct ftl_layout_region *reg; + union ftl_superblock_ver *sb = (void *)g_sb_buf; + ftl_df_obj_id df_next; + uint32_t md_type; + int rc; + + test_setup_sb_v3(false); + CU_ASSERT_EQUAL(ftl_superblock_md_layout_is_empty(&sb->v3), true); + + /* load failed: empty md list: */ + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_NOT_EQUAL(rc, 0); + + /* create md layout: */ + ftl_superblock_md_layout_build(&g_dev); + CU_ASSERT_EQUAL(ftl_superblock_md_layout_is_empty(&sb->v3), false); + + /* buf overflow, sb_reg = 1 byte overflow: */ + df_next = sb->v3.md_layout_head.df_next; + sb->v3.md_layout_head.df_next = FTL_SUPERBLOCK_SIZE - sizeof(sb->v3.md_layout_head) + 1; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_EQUAL(rc, -EOVERFLOW); + + /* buf underflow, sb_reg = -1: */ + sb->v3.md_layout_head.df_next = UINTPTR_MAX - (uintptr_t)sb; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_EQUAL(rc, -EOVERFLOW); + + /* buf underflow, sb_reg = 2 bytes underflow */ + sb->v3.md_layout_head.df_next = UINTPTR_MAX - 1; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_EQUAL(rc, -EOVERFLOW); + + /* looping md layout list: */ + sb->v3.md_layout_head.df_next = ftl_df_get_obj_id(sb, &sb->v3.md_layout_head); + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_NOT_EQUAL(rc, 0); + + sb->v3.md_layout_head.df_next = df_next; + + /* unsupported/fixed md region: */ + md_type = sb->v3.md_layout_head.type; + sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_SB; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_NOT_EQUAL(rc, 0); + + /* unsupported/invalid md region: */ + sb->v3.md_layout_head.type = FTL_LAYOUT_REGION_TYPE_MAX; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_NOT_EQUAL(rc, 0); + + /* restore the sb: */ + sb->v3.md_layout_head.type = md_type; + + /* load succeeded, no prev version found: */ + reg = &g_dev.layout.region[md_type]; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_EQUAL(rc, 0); + CU_ASSERT_EQUAL(reg->current.version, reg->prev.version); + CU_ASSERT_NOT_EQUAL(reg->current.sb_md_reg, NULL); + CU_ASSERT_EQUAL(reg->prev.sb_md_reg, NULL); + + /* load succeeded, prev (upgrade, i.e. no current) version discovery: */ + reg = &g_dev.layout.region[md_type]; + sb->v3.md_layout_head.version--; + rc = ftl_superblock_md_layout_load_all(&g_dev); + sb->v3.md_layout_head.version++; + CU_ASSERT_EQUAL(rc, 0); + CU_ASSERT_NOT_EQUAL(reg->current.version, reg->prev.version); + CU_ASSERT_EQUAL(reg->current.sb_md_reg, NULL); + CU_ASSERT_NOT_EQUAL(reg->prev.sb_md_reg, NULL); + + /* load failed, unknown (newer) version found: */ + sb->v3.md_layout_head.df_next = FTL_SUPERBLOCK_SIZE - sizeof(sb->v3.md_layout_head); + sb_reg = ftl_df_get_obj_ptr(sb, sb->v3.md_layout_head.df_next); + rc = superblock_md_layout_add(&g_dev, sb_reg, md_type, FTL_SB_VERSION_CURRENT + 1, + sb->v3.md_layout_head.blk_offs, sb->v3.md_layout_head.blk_sz); + CU_ASSERT_EQUAL(rc, 0); + sb_reg->df_next = df_next; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_NOT_EQUAL(rc, 0); + + /* load succeeded, prev version discovery: */ + sb_reg->version = FTL_SB_VERSION_2; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_EQUAL(rc, 0); + CU_ASSERT_NOT_EQUAL(reg->current.version, reg->prev.version); + CU_ASSERT_EQUAL(reg->current.version, FTL_SB_VERSION_CURRENT); + CU_ASSERT_EQUAL(reg->prev.version, FTL_SB_VERSION_2); + + /* looping/multiple (same ver) prev regions found: */ + sb_reg->df_next = FTL_SUPERBLOCK_SIZE - 2 * sizeof(sb->v3.md_layout_head); + sb_reg2 = ftl_df_get_obj_ptr(sb, sb_reg->df_next); + rc = superblock_md_layout_add(&g_dev, sb_reg2, md_type, FTL_SB_VERSION_2, + sb->v3.md_layout_head.blk_offs, sb->v3.md_layout_head.blk_sz); + CU_ASSERT_EQUAL(rc, 0); + sb_reg2->df_next = df_next; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_NOT_EQUAL(rc, 0); + + /* multiple (different ver) prev regions found: */ + sb_reg->df_next = FTL_SUPERBLOCK_SIZE - 2 * sizeof(sb->v3.md_layout_head); + sb_reg2 = ftl_df_get_obj_ptr(sb, sb_reg->df_next); + rc = superblock_md_layout_add(&g_dev, sb_reg2, md_type, FTL_SB_VERSION_1, + sb->v3.md_layout_head.blk_offs, sb->v3.md_layout_head.blk_sz); + CU_ASSERT_EQUAL(rc, 0); + sb_reg2->df_next = df_next; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_EQUAL(rc, 0); + + /* multiple current regions found: */ + sb->v3.md_layout_head.df_next = FTL_SUPERBLOCK_SIZE - sizeof(sb->v3.md_layout_head); + sb_reg2->version = FTL_SB_VERSION_CURRENT; + rc = ftl_superblock_md_layout_load_all(&g_dev); + CU_ASSERT_NOT_EQUAL(rc, 0); + + /* restore the sb: */ + sb->v3.md_layout_head.df_next = df_next; +} + +int +main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + CU_set_error_action(CUEA_ABORT); + CU_initialize_registry(); + + suite = CU_add_suite("ftl_sb", test_setup, NULL); + + CU_ADD_TEST(suite, test_sb_crc_v2); + CU_ADD_TEST(suite, test_sb_crc_v3); + CU_ADD_TEST(suite, test_sb_v3_md_layout); + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + + return num_failures; +} diff --git a/test/unit/unittest.sh b/test/unit/unittest.sh index b7fe5dfc2..4e175bcb5 100755 --- a/test/unit/unittest.sh +++ b/test/unit/unittest.sh @@ -51,6 +51,8 @@ function unittest_ftl() { $valgrind $testdir/lib/ftl/ftl_mngt/ftl_mngt_ut $valgrind $testdir/lib/ftl/ftl_mempool.c/ftl_mempool_ut $valgrind $testdir/lib/ftl/ftl_l2p/ftl_l2p_ut + $valgrind $testdir/lib/ftl/ftl_sb/ftl_sb_ut + $valgrind $testdir/lib/ftl/ftl_layout_upgrade/ftl_layout_upgrade_ut } function unittest_iscsi() {