Adds API for fast shutdown - the ability for FTL to skip most of the metadata persists made during clean shutdown, and relying on their representation in shared memory instead. This allows for faster update of SPDK (or just FTL, assuming no metadata changes), with downtime reduction from 2-5 seconds to 500-1000 ms (for 14TiB+800GiB base and cache drives). Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com> Change-Id: I5999d31698a81512db8d5893eabee7b505c80d06 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13348 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>
141 lines
2.7 KiB
C
141 lines
2.7 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (c) Intel Corporation.
|
|
* All rights reserved.
|
|
*/
|
|
#include "spdk/ftl.h"
|
|
|
|
#include "ftl_conf.h"
|
|
#include "ftl_core.h"
|
|
|
|
static const struct spdk_ftl_conf g_default_conf = {
|
|
/* 2 free bands - compaction is blocked, gc only */
|
|
.limits[SPDK_FTL_LIMIT_CRIT] = 2,
|
|
/* 3 free bands */
|
|
.limits[SPDK_FTL_LIMIT_HIGH] = 3,
|
|
/* 4 free bands */
|
|
.limits[SPDK_FTL_LIMIT_LOW] = 4,
|
|
/* 5 free bands - gc starts running */
|
|
.limits[SPDK_FTL_LIMIT_START] = 5,
|
|
/* 20% spare blocks */
|
|
.overprovisioning = 20,
|
|
/* IO pool size per user thread (this should be adjusted to thread IO qdepth) */
|
|
.user_io_pool_size = 2048,
|
|
.nv_cache = {
|
|
.chunk_compaction_threshold = 80,
|
|
},
|
|
.fast_shutdown = true,
|
|
};
|
|
|
|
void
|
|
spdk_ftl_get_default_conf(struct spdk_ftl_conf *conf)
|
|
{
|
|
*conf = g_default_conf;
|
|
}
|
|
|
|
void
|
|
spdk_ftl_dev_get_conf(const struct spdk_ftl_dev *dev, struct spdk_ftl_conf *conf)
|
|
{
|
|
*conf = dev->conf;
|
|
}
|
|
|
|
int
|
|
spdk_ftl_conf_copy(struct spdk_ftl_conf *dst, const struct spdk_ftl_conf *src)
|
|
{
|
|
char *name = NULL;
|
|
char *core_mask = NULL;
|
|
char *base_bdev = NULL;
|
|
char *cache_bdev = NULL;
|
|
|
|
if (src->name) {
|
|
name = strdup(src->name);
|
|
if (!name) {
|
|
goto error;
|
|
}
|
|
}
|
|
if (src->core_mask) {
|
|
core_mask = strdup(src->core_mask);
|
|
if (!core_mask) {
|
|
goto error;
|
|
}
|
|
}
|
|
if (src->base_bdev) {
|
|
base_bdev = strdup(src->base_bdev);
|
|
if (!base_bdev) {
|
|
goto error;
|
|
}
|
|
}
|
|
if (src->cache_bdev) {
|
|
cache_bdev = strdup(src->cache_bdev);
|
|
if (!cache_bdev) {
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
*dst = *src;
|
|
dst->name = name;
|
|
dst->core_mask = core_mask;
|
|
dst->base_bdev = base_bdev;
|
|
dst->cache_bdev = cache_bdev;
|
|
return 0;
|
|
error:
|
|
free(name);
|
|
free(core_mask);
|
|
free(base_bdev);
|
|
free(cache_bdev);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
void
|
|
spdk_ftl_conf_deinit(struct spdk_ftl_conf *conf)
|
|
{
|
|
free(conf->name);
|
|
free(conf->core_mask);
|
|
free(conf->base_bdev);
|
|
free(conf->cache_bdev);
|
|
}
|
|
|
|
int
|
|
ftl_conf_init_dev(struct spdk_ftl_dev *dev, const struct spdk_ftl_conf *conf)
|
|
{
|
|
int rc;
|
|
|
|
if (!conf->name) {
|
|
FTL_ERRLOG(dev, "No FTL name in configuration\n");
|
|
return -EINVAL;
|
|
}
|
|
if (!conf->base_bdev) {
|
|
FTL_ERRLOG(dev, "No base device in configuration\n");
|
|
return -EINVAL;
|
|
}
|
|
if (!conf->cache_bdev) {
|
|
FTL_ERRLOG(dev, "No NV cache device in configuration\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = spdk_ftl_conf_copy(&dev->conf, conf);
|
|
if (rc) {
|
|
return rc;
|
|
}
|
|
|
|
dev->limit = SPDK_FTL_LIMIT_MAX;
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
ftl_conf_is_valid(const struct spdk_ftl_conf *conf)
|
|
{
|
|
if (conf->overprovisioning >= 100) {
|
|
return false;
|
|
}
|
|
if (conf->overprovisioning == 0) {
|
|
return false;
|
|
}
|
|
|
|
if (conf->nv_cache.chunk_compaction_threshold == 0 ||
|
|
conf->nv_cache.chunk_compaction_threshold > 100) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|