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 <mateusz.kozlowski@intel.com> Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Change-Id: If888866806e948ee07f0777612da73ab8b7548b1 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13385 Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
7ff285193f
commit
c8ab874d7c
@ -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_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 += 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 += 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)
|
SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_ftl.map)
|
||||||
|
|
||||||
|
@ -503,8 +503,8 @@ ftl_layout_setup_superblock(struct spdk_ftl_dev *dev)
|
|||||||
region->type = FTL_LAYOUT_REGION_TYPE_SB;
|
region->type = FTL_LAYOUT_REGION_TYPE_SB;
|
||||||
region->mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE;
|
region->mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE;
|
||||||
region->name = "sb";
|
region->name = "sb";
|
||||||
region->current.version = FTL_METADATA_VERSION_CURRENT;
|
region->current.version = FTL_SB_VERSION_CURRENT;
|
||||||
region->prev.version = FTL_METADATA_VERSION_CURRENT;
|
region->prev.version = FTL_SB_VERSION_CURRENT;
|
||||||
region->current.offset = 0;
|
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->type = FTL_LAYOUT_REGION_TYPE_SB_BASE;
|
||||||
region->mirror_type = FTL_LAYOUT_REGION_TYPE_MAX;
|
region->mirror_type = FTL_LAYOUT_REGION_TYPE_MAX;
|
||||||
region->name = "sb_mirror";
|
region->name = "sb_mirror";
|
||||||
region->current.version = FTL_METADATA_VERSION_CURRENT;
|
region->current.version = FTL_SB_VERSION_CURRENT;
|
||||||
region->prev.version = FTL_METADATA_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
|
/* 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)
|
* This is an issue if some other metadata appears at block 0 of base device (most likely GPT or blobstore)
|
||||||
*/
|
*/
|
||||||
|
@ -6,11 +6,16 @@
|
|||||||
#include "ftl_sb.h"
|
#include "ftl_sb.h"
|
||||||
#include "ftl_core.h"
|
#include "ftl_core.h"
|
||||||
#include "ftl_layout.h"
|
#include "ftl_layout.h"
|
||||||
|
#include "upgrade/ftl_sb_prev.h"
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ftl_superblock_check_magic(struct ftl_superblock *sb)
|
ftl_superblock_check_magic(struct ftl_superblock *sb)
|
||||||
{
|
{
|
||||||
|
if (sb->header.version >= FTL_SB_VERSION_3) {
|
||||||
return sb->header.magic == FTL_SUPERBLOCK_MAGIC;
|
return sb->header.magic == FTL_SUPERBLOCK_MAGIC;
|
||||||
|
} else {
|
||||||
|
return sb->header.magic == FTL_SUPERBLOCK_MAGIC_V2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bool
|
bool
|
||||||
ftl_superblock_md_layout_is_empty(struct ftl_superblock *sb)
|
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;
|
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. */
|
/* Make sure the entry doesn't overflow the pointer value (probably overkill to check) */
|
||||||
if ((uintptr_t)(sb_reg + 1) > ((uintptr_t)(dev->sb) + FTL_SUPERBLOCK_SIZE)) {
|
if (UINT64_MAX - (uintptr_t)sb_reg < sizeof(*sb_reg)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure the entry doesn't overflow the pointer value (probably overkill to check) */
|
/* 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)sb_reg) {
|
if ((uintptr_t)(sb_reg + 1) > ((uintptr_t)(dev->sb) + FTL_SUPERBLOCK_SIZE)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,6 +263,11 @@ next_sb_reg:
|
|||||||
break;
|
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);
|
sb_reg = ftl_df_get_obj_ptr(sb, sb_reg->df_next);
|
||||||
if (superblock_md_region_overflow(dev, sb_reg)) {
|
if (superblock_md_region_overflow(dev, sb_reg)) {
|
||||||
FTL_ERRLOG(dev, "Buffer overflow\n");
|
FTL_ERRLOG(dev, "Buffer overflow\n");
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
#include "spdk/uuid.h"
|
#include "spdk/uuid.h"
|
||||||
#include "ftl_sb_common.h"
|
#include "ftl_sb_common.h"
|
||||||
|
|
||||||
#define FTL_METADATA_VERSION_4 4
|
#define FTL_SB_VERSION_4 4
|
||||||
#define FTL_METADATA_VERSION_CURRENT FTL_METADATA_VERSION_4
|
#define FTL_SB_VERSION_CURRENT FTL_SB_VERSION_4
|
||||||
|
|
||||||
struct ftl_superblock {
|
struct ftl_superblock {
|
||||||
struct ftl_superblock_header header;
|
struct ftl_superblock_header header;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "ftl_internal.h"
|
#include "ftl_internal.h"
|
||||||
#include "ftl_sb.h"
|
#include "ftl_sb.h"
|
||||||
#include "upgrade/ftl_layout_upgrade.h"
|
#include "upgrade/ftl_layout_upgrade.h"
|
||||||
|
#include "upgrade/ftl_sb_upgrade.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
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);
|
crc = spdk_crc32c_update(buffer, size, crc);
|
||||||
|
|
||||||
buffer += offset + sizeof(sb->header.crc);
|
buffer += offset + sizeof(sb->header.crc);
|
||||||
|
if (sb->header.version > FTL_SB_VERSION_2) {
|
||||||
|
/* whole buf for v3 and on: */
|
||||||
size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc);
|
size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc);
|
||||||
crc = spdk_crc32c_update(buffer, size, 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;
|
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;
|
struct ftl_superblock *sb = dev->sb;
|
||||||
|
|
||||||
sb->header.magic = FTL_SUPERBLOCK_MAGIC;
|
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->uuid = dev->conf.uuid;
|
||||||
sb->clean = 0;
|
sb->clean = 0;
|
||||||
dev->sb_shm->shm_clean = false;
|
dev->sb_shm->shm_clean = false;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "ftl_layout_upgrade.h"
|
#include "ftl_layout_upgrade.h"
|
||||||
#include "ftl_layout.h"
|
#include "ftl_layout.h"
|
||||||
#include "ftl_sb_current.h"
|
#include "ftl_sb_current.h"
|
||||||
|
#include "ftl_sb_prev.h"
|
||||||
#include "ftl_core.h"
|
#include "ftl_core.h"
|
||||||
#include "ftl_band.h"
|
#include "ftl_band.h"
|
||||||
|
|
||||||
@ -35,8 +36,14 @@ static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = {
|
|||||||
#ifdef SPDK_FTL_VSS_EMU
|
#ifdef SPDK_FTL_VSS_EMU
|
||||||
[FTL_LAYOUT_REGION_TYPE_VSS] = {},
|
[FTL_LAYOUT_REGION_TYPE_VSS] = {},
|
||||||
#endif
|
#endif
|
||||||
[FTL_LAYOUT_REGION_TYPE_SB] = {},
|
[FTL_LAYOUT_REGION_TYPE_SB] = {
|
||||||
[FTL_LAYOUT_REGION_TYPE_SB_BASE] = {},
|
.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_L2P] = {},
|
||||||
[FTL_LAYOUT_REGION_TYPE_BAND_MD] = {},
|
[FTL_LAYOUT_REGION_TYPE_BAND_MD] = {},
|
||||||
[FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = {},
|
[FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = {},
|
||||||
|
68
lib/ftl/upgrade/ftl_sb_prev.h
Normal file
68
lib/ftl/upgrade/ftl_sb_prev.h
Normal file
@ -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 */
|
19
lib/ftl/upgrade/ftl_sb_upgrade.c
Normal file
19
lib/ftl/upgrade/ftl_sb_upgrade.c
Normal file
@ -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");
|
23
lib/ftl/upgrade/ftl_sb_upgrade.h
Normal file
23
lib/ftl/upgrade/ftl_sb_upgrade.h
Normal file
@ -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 */
|
@ -7,7 +7,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
|
|||||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||||
|
|
||||||
DIRS-y = ftl_l2p ftl_band.c ftl_io.c
|
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)
|
.PHONY: all clean $(DIRS-y)
|
||||||
|
|
||||||
|
1
test/unit/lib/ftl/ftl_layout_upgrade/.gitignore
vendored
Normal file
1
test/unit/lib/ftl/ftl_layout_upgrade/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
ftl_layout_upgrade_ut
|
12
test/unit/lib/ftl/ftl_layout_upgrade/Makefile
Normal file
12
test/unit/lib/ftl/ftl_layout_upgrade/Makefile
Normal file
@ -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
|
303
test/unit/lib/ftl/ftl_layout_upgrade/ftl_layout_upgrade_ut.c
Normal file
303
test/unit/lib/ftl/ftl_layout_upgrade/ftl_layout_upgrade_ut.c
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright (c) Intel Corporation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
1
test/unit/lib/ftl/ftl_sb/.gitignore
vendored
Normal file
1
test/unit/lib/ftl/ftl_sb/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
ftl_sb_ut
|
12
test/unit/lib/ftl/ftl_sb/Makefile
Normal file
12
test/unit/lib/ftl/ftl_sb/Makefile
Normal file
@ -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
|
322
test/unit/lib/ftl/ftl_sb/ftl_sb_ut.c
Normal file
322
test/unit/lib/ftl/ftl_sb/ftl_sb_ut.c
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright (c) Intel Corporation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
@ -51,6 +51,8 @@ function unittest_ftl() {
|
|||||||
$valgrind $testdir/lib/ftl/ftl_mngt/ftl_mngt_ut
|
$valgrind $testdir/lib/ftl/ftl_mngt/ftl_mngt_ut
|
||||||
$valgrind $testdir/lib/ftl/ftl_mempool.c/ftl_mempool_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_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() {
|
function unittest_iscsi() {
|
||||||
|
Loading…
Reference in New Issue
Block a user