ftl: superblock
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com> Change-Id: Ic8ca0cd3bf3621ad5604e83ed24c0fa59a83f124 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13313 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
f725ca81cf
commit
c6880a3974
@ -21,7 +21,7 @@ CFLAGS += -I.
|
|||||||
|
|
||||||
FTL_SUBDIRS := mngt utils
|
FTL_SUBDIRS := mngt utils
|
||||||
|
|
||||||
C_SRCS = ftl_core.c ftl_init.c ftl_layout.c ftl_debug.c ftl_io.c
|
C_SRCS = ftl_core.c ftl_init.c ftl_layout.c ftl_debug.c ftl_io.c ftl_sb.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.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
|
C_SRCS += mngt/ftl_mngt_md.c mngt/ftl_mngt_misc.c mngt/ftl_mngt_ioch.c
|
||||||
C_SRCS += utils/ftl_conf.c utils/ftl_md.c utils/ftl_mempool.c
|
C_SRCS += utils/ftl_conf.c utils/ftl_md.c utils/ftl_mempool.c
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "ftl_internal.h"
|
#include "ftl_internal.h"
|
||||||
#include "ftl_io.h"
|
#include "ftl_io.h"
|
||||||
#include "ftl_layout.h"
|
#include "ftl_layout.h"
|
||||||
|
#include "ftl_sb.h"
|
||||||
#include "utils/ftl_log.h"
|
#include "utils/ftl_log.h"
|
||||||
|
|
||||||
/* When using VSS on nvcache, FTL sometimes doesn't require the contents of metadata.
|
/* When using VSS on nvcache, FTL sometimes doesn't require the contents of metadata.
|
||||||
@ -35,6 +36,9 @@ struct spdk_ftl_dev {
|
|||||||
/* FTL device layout */
|
/* FTL device layout */
|
||||||
struct ftl_layout layout;
|
struct ftl_layout layout;
|
||||||
|
|
||||||
|
/* FTL superblock */
|
||||||
|
struct ftl_superblock *sb;
|
||||||
|
|
||||||
/* Queue of registered IO channels */
|
/* Queue of registered IO channels */
|
||||||
TAILQ_HEAD(, ftl_io_channel) ioch_queue;
|
TAILQ_HEAD(, ftl_io_channel) ioch_queue;
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "ftl_core.h"
|
#include "ftl_core.h"
|
||||||
#include "ftl_utils.h"
|
#include "ftl_utils.h"
|
||||||
#include "ftl_layout.h"
|
#include "ftl_layout.h"
|
||||||
|
#include "ftl_sb.h"
|
||||||
|
|
||||||
static inline float
|
static inline float
|
||||||
blocks2mib(uint64_t blocks)
|
blocks2mib(uint64_t blocks)
|
||||||
@ -27,7 +28,6 @@ blocks2mib(uint64_t blocks)
|
|||||||
#define FTL_LAYOUT_REGION_ALIGNMENT_BLOCKS 32ULL
|
#define FTL_LAYOUT_REGION_ALIGNMENT_BLOCKS 32ULL
|
||||||
#define FTL_LAYOUT_REGION_ALIGNMENT_BYTES (FTL_LAYOUT_REGION_ALIGNMENT_BLOCKS * FTL_BLOCK_SIZE)
|
#define FTL_LAYOUT_REGION_ALIGNMENT_BYTES (FTL_LAYOUT_REGION_ALIGNMENT_BLOCKS * FTL_BLOCK_SIZE)
|
||||||
|
|
||||||
#ifdef SPDK_FTL_VSS_EMU
|
|
||||||
static inline uint64_t
|
static inline uint64_t
|
||||||
blocks_region(uint64_t bytes)
|
blocks_region(uint64_t bytes)
|
||||||
{
|
{
|
||||||
@ -40,7 +40,6 @@ blocks_region(uint64_t bytes)
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
|
dump_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
|
||||||
@ -136,6 +135,14 @@ setup_layout_nvc(struct spdk_ftl_dev *dev)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Skip the superblock region. Already init`d in ftl_layout_setup_superblock */
|
||||||
|
region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
|
||||||
|
offset += region->current.blocks;
|
||||||
|
|
||||||
|
if (offset >= layout->nvc.total_blocks) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
region = &layout->region[FTL_LAYOUT_REGION_TYPE_DATA_NVC];
|
region = &layout->region[FTL_LAYOUT_REGION_TYPE_DATA_NVC];
|
||||||
region->type = FTL_LAYOUT_REGION_TYPE_DATA_NVC;
|
region->type = FTL_LAYOUT_REGION_TYPE_DATA_NVC;
|
||||||
region->name = "data_nvc";
|
region->name = "data_nvc";
|
||||||
@ -157,21 +164,55 @@ error:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ftl_addr
|
||||||
|
layout_base_offset(struct spdk_ftl_dev *dev)
|
||||||
|
{
|
||||||
|
ftl_addr addr;
|
||||||
|
|
||||||
|
addr = dev->num_bands * ftl_get_num_blocks_in_band(dev);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
setup_layout_base(struct spdk_ftl_dev *dev)
|
setup_layout_base(struct spdk_ftl_dev *dev)
|
||||||
{
|
{
|
||||||
|
uint64_t left, offset;
|
||||||
struct ftl_layout *layout = &dev->layout;
|
struct ftl_layout *layout = &dev->layout;
|
||||||
struct ftl_layout_region *region;
|
struct ftl_layout_region *region;
|
||||||
|
|
||||||
|
/* Base device layout is following:
|
||||||
|
* - data
|
||||||
|
* - superblock
|
||||||
|
* - valid map
|
||||||
|
*
|
||||||
|
* Superblock has been already configured, its offset marks the end of the data region
|
||||||
|
*/
|
||||||
|
offset = layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.offset;
|
||||||
|
|
||||||
/* Setup data region on base device */
|
/* Setup data region on base device */
|
||||||
region = &layout->region[FTL_LAYOUT_REGION_TYPE_DATA_BASE];
|
region = &layout->region[FTL_LAYOUT_REGION_TYPE_DATA_BASE];
|
||||||
region->type = FTL_LAYOUT_REGION_TYPE_DATA_BASE;
|
region->type = FTL_LAYOUT_REGION_TYPE_DATA_BASE;
|
||||||
region->name = "data_btm";
|
region->name = "data_btm";
|
||||||
region->current.version = region->prev.version = 0;
|
region->current.version = region->prev.version = 0;
|
||||||
region->current.offset = 0;
|
region->current.offset = 0;
|
||||||
region->current.blocks = layout->base.total_blocks;
|
region->current.blocks = offset;
|
||||||
set_region_bdev_btm(region, dev);
|
set_region_bdev_btm(region, dev);
|
||||||
|
|
||||||
|
/* Move offset after base superblock */
|
||||||
|
offset += layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.blocks;
|
||||||
|
|
||||||
|
/* Checking for underflow */
|
||||||
|
left = layout->base.total_blocks - offset;
|
||||||
|
if (left > layout->base.total_blocks) {
|
||||||
|
FTL_ERRLOG(dev, "Error when setup base device layout\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset > layout->base.total_blocks) {
|
||||||
|
FTL_ERRLOG(dev, "Error when setup base device layout\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,6 +232,11 @@ ftl_layout_setup(struct spdk_ftl_dev *dev)
|
|||||||
|
|
||||||
/* Initialize mirrors types */
|
/* Initialize mirrors types */
|
||||||
for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
|
for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
|
||||||
|
if (i == FTL_LAYOUT_REGION_TYPE_SB) {
|
||||||
|
/* Super block has been already initialized */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
|
layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,6 +247,7 @@ ftl_layout_setup(struct spdk_ftl_dev *dev)
|
|||||||
if (dev->num_lbas == 0) {
|
if (dev->num_lbas == 0) {
|
||||||
assert(dev->conf.mode & SPDK_FTL_MODE_CREATE);
|
assert(dev->conf.mode & SPDK_FTL_MODE_CREATE);
|
||||||
dev->num_lbas = num_lbas;
|
dev->num_lbas = num_lbas;
|
||||||
|
dev->sb->lba_cnt = num_lbas;
|
||||||
} else if (dev->num_lbas != num_lbas) {
|
} else if (dev->num_lbas != num_lbas) {
|
||||||
FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n");
|
FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -262,6 +309,64 @@ ftl_layout_setup_vss_emu(struct spdk_ftl_dev *dev)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
ftl_layout_setup_superblock(struct spdk_ftl_dev *dev)
|
||||||
|
{
|
||||||
|
struct ftl_layout *layout = &dev->layout;
|
||||||
|
struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
|
||||||
|
uint64_t total_blocks, offset, left;
|
||||||
|
|
||||||
|
assert(layout->md[FTL_LAYOUT_REGION_TYPE_SB] == NULL);
|
||||||
|
|
||||||
|
/* Initialize superblock region */
|
||||||
|
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.offset = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VSS region must go first in case SB to make calculating its relative size easier
|
||||||
|
*/
|
||||||
|
#ifdef SPDK_FTL_VSS_EMU
|
||||||
|
region->current.offset = layout->region[FTL_LAYOUT_REGION_TYPE_VSS].current.offset +
|
||||||
|
layout->region[FTL_LAYOUT_REGION_TYPE_VSS].current.blocks;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
region->current.blocks = blocks_region(FTL_SUPERBLOCK_SIZE);
|
||||||
|
region->vss_blksz = 0;
|
||||||
|
region->bdev_desc = dev->cache_bdev_desc;
|
||||||
|
region->ioch = dev->cache_ioch;
|
||||||
|
|
||||||
|
assert(region->bdev_desc != NULL);
|
||||||
|
assert(region->ioch != NULL);
|
||||||
|
|
||||||
|
region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
|
||||||
|
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;
|
||||||
|
/* 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)
|
||||||
|
*/
|
||||||
|
region->current.offset = layout_base_offset(dev);
|
||||||
|
region->current.blocks = blocks_region(FTL_SUPERBLOCK_SIZE);
|
||||||
|
set_region_bdev_btm(region, dev);
|
||||||
|
|
||||||
|
/* Check if SB can be stored at the end of base device */
|
||||||
|
total_blocks = spdk_bdev_get_num_blocks(
|
||||||
|
spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
|
||||||
|
offset = region->current.offset + region->current.blocks;
|
||||||
|
left = total_blocks - offset;
|
||||||
|
if ((left > total_blocks) || (offset > total_blocks)) {
|
||||||
|
FTL_ERRLOG(dev, "Error when setup base device super block\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ftl_layout_dump(struct spdk_ftl_dev *dev)
|
ftl_layout_dump(struct spdk_ftl_dev *dev)
|
||||||
|
@ -16,6 +16,10 @@ enum ftl_layout_region_type {
|
|||||||
/** VSS region for NV cache VSS emulation */
|
/** VSS region for NV cache VSS emulation */
|
||||||
FTL_LAYOUT_REGION_TYPE_VSS,
|
FTL_LAYOUT_REGION_TYPE_VSS,
|
||||||
#endif
|
#endif
|
||||||
|
/* Superblock describing the basic FTL information */
|
||||||
|
FTL_LAYOUT_REGION_TYPE_SB,
|
||||||
|
/* Mirrored instance of the superblock on the base device */
|
||||||
|
FTL_LAYOUT_REGION_TYPE_SB_BASE,
|
||||||
/* User data region on the nv cache device */
|
/* User data region on the nv cache device */
|
||||||
FTL_LAYOUT_REGION_TYPE_DATA_NVC,
|
FTL_LAYOUT_REGION_TYPE_DATA_NVC,
|
||||||
|
|
||||||
@ -115,6 +119,11 @@ struct ftl_layout {
|
|||||||
*/
|
*/
|
||||||
int ftl_layout_setup(struct spdk_ftl_dev *dev);
|
int ftl_layout_setup(struct spdk_ftl_dev *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Setup FTL layout of a superblock
|
||||||
|
*/
|
||||||
|
int ftl_layout_setup_superblock(struct spdk_ftl_dev *dev);
|
||||||
|
|
||||||
#ifdef SPDK_FTL_VSS_EMU
|
#ifdef SPDK_FTL_VSS_EMU
|
||||||
/**
|
/**
|
||||||
* @brief Setup FTL layout of VSS emu
|
* @brief Setup FTL layout of VSS emu
|
||||||
|
14
lib/ftl/ftl_sb.c
Normal file
14
lib/ftl/ftl_sb.c
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright (c) Intel Corporation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ftl_sb.h"
|
||||||
|
#include "ftl_core.h"
|
||||||
|
#include "ftl_layout.h"
|
||||||
|
|
||||||
|
bool
|
||||||
|
ftl_superblock_check_magic(struct ftl_superblock *sb)
|
||||||
|
{
|
||||||
|
return sb->header.magic == FTL_SUPERBLOCK_MAGIC;
|
||||||
|
}
|
17
lib/ftl/ftl_sb.h
Normal file
17
lib/ftl/ftl_sb.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright (c) Intel Corporation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FTL_SB_H
|
||||||
|
#define FTL_SB_H
|
||||||
|
|
||||||
|
#include "spdk/uuid.h"
|
||||||
|
#include "ftl_sb_common.h"
|
||||||
|
#include "ftl_sb_current.h"
|
||||||
|
|
||||||
|
struct spdk_ftl_dev;
|
||||||
|
|
||||||
|
bool ftl_superblock_check_magic(struct ftl_superblock *sb);
|
||||||
|
|
||||||
|
#endif /* FTL_SB_H */
|
50
lib/ftl/ftl_sb_common.h
Normal file
50
lib/ftl/ftl_sb_common.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright (c) Intel Corporation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FTL_SB_COMMON_H
|
||||||
|
#define FTL_SB_COMMON_H
|
||||||
|
|
||||||
|
#include "spdk/stdinc.h"
|
||||||
|
#include "utils/ftl_defs.h"
|
||||||
|
|
||||||
|
/* Size of superblock on NV cache, make it bigger for future fields */
|
||||||
|
#define FTL_SUPERBLOCK_SIZE (128ULL * KiB)
|
||||||
|
|
||||||
|
#define FTL_MAGIC(a, b, c, d) \
|
||||||
|
((UINT64_C(a) << 48) | (UINT64_C(b) << 32) | (UINT64_C(c) << 16) | \
|
||||||
|
UINT64_C(d))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic number identifies FTL superblock
|
||||||
|
*/
|
||||||
|
#define FTL_SUPERBLOCK_MAGIC FTL_MAGIC(0x1410, 0x1683, 0x1920, 0x1989)
|
||||||
|
|
||||||
|
struct ftl_superblock_gc_info {
|
||||||
|
/* High priority band; if there's no free bands after dirty shutdown, don't restart GC from same id, or phys_id -
|
||||||
|
* pick actual lowest validity band to avoid being stuck and try to write it to the open band.
|
||||||
|
*/
|
||||||
|
uint64_t band_id_high_prio;
|
||||||
|
/* Currently relocated band (note it's just id, not seq_id ie. its actual location on disk) */
|
||||||
|
uint64_t current_band_id;
|
||||||
|
/* Bands are grouped together into larger reclaim units; this is the band id translated to those units */
|
||||||
|
uint64_t band_phys_id;
|
||||||
|
/* May be updating multiple fields at the same time, clearing/setting this marks the transaction */
|
||||||
|
uint64_t is_valid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ftl_superblock_header {
|
||||||
|
uint64_t magic;
|
||||||
|
uint64_t crc;
|
||||||
|
uint64_t version;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ftl_superblock_md_region {
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t version;
|
||||||
|
uint64_t blk_offs;
|
||||||
|
uint64_t blk_sz;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FTL_SB_COMMON_H */
|
48
lib/ftl/ftl_sb_current.h
Normal file
48
lib/ftl/ftl_sb_current.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright (c) Intel Corporation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FTL_SB_CURRENT_H
|
||||||
|
#define FTL_SB_CURRENT_H
|
||||||
|
|
||||||
|
#include "spdk/uuid.h"
|
||||||
|
#include "ftl_sb_common.h"
|
||||||
|
|
||||||
|
#define FTL_METADATA_VERSION_4 4
|
||||||
|
#define FTL_METADATA_VERSION_CURRENT FTL_METADATA_VERSION_4
|
||||||
|
|
||||||
|
struct ftl_superblock {
|
||||||
|
struct ftl_superblock_header header;
|
||||||
|
|
||||||
|
struct spdk_uuid uuid;
|
||||||
|
|
||||||
|
/* Flag describing clean shutdown */
|
||||||
|
uint64_t clean;
|
||||||
|
|
||||||
|
/* Number of surfaced LBAs */
|
||||||
|
uint64_t lba_cnt;
|
||||||
|
|
||||||
|
/* Percentage of base device blocks not exposed to the user */
|
||||||
|
uint64_t overprovisioning;
|
||||||
|
|
||||||
|
/* Maximum IO depth per band relocate */
|
||||||
|
uint64_t max_reloc_qdepth;
|
||||||
|
|
||||||
|
/* Reserved field */
|
||||||
|
uint64_t reserved;
|
||||||
|
|
||||||
|
uint32_t reserved2;
|
||||||
|
|
||||||
|
struct ftl_superblock_gc_info gc_info;
|
||||||
|
|
||||||
|
struct ftl_superblock_md_region md_layout_head;
|
||||||
|
};
|
||||||
|
|
||||||
|
SPDK_STATIC_ASSERT(offsetof(struct ftl_superblock, header) == 0,
|
||||||
|
"Invalid placement of header");
|
||||||
|
|
||||||
|
SPDK_STATIC_ASSERT(FTL_SUPERBLOCK_SIZE >= sizeof(struct ftl_superblock),
|
||||||
|
"FTL SB metadata size is invalid");
|
||||||
|
|
||||||
|
#endif /* FTL_SB_CURRENT_H */
|
@ -11,6 +11,7 @@
|
|||||||
#include "ftl_mngt_steps.h"
|
#include "ftl_mngt_steps.h"
|
||||||
#include "ftl_utils.h"
|
#include "ftl_utils.h"
|
||||||
#include "ftl_internal.h"
|
#include "ftl_internal.h"
|
||||||
|
#include "ftl_sb.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)
|
||||||
@ -29,6 +30,8 @@ is_buffer_needed(enum ftl_layout_region_type type)
|
|||||||
#ifdef SPDK_FTL_VSS_EMU
|
#ifdef SPDK_FTL_VSS_EMU
|
||||||
case FTL_LAYOUT_REGION_TYPE_VSS:
|
case FTL_LAYOUT_REGION_TYPE_VSS:
|
||||||
#endif
|
#endif
|
||||||
|
case FTL_LAYOUT_REGION_TYPE_SB:
|
||||||
|
case FTL_LAYOUT_REGION_TYPE_SB_BASE:
|
||||||
case FTL_LAYOUT_REGION_TYPE_DATA_NVC:
|
case FTL_LAYOUT_REGION_TYPE_DATA_NVC:
|
||||||
case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
|
case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
|
||||||
return false;
|
return false;
|
||||||
@ -83,6 +86,103 @@ ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|||||||
ftl_mngt_next_step(mngt);
|
ftl_mngt_next_step(mngt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
|
||||||
|
{
|
||||||
|
struct ftl_mngt_process *mngt = md->owner.cb_ctx;
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
ftl_mngt_fail_step(mngt);
|
||||||
|
} else {
|
||||||
|
ftl_mngt_next_step(mngt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
|
||||||
|
enum ftl_layout_region_type type)
|
||||||
|
{
|
||||||
|
struct ftl_layout *layout = &dev->layout;
|
||||||
|
struct ftl_md *md = layout->md[type];
|
||||||
|
|
||||||
|
assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
|
||||||
|
|
||||||
|
if (!md) {
|
||||||
|
ftl_mngt_fail_step(mngt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
md->owner.cb_ctx = mngt;
|
||||||
|
md->cb = persist_cb;
|
||||||
|
ftl_md_persist(md);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
get_sb_crc(struct ftl_superblock *sb)
|
||||||
|
{
|
||||||
|
uint32_t crc = 0;
|
||||||
|
|
||||||
|
/* Calculate CRC excluding CRC field in superblock */
|
||||||
|
void *buffer = sb;
|
||||||
|
size_t offset = offsetof(struct ftl_superblock, header.crc);
|
||||||
|
size_t size = offset;
|
||||||
|
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);
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
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->uuid = dev->conf.uuid;
|
||||||
|
sb->clean = 0;
|
||||||
|
|
||||||
|
/* Max 16 IO depth per band relocate */
|
||||||
|
sb->max_reloc_qdepth = 16;
|
||||||
|
|
||||||
|
sb->overprovisioning = dev->conf.overprovisioning;
|
||||||
|
|
||||||
|
/* md layout isn't initialized yet.
|
||||||
|
* empty region list => all regions in the default location */
|
||||||
|
sb->md_layout_head.type = FTL_LAYOUT_REGION_TYPE_INVALID;
|
||||||
|
|
||||||
|
sb->header.crc = get_sb_crc(sb);
|
||||||
|
|
||||||
|
ftl_mngt_next_step(mngt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||||
|
{
|
||||||
|
struct ftl_superblock *sb = dev->sb;
|
||||||
|
|
||||||
|
sb->clean = 0;
|
||||||
|
sb->header.crc = get_sb_crc(sb);
|
||||||
|
persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes the superblock fields during first startup of FTL
|
||||||
|
*/
|
||||||
|
static const struct ftl_mngt_process_desc desc_init_sb = {
|
||||||
|
.name = "SB initialize",
|
||||||
|
.steps = {
|
||||||
|
{
|
||||||
|
.name = "Default-initialize superblock",
|
||||||
|
.action = ftl_mngt_init_default_sb,
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef SPDK_FTL_VSS_EMU
|
#ifdef SPDK_FTL_VSS_EMU
|
||||||
void
|
void
|
||||||
ftl_mngt_md_init_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
ftl_mngt_md_init_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||||
@ -116,3 +216,69 @@ ftl_mngt_md_deinit_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mn
|
|||||||
ftl_mngt_next_step(mngt);
|
ftl_mngt_next_step(mngt);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||||
|
{
|
||||||
|
struct ftl_layout *layout = &dev->layout;
|
||||||
|
struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
|
||||||
|
char uuid[SPDK_UUID_STRING_LEN];
|
||||||
|
|
||||||
|
/* Must generate UUID before MD create on SHM for the SB */
|
||||||
|
if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
|
||||||
|
spdk_uuid_generate(&dev->conf.uuid);
|
||||||
|
spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
|
||||||
|
FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the layout of a superblock */
|
||||||
|
if (ftl_layout_setup_superblock(dev)) {
|
||||||
|
ftl_mngt_fail_step(mngt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate md buf */
|
||||||
|
layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
|
||||||
|
region->vss_blksz, region->name, false, region);
|
||||||
|
if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
|
||||||
|
ftl_mngt_fail_step(mngt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Link the md buf to the device */
|
||||||
|
dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
|
||||||
|
|
||||||
|
/* Setup superblock mirror to QLC */
|
||||||
|
region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
|
||||||
|
layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
|
||||||
|
region->vss_blksz, NULL, false, region);
|
||||||
|
if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
|
||||||
|
ftl_mngt_fail_step(mngt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the superblock */
|
||||||
|
if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
|
||||||
|
ftl_mngt_call_process(mngt, &desc_init_sb);
|
||||||
|
} else {
|
||||||
|
ftl_mngt_fail_step(mngt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||||
|
{
|
||||||
|
struct ftl_layout *layout = &dev->layout;
|
||||||
|
|
||||||
|
if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
|
||||||
|
ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
|
||||||
|
layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
|
||||||
|
ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]);
|
||||||
|
layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ftl_mngt_next_step(mngt);
|
||||||
|
}
|
||||||
|
@ -49,6 +49,11 @@ static const struct ftl_mngt_process_desc desc_startup = {
|
|||||||
.cleanup = ftl_mngt_md_deinit_vss_emu
|
.cleanup = ftl_mngt_md_deinit_vss_emu
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
.name = "Initialize superblock",
|
||||||
|
.action = ftl_mngt_superblock_init,
|
||||||
|
.cleanup = ftl_mngt_superblock_deinit
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "Register IO device",
|
.name = "Register IO device",
|
||||||
.action = ftl_mngt_register_io_device,
|
.action = ftl_mngt_register_io_device,
|
||||||
@ -88,6 +93,10 @@ static const struct ftl_mngt_process_desc desc_first_start = {
|
|||||||
.name = "Scrub NV cache",
|
.name = "Scrub NV cache",
|
||||||
.action = ftl_mngt_scrub_nv_cache,
|
.action = ftl_mngt_scrub_nv_cache,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "Set FTL dirty state",
|
||||||
|
.action = ftl_mngt_set_dirty,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "Start core poller",
|
.name = "Start core poller",
|
||||||
.action = ftl_mngt_start_core_poller,
|
.action = ftl_mngt_start_core_poller,
|
||||||
|
@ -20,6 +20,10 @@ void ftl_mngt_md_init_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process
|
|||||||
void ftl_mngt_md_deinit_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
void ftl_mngt_md_deinit_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||||
|
|
||||||
|
void ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||||
|
|
||||||
void ftl_mngt_open_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
void ftl_mngt_open_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||||
|
|
||||||
void ftl_mngt_close_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
void ftl_mngt_close_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||||
@ -50,4 +54,8 @@ void ftl_mngt_rollback_device(struct spdk_ftl_dev *dev, struct ftl_mngt_process
|
|||||||
|
|
||||||
void ftl_mngt_dump_stats(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
void ftl_mngt_dump_stats(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||||
|
|
||||||
|
void ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||||
|
|
||||||
|
void ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||||
|
|
||||||
#endif /* FTL_MNGT_STEPS_H */
|
#endif /* FTL_MNGT_STEPS_H */
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "ftl_core.h"
|
#include "ftl_core.h"
|
||||||
#include "ftl_md.h"
|
#include "ftl_md.h"
|
||||||
#include "ftl_nv_cache_io.h"
|
#include "ftl_nv_cache_io.h"
|
||||||
#include "ftl_utils.h"
|
|
||||||
|
|
||||||
struct ftl_md;
|
struct ftl_md;
|
||||||
static void io_submit(struct ftl_md *md);
|
static void io_submit(struct ftl_md *md);
|
||||||
@ -703,6 +702,21 @@ restore_mirror_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
restore_sync_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
|
||||||
|
{
|
||||||
|
struct ftl_md *primary = md->owner.private;
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
/* Cannot sync the object from the primary to the mirror, mark error and fail */
|
||||||
|
primary->io.status = -EIO;
|
||||||
|
io_done(primary);
|
||||||
|
} else {
|
||||||
|
primary->cb(dev, primary, primary->io.status);
|
||||||
|
io_cleanup(primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
restore_done(struct ftl_md *md)
|
restore_done(struct ftl_md *md)
|
||||||
{
|
{
|
||||||
@ -729,6 +743,18 @@ restore_done(struct ftl_md *md)
|
|||||||
} else {
|
} else {
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
} else if (0 == md->io.status && false == md->dev->sb->clean) {
|
||||||
|
if (has_mirror(md)) {
|
||||||
|
/* There was a dirty shutdown, synchronize primary to mirror */
|
||||||
|
|
||||||
|
/* Set callback and context in the mirror */
|
||||||
|
md->mirror->cb = restore_sync_cb;
|
||||||
|
md->mirror->owner.private = md;
|
||||||
|
|
||||||
|
/* First persist the mirror */
|
||||||
|
ftl_md_persist(md->mirror);
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return md->io.status;
|
return md->io.status;
|
||||||
|
@ -161,6 +161,7 @@ free_device(struct spdk_ftl_dev *dev)
|
|||||||
free_threads();
|
free_threads();
|
||||||
|
|
||||||
free(dev->ioch);
|
free(dev->ioch);
|
||||||
|
free(dev->sb);
|
||||||
free(dev);
|
free(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user