Spdk/lib/ftl/mngt/ftl_mngt_md.c

285 lines
6.9 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) Intel Corporation.
* All rights reserved.
*/
#include "spdk/thread.h"
#include "spdk/crc32.h"
#include "ftl_core.h"
#include "ftl_mngt.h"
#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)
{
if (ftl_layout_setup(dev)) {
ftl_mngt_fail_step(mngt);
} else {
ftl_mngt_next_step(mngt);
}
}
static bool
is_buffer_needed(enum ftl_layout_region_type type)
{
switch (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;
default:
return true;
}
}
void
ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
struct ftl_layout *layout = &dev->layout;
struct ftl_layout_region *region = layout->region;
uint64_t i;
for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
if (layout->md[i]) {
/*
* Some metadata objects are initialized by other FTL
* components. At the moment it's only used by superblock (and its mirror) -
* during load time we need to read it earlier in order to get the layout for the
* other regions.
*/
continue;
}
layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name,
!is_buffer_needed(i), region);
if (NULL == layout->md[i]) {
ftl_mngt_fail_step(mngt);
return;
}
}
ftl_mngt_next_step(mngt);
}
void
ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
struct ftl_layout *layout = &dev->layout;
struct ftl_layout_region *region = layout->region;
uint64_t i;
for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
if (layout->md[i]) {
ftl_md_destroy(layout->md[i]);
layout->md[i] = NULL;
}
}
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)
{
struct ftl_layout *layout = &dev->layout;
struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS];
/* Initialize VSS layout */
ftl_layout_setup_vss_emu(dev);
/* Allocate md buf */
layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = ftl_md_create(dev, region->current.blocks,
region->vss_blksz, NULL, 0, region);
if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
ftl_mngt_fail_step(mngt);
return;
}
ftl_mngt_next_step(mngt);
}
void
ftl_mngt_md_deinit_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
struct ftl_layout *layout = &dev->layout;
if (layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_VSS]);
layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = NULL;
}
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);
}