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
|
||||
|
||||
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_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
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "ftl_internal.h"
|
||||
#include "ftl_io.h"
|
||||
#include "ftl_layout.h"
|
||||
#include "ftl_sb.h"
|
||||
#include "utils/ftl_log.h"
|
||||
|
||||
/* 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 */
|
||||
struct ftl_layout layout;
|
||||
|
||||
/* FTL superblock */
|
||||
struct ftl_superblock *sb;
|
||||
|
||||
/* Queue of registered IO channels */
|
||||
TAILQ_HEAD(, ftl_io_channel) ioch_queue;
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "ftl_core.h"
|
||||
#include "ftl_utils.h"
|
||||
#include "ftl_layout.h"
|
||||
#include "ftl_sb.h"
|
||||
|
||||
static inline float
|
||||
blocks2mib(uint64_t blocks)
|
||||
@ -27,7 +28,6 @@ blocks2mib(uint64_t blocks)
|
||||
#define FTL_LAYOUT_REGION_ALIGNMENT_BLOCKS 32ULL
|
||||
#define FTL_LAYOUT_REGION_ALIGNMENT_BYTES (FTL_LAYOUT_REGION_ALIGNMENT_BLOCKS * FTL_BLOCK_SIZE)
|
||||
|
||||
#ifdef SPDK_FTL_VSS_EMU
|
||||
static inline uint64_t
|
||||
blocks_region(uint64_t bytes)
|
||||
{
|
||||
@ -40,7 +40,6 @@ blocks_region(uint64_t bytes)
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
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
|
||||
|
||||
/* 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->type = FTL_LAYOUT_REGION_TYPE_DATA_NVC;
|
||||
region->name = "data_nvc";
|
||||
@ -157,21 +164,55 @@ error:
|
||||
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
|
||||
setup_layout_base(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
uint64_t left, offset;
|
||||
struct ftl_layout *layout = &dev->layout;
|
||||
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 */
|
||||
region = &layout->region[FTL_LAYOUT_REGION_TYPE_DATA_BASE];
|
||||
region->type = FTL_LAYOUT_REGION_TYPE_DATA_BASE;
|
||||
region->name = "data_btm";
|
||||
region->current.version = region->prev.version = 0;
|
||||
region->current.offset = 0;
|
||||
region->current.blocks = layout->base.total_blocks;
|
||||
region->current.blocks = offset;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -191,6 +232,11 @@ ftl_layout_setup(struct spdk_ftl_dev *dev)
|
||||
|
||||
/* Initialize mirrors types */
|
||||
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;
|
||||
}
|
||||
|
||||
@ -201,6 +247,7 @@ ftl_layout_setup(struct spdk_ftl_dev *dev)
|
||||
if (dev->num_lbas == 0) {
|
||||
assert(dev->conf.mode & SPDK_FTL_MODE_CREATE);
|
||||
dev->num_lbas = num_lbas;
|
||||
dev->sb->lba_cnt = num_lbas;
|
||||
} else if (dev->num_lbas != num_lbas) {
|
||||
FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n");
|
||||
return -EINVAL;
|
||||
@ -262,6 +309,64 @@ ftl_layout_setup_vss_emu(struct spdk_ftl_dev *dev)
|
||||
}
|
||||
#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
|
||||
ftl_layout_dump(struct spdk_ftl_dev *dev)
|
||||
|
@ -16,6 +16,10 @@ enum ftl_layout_region_type {
|
||||
/** VSS region for NV cache VSS emulation */
|
||||
FTL_LAYOUT_REGION_TYPE_VSS,
|
||||
#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 */
|
||||
FTL_LAYOUT_REGION_TYPE_DATA_NVC,
|
||||
|
||||
@ -115,6 +119,11 @@ struct ftl_layout {
|
||||
*/
|
||||
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
|
||||
/**
|
||||
* @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_utils.h"
|
||||
#include "ftl_internal.h"
|
||||
#include "ftl_sb.h"
|
||||
|
||||
void
|
||||
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
|
||||
case FTL_LAYOUT_REGION_TYPE_VSS:
|
||||
#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_BASE:
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
void
|
||||
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);
|
||||
}
|
||||
#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
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.name = "Initialize superblock",
|
||||
.action = ftl_mngt_superblock_init,
|
||||
.cleanup = ftl_mngt_superblock_deinit
|
||||
},
|
||||
{
|
||||
.name = "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",
|
||||
.action = ftl_mngt_scrub_nv_cache,
|
||||
},
|
||||
{
|
||||
.name = "Set FTL dirty state",
|
||||
.action = ftl_mngt_set_dirty,
|
||||
},
|
||||
{
|
||||
.name = "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);
|
||||
#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_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_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 */
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "ftl_core.h"
|
||||
#include "ftl_md.h"
|
||||
#include "ftl_nv_cache_io.h"
|
||||
#include "ftl_utils.h"
|
||||
|
||||
struct ftl_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
|
||||
restore_done(struct ftl_md *md)
|
||||
{
|
||||
@ -729,6 +743,18 @@ restore_done(struct ftl_md *md)
|
||||
} else {
|
||||
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;
|
||||
|
@ -161,6 +161,7 @@ free_device(struct spdk_ftl_dev *dev)
|
||||
free_threads();
|
||||
|
||||
free(dev->ioch);
|
||||
free(dev->sb);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user