ftl: device startup and shutdown
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com> Change-Id: Ia4a3439a2ac79e24bc6dc11a5c131d44ecb2ad80 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13291 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Mellanox Build Bot Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
This commit is contained in:
parent
9f6a324301
commit
e49ccfc820
@ -18,6 +18,12 @@ extern "C" {
|
||||
struct spdk_ftl_dev;
|
||||
|
||||
struct spdk_ftl_conf {
|
||||
/* Device's name */
|
||||
char *name;
|
||||
|
||||
/* Device UUID (valid when restoring device from disk) */
|
||||
struct spdk_uuid uuid;
|
||||
|
||||
/* Percentage of base device blocks not exposed to the user */
|
||||
uint64_t overprovisioning;
|
||||
|
||||
@ -35,9 +41,6 @@ struct spdk_ftl_conf {
|
||||
|
||||
/* Name of cache block device (must support extended metadata) */
|
||||
char *cache_bdev;
|
||||
|
||||
/* Base bdev reclaim unit size */
|
||||
uint64_t base_bdev_reclaim_unit_size;
|
||||
};
|
||||
|
||||
enum spdk_ftl_mode {
|
||||
@ -45,6 +48,39 @@ enum spdk_ftl_mode {
|
||||
SPDK_FTL_MODE_CREATE = (1 << 0),
|
||||
};
|
||||
|
||||
typedef void (*spdk_ftl_fn)(void *cb_arg, int status);
|
||||
typedef void (*spdk_ftl_init_fn)(struct spdk_ftl_dev *dev, void *cb_arg, int status);
|
||||
|
||||
/**
|
||||
* Initialize the FTL on the given pair of bdevs - base and cache bdev.
|
||||
* Upon receiving a successful completion callback user is free to use I/O calls.
|
||||
*
|
||||
* \param conf configuration for new device
|
||||
* \param cb callback function to call when the device is created
|
||||
* \param cb_arg callback's argument
|
||||
*
|
||||
* \return 0 if initialization was started successfully, negative errno otherwise.
|
||||
*/
|
||||
int spdk_ftl_dev_init(const struct spdk_ftl_conf *conf, spdk_ftl_init_fn cb, void *cb_arg);
|
||||
|
||||
/**
|
||||
* Deinitialize and free given device.
|
||||
*
|
||||
* \param dev device
|
||||
* \param cb callback function to call when the device is freed
|
||||
* \param cb_arg callback's argument
|
||||
*
|
||||
* \return 0 if deinitialization was started successfully, negative errno otherwise.
|
||||
*/
|
||||
int spdk_ftl_dev_free(struct spdk_ftl_dev *dev, spdk_ftl_fn cb, void *cb_arg);
|
||||
|
||||
/**
|
||||
* Initialize FTL configuration structure with default values.
|
||||
*
|
||||
* \param conf FTL configuration to initialize
|
||||
*/
|
||||
void spdk_ftl_get_default_conf(struct spdk_ftl_conf *conf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -9,12 +9,16 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
SO_VER := 5
|
||||
SO_MINOR := 0
|
||||
|
||||
ifneq ($(strip $(SPDK_FTL_ZONE_EMU_BLOCKS)),)
|
||||
CFLAGS += -DSPDK_FTL_ZONE_EMU_BLOCKS=$(SPDK_FTL_ZONE_EMU_BLOCKS)
|
||||
endif
|
||||
|
||||
CFLAGS += -I.
|
||||
|
||||
FTL_SUBDIRS := mngt utils
|
||||
|
||||
C_SRCS = ftl_core.c
|
||||
C_SRCS += mngt/ftl_mngt.c
|
||||
C_SRCS = ftl_core.c ftl_init.c
|
||||
C_SRCS += mngt/ftl_mngt.c mngt/ftl_mngt_bdev.c mngt/ftl_mngt_shutdown.c mngt/ftl_mngt_startup.c
|
||||
C_SRCS += utils/ftl_conf.c
|
||||
|
||||
SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_ftl.map)
|
||||
|
@ -20,11 +20,8 @@
|
||||
#include "utils/ftl_log.h"
|
||||
|
||||
struct spdk_ftl_dev {
|
||||
/* Device instance */
|
||||
struct spdk_uuid uuid;
|
||||
|
||||
/* Device name */
|
||||
char *name;
|
||||
/* Configuration */
|
||||
struct spdk_ftl_conf conf;
|
||||
|
||||
/* Underlying device */
|
||||
struct spdk_bdev_desc *base_bdev_desc;
|
||||
@ -92,4 +89,33 @@ struct spdk_ftl_dev {
|
||||
TAILQ_HEAD(, ftl_io) wr_sq;
|
||||
};
|
||||
|
||||
static inline uint64_t
|
||||
ftl_get_num_blocks_in_band(const struct spdk_ftl_dev *dev)
|
||||
{
|
||||
return dev->num_blocks_in_band;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
ftl_get_num_zones_in_band(const struct spdk_ftl_dev *dev)
|
||||
{
|
||||
return dev->num_zones_in_band;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
ftl_get_num_blocks_in_zone(const struct spdk_ftl_dev *dev)
|
||||
{
|
||||
return dev->num_blocks_in_zone;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
ftl_get_write_unit_size(struct spdk_bdev *bdev)
|
||||
{
|
||||
if (spdk_bdev_is_zoned(bdev)) {
|
||||
return spdk_bdev_get_write_unit_size(bdev);
|
||||
}
|
||||
|
||||
/* TODO: this should be passed via input parameter */
|
||||
return 32;
|
||||
}
|
||||
|
||||
#endif /* FTL_CORE_H */
|
||||
|
207
lib/ftl/ftl_init.c
Normal file
207
lib/ftl/ftl_init.c
Normal file
@ -0,0 +1,207 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include "spdk/stdinc.h"
|
||||
#include "spdk/nvme.h"
|
||||
#include "spdk/thread.h"
|
||||
#include "spdk/string.h"
|
||||
#include "spdk/likely.h"
|
||||
#include "spdk/ftl.h"
|
||||
#include "spdk/likely.h"
|
||||
#include "spdk/string.h"
|
||||
#include "spdk/bdev_zone.h"
|
||||
#include "spdk/bdev_module.h"
|
||||
#include "spdk/config.h"
|
||||
|
||||
#include "ftl_core.h"
|
||||
#include "ftl_utils.h"
|
||||
#include "mngt/ftl_mngt.h"
|
||||
|
||||
struct ftl_dev_init_ctx {
|
||||
spdk_ftl_init_fn cb_fn;
|
||||
/* Callback's argument */
|
||||
void *cb_arg;
|
||||
};
|
||||
|
||||
struct ftl_dev_free_ctx {
|
||||
spdk_ftl_fn cb_fn;
|
||||
/* Callback's argument */
|
||||
void *cb_arg;
|
||||
};
|
||||
|
||||
static int
|
||||
init_core_thread(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
struct spdk_cpuset cpumask = {};
|
||||
|
||||
/*
|
||||
* If core mask is provided create core thread on first cpu that match with the mask,
|
||||
* otherwise use current user thread
|
||||
*/
|
||||
if (dev->conf.core_mask) {
|
||||
if (spdk_cpuset_parse(&cpumask, dev->conf.core_mask)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
dev->core_thread = spdk_thread_create("ftl_core_thread", &cpumask);
|
||||
} else {
|
||||
dev->core_thread = spdk_get_thread();
|
||||
}
|
||||
|
||||
if (dev->core_thread == NULL) {
|
||||
FTL_ERRLOG(dev, "Cannot create thread for mask %s\n", dev->conf.core_mask);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
exit_thread(void *ctx)
|
||||
{
|
||||
struct spdk_thread *thread = ctx;
|
||||
|
||||
spdk_thread_exit(thread);
|
||||
}
|
||||
|
||||
static void
|
||||
deinit_core_thread(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
if (dev->core_thread && dev->conf.core_mask) {
|
||||
spdk_thread_send_msg(dev->core_thread, exit_thread,
|
||||
dev->core_thread);
|
||||
dev->core_thread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_dev(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
deinit_core_thread(dev);
|
||||
ftl_conf_deinit(&dev->conf);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
static struct spdk_ftl_dev *
|
||||
allocate_dev(const struct spdk_ftl_conf *conf, int *error)
|
||||
{
|
||||
int rc;
|
||||
struct spdk_ftl_dev *dev = calloc(1, sizeof(*dev));
|
||||
|
||||
if (!dev) {
|
||||
FTL_ERRLOG(dev, "Cannot allocate FTL device\n");
|
||||
*error = -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = ftl_conf_init_dev(dev, conf);
|
||||
if (rc) {
|
||||
*error = rc;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = init_core_thread(dev);
|
||||
if (rc) {
|
||||
*error = rc;
|
||||
goto error;
|
||||
}
|
||||
|
||||
TAILQ_INIT(&dev->rd_sq);
|
||||
TAILQ_INIT(&dev->wr_sq);
|
||||
|
||||
return dev;
|
||||
error:
|
||||
free_dev(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
dev_init_cb(struct spdk_ftl_dev *dev, void *_ctx, int status)
|
||||
{
|
||||
struct ftl_dev_init_ctx *ctx = _ctx;
|
||||
|
||||
if (status) {
|
||||
free_dev(dev);
|
||||
dev = NULL;
|
||||
}
|
||||
ctx->cb_fn(dev, ctx->cb_arg, status);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int
|
||||
spdk_ftl_dev_init(const struct spdk_ftl_conf *conf, spdk_ftl_init_fn cb_fn, void *cb_arg)
|
||||
{
|
||||
int rc = -1;
|
||||
struct ftl_dev_init_ctx *ctx;
|
||||
struct spdk_ftl_dev *dev = NULL;
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
ctx->cb_fn = cb_fn;
|
||||
ctx->cb_arg = cb_arg;
|
||||
|
||||
dev = allocate_dev(conf, &rc);
|
||||
if (!dev) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ftl_mngt_call_dev_startup(dev, dev_init_cb, ctx);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free(ctx);
|
||||
free_dev(dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
dev_free_cb(struct spdk_ftl_dev *dev, void *_ctx, int status)
|
||||
{
|
||||
struct ftl_dev_free_ctx *ctx = _ctx;
|
||||
|
||||
if (!status) {
|
||||
free_dev(dev);
|
||||
}
|
||||
ctx->cb_fn(ctx->cb_arg, status);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int
|
||||
spdk_ftl_dev_free(struct spdk_ftl_dev *dev, spdk_ftl_fn cb_fn, void *cb_arg)
|
||||
{
|
||||
int rc = -1;
|
||||
struct ftl_dev_free_ctx *ctx;
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
ctx->cb_fn = cb_fn;
|
||||
ctx->cb_arg = cb_arg;
|
||||
|
||||
rc = ftl_mngt_call_dev_shutdown(dev, dev_free_cb, ctx);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
SPDK_LOG_REGISTER_COMPONENT(ftl_init)
|
@ -13,6 +13,8 @@
|
||||
|
||||
/* Marks address as invalid */
|
||||
#define FTL_ADDR_INVALID ((ftl_addr)-1)
|
||||
/* Smallest data unit size */
|
||||
#define FTL_BLOCK_SIZE 4096ULL
|
||||
|
||||
/*
|
||||
* This type represents address in the ftl address space. Values from 0 to based bdev size are
|
||||
|
@ -410,31 +410,34 @@ trace_step(struct spdk_ftl_dev *dev, struct ftl_mngt_step *step, bool rollback)
|
||||
FTL_NOTICELOG(dev, "\t status: %d\n", step->action.status);
|
||||
}
|
||||
|
||||
static void
|
||||
process_summary(struct ftl_mngt_process *mngt)
|
||||
{
|
||||
uint64_t duration;
|
||||
|
||||
if (mngt->silent) {
|
||||
return;
|
||||
}
|
||||
|
||||
duration = mngt->tsc_stop - mngt->tsc_start;
|
||||
FTL_NOTICELOG(mngt->dev, "Management process finished, "
|
||||
"name '%s', duration = %.3f ms, result %d\n",
|
||||
mngt->desc->name,
|
||||
tsc_to_ms(duration),
|
||||
mngt->status);
|
||||
}
|
||||
|
||||
static void
|
||||
finish_msg(void *ctx)
|
||||
{
|
||||
struct ftl_mngt_process *mngt = ctx;
|
||||
char *devname = NULL;
|
||||
|
||||
if (!mngt->silent && mngt->dev->conf.name) {
|
||||
/* the callback below can free the device so make a temp copy of the name */
|
||||
devname = strdup(mngt->dev->conf.name);
|
||||
}
|
||||
|
||||
mngt->caller.cb(mngt->dev, mngt->caller.cb_ctx, mngt->status);
|
||||
process_summary(mngt);
|
||||
|
||||
if (!mngt->silent) {
|
||||
/* TODO: refactor the logging macros to pass just the name instead of device */
|
||||
struct spdk_ftl_dev tmpdev = {
|
||||
.conf = {
|
||||
.name = devname
|
||||
}
|
||||
};
|
||||
|
||||
FTL_NOTICELOG(&tmpdev, "Management process finished, name '%s', duration = %.3f ms, result %d\n",
|
||||
mngt->desc->name,
|
||||
tsc_to_ms(mngt->tsc_stop - mngt->tsc_start),
|
||||
mngt->status);
|
||||
}
|
||||
free_mngt(mngt);
|
||||
free(devname);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -287,4 +287,33 @@ void ftl_mngt_call_process(struct ftl_mngt_process *mngt,
|
||||
void ftl_mngt_call_process_rollback(struct ftl_mngt_process *mngt,
|
||||
const struct ftl_mngt_process_desc *process);
|
||||
|
||||
/*
|
||||
* The specific management functions
|
||||
*/
|
||||
/**
|
||||
* @brief Starts up a FTL instance
|
||||
*
|
||||
* @param dev FTL device
|
||||
* @param cb Caller callback
|
||||
* @param cb_cntx Caller context
|
||||
*
|
||||
* @return Operation result
|
||||
* @retval 0 The operation successful has started
|
||||
* @retval Non-zero Startup failure
|
||||
*/
|
||||
int ftl_mngt_call_dev_startup(struct spdk_ftl_dev *dev, ftl_mngt_completion cb, void *cb_cntx);
|
||||
|
||||
/**
|
||||
* @brief Shuts down a FTL instance
|
||||
*
|
||||
* @param dev FTL device
|
||||
* @param cb Caller callback
|
||||
* @param cb_cntx Caller context
|
||||
*
|
||||
* @return Operation result
|
||||
* @retval 0 The operation successful has started
|
||||
* @retval Non-zero Shutdown failure
|
||||
*/
|
||||
int ftl_mngt_call_dev_shutdown(struct spdk_ftl_dev *dev, ftl_mngt_completion cb, void *cb_cntx);
|
||||
|
||||
#endif /* LIB_FTL_FTL_MNGT_H */
|
||||
|
250
lib/ftl/mngt/ftl_mngt_bdev.c
Normal file
250
lib/ftl/mngt/ftl_mngt_bdev.c
Normal file
@ -0,0 +1,250 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include "spdk/bdev_module.h"
|
||||
#include "spdk/ftl.h"
|
||||
|
||||
#include "ftl_internal.h"
|
||||
#include "ftl_mngt_steps.h"
|
||||
#include "ftl_internal.h"
|
||||
#include "ftl_core.h"
|
||||
#include "utils/ftl_defs.h"
|
||||
|
||||
#define MINIMUM_CACHE_SIZE_GIB 5
|
||||
#define MINIMUM_BASE_SIZE_GIB 20
|
||||
|
||||
/* Dummy bdev module used to to claim bdevs. */
|
||||
static struct spdk_bdev_module g_ftl_bdev_module = {
|
||||
.name = "ftl_lib",
|
||||
};
|
||||
|
||||
static inline size_t
|
||||
ftl_calculate_num_zones_in_band(struct spdk_bdev_desc *desc)
|
||||
{
|
||||
if (spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(desc))) {
|
||||
return spdk_bdev_get_optimal_open_zones(spdk_bdev_desc_get_bdev(desc));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
ftl_calculate_num_blocks_in_zone(struct spdk_bdev_desc *desc)
|
||||
{
|
||||
if (spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(desc))) {
|
||||
return spdk_bdev_get_zone_size(spdk_bdev_desc_get_bdev(desc));
|
||||
}
|
||||
|
||||
/* TODO: this should be passed via input parameter */
|
||||
#ifdef SPDK_FTL_ZONE_EMU_BLOCKS
|
||||
return SPDK_FTL_ZONE_EMU_BLOCKS;
|
||||
#else
|
||||
return (1ULL << 30) / FTL_BLOCK_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
ftl_calculate_num_blocks_in_band(struct spdk_bdev_desc *desc)
|
||||
{
|
||||
return ftl_calculate_num_zones_in_band(desc) * ftl_calculate_num_blocks_in_zone(desc);
|
||||
}
|
||||
|
||||
static void
|
||||
base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
|
||||
{
|
||||
switch (type) {
|
||||
case SPDK_BDEV_EVENT_REMOVE:
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ftl_mngt_open_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||
{
|
||||
uint32_t block_size;
|
||||
uint64_t num_blocks;
|
||||
const char *bdev_name = dev->conf.base_bdev;
|
||||
struct spdk_bdev *bdev;
|
||||
|
||||
if (spdk_bdev_open_ext(bdev_name, true, base_bdev_event_cb,
|
||||
dev, &dev->base_bdev_desc)) {
|
||||
FTL_ERRLOG(dev, "Unable to open bdev: %s\n", bdev_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
|
||||
|
||||
if (spdk_bdev_module_claim_bdev(bdev, dev->base_bdev_desc, &g_ftl_bdev_module)) {
|
||||
/* clear the desc so that we don't try to release the claim on cleanup */
|
||||
spdk_bdev_close(dev->base_bdev_desc);
|
||||
dev->base_bdev_desc = NULL;
|
||||
FTL_ERRLOG(dev, "Unable to claim bdev %s\n", bdev_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
block_size = spdk_bdev_get_block_size(bdev);
|
||||
if (block_size != FTL_BLOCK_SIZE) {
|
||||
FTL_ERRLOG(dev, "Unsupported block size (%"PRIu32")\n", block_size);
|
||||
goto error;
|
||||
}
|
||||
|
||||
num_blocks = spdk_bdev_get_num_blocks(bdev);
|
||||
|
||||
if (num_blocks * block_size < MINIMUM_BASE_SIZE_GIB * GiB) {
|
||||
FTL_ERRLOG(dev, "Bdev %s is too small, requires, at least %uGiB capacity\n",
|
||||
spdk_bdev_get_name(bdev), MINIMUM_BASE_SIZE_GIB);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->base_ioch = spdk_bdev_get_io_channel(dev->base_bdev_desc);
|
||||
if (!dev->base_ioch) {
|
||||
FTL_ERRLOG(dev, "Failed to create base bdev IO channel\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->xfer_size = ftl_get_write_unit_size(bdev);
|
||||
|
||||
/* TODO: validate size when base device VSS usage gets added */
|
||||
dev->md_size = spdk_bdev_get_md_size(bdev);
|
||||
|
||||
/* Cache frequently used values */
|
||||
dev->num_blocks_in_band = ftl_calculate_num_blocks_in_band(dev->base_bdev_desc);
|
||||
dev->num_zones_in_band = ftl_calculate_num_zones_in_band(dev->base_bdev_desc);
|
||||
dev->num_blocks_in_zone = ftl_calculate_num_blocks_in_zone(dev->base_bdev_desc);
|
||||
dev->is_zoned = spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
|
||||
|
||||
if (dev->is_zoned) {
|
||||
/* TODO - current FTL code isn't fully compatible with ZNS drives */
|
||||
FTL_ERRLOG(dev, "Creating FTL on Zoned devices is not supported\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->num_bands = num_blocks / ftl_get_num_blocks_in_band(dev);
|
||||
|
||||
/* Save a band worth of space for metadata */
|
||||
dev->num_bands--;
|
||||
|
||||
ftl_mngt_next_step(mngt);
|
||||
return;
|
||||
error:
|
||||
ftl_mngt_fail_step(mngt);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_mngt_close_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||
{
|
||||
if (dev->base_ioch) {
|
||||
spdk_put_io_channel(dev->base_ioch);
|
||||
dev->base_ioch = NULL;
|
||||
}
|
||||
|
||||
if (dev->base_bdev_desc) {
|
||||
struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
|
||||
|
||||
spdk_bdev_module_release_bdev(bdev);
|
||||
spdk_bdev_close(dev->base_bdev_desc);
|
||||
|
||||
dev->base_bdev_desc = NULL;
|
||||
}
|
||||
|
||||
ftl_mngt_next_step(mngt);
|
||||
}
|
||||
|
||||
static void
|
||||
nv_cache_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
|
||||
{
|
||||
switch (type) {
|
||||
case SPDK_BDEV_EVENT_REMOVE:
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ftl_mngt_open_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||
{
|
||||
struct spdk_bdev *bdev;
|
||||
const char *bdev_name = dev->conf.cache_bdev;
|
||||
|
||||
if (spdk_bdev_open_ext(bdev_name, true, nv_cache_bdev_event_cb, dev,
|
||||
&dev->cache_bdev_desc)) {
|
||||
FTL_ERRLOG(dev, "Unable to open bdev: %s\n", bdev_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
bdev = spdk_bdev_desc_get_bdev(dev->cache_bdev_desc);
|
||||
|
||||
if (spdk_bdev_module_claim_bdev(bdev, dev->cache_bdev_desc, &g_ftl_bdev_module)) {
|
||||
/* clear the desc so that we don't try to release the claim on cleanup */
|
||||
spdk_bdev_close(dev->cache_bdev_desc);
|
||||
dev->cache_bdev_desc = NULL;
|
||||
FTL_ERRLOG(dev, "Unable to claim bdev %s\n", bdev_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
FTL_NOTICELOG(dev, "Using %s as write buffer cache\n", spdk_bdev_get_name(bdev));
|
||||
|
||||
if (spdk_bdev_get_block_size(bdev) != FTL_BLOCK_SIZE) {
|
||||
FTL_ERRLOG(dev, "Unsupported block size (%d)\n",
|
||||
spdk_bdev_get_block_size(bdev));
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->cache_ioch = spdk_bdev_get_io_channel(dev->cache_bdev_desc);
|
||||
if (!dev->cache_ioch) {
|
||||
FTL_ERRLOG(dev, "Failed to create cache IO channel for NV Cache\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!spdk_bdev_is_md_separate(bdev)) {
|
||||
FTL_ERRLOG(dev, "Bdev %s doesn't support separate metadata buffer IO\n",
|
||||
spdk_bdev_get_name(bdev));
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->cache_md_size = spdk_bdev_get_md_size(bdev);
|
||||
|
||||
if (spdk_bdev_get_dif_type(bdev) != SPDK_DIF_DISABLE) {
|
||||
FTL_ERRLOG(dev, "Unsupported DIF type used by bdev %s\n",
|
||||
spdk_bdev_get_name(bdev));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bdev->blockcnt * bdev->blocklen < MINIMUM_CACHE_SIZE_GIB * GiB) {
|
||||
FTL_ERRLOG(dev, "Bdev %s is too small, requires, at least %uGiB capacity\n",
|
||||
spdk_bdev_get_name(bdev), MINIMUM_CACHE_SIZE_GIB);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ftl_mngt_next_step(mngt);
|
||||
return;
|
||||
error:
|
||||
ftl_mngt_fail_step(mngt);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_mngt_close_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||
{
|
||||
if (dev->cache_ioch) {
|
||||
spdk_put_io_channel(dev->cache_ioch);
|
||||
dev->cache_ioch = NULL;
|
||||
}
|
||||
|
||||
if (dev->cache_bdev_desc) {
|
||||
struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->cache_bdev_desc);
|
||||
|
||||
spdk_bdev_module_release_bdev(bdev);
|
||||
spdk_bdev_close(dev->cache_bdev_desc);
|
||||
|
||||
dev->cache_bdev_desc = NULL;
|
||||
}
|
||||
|
||||
ftl_mngt_next_step(mngt);
|
||||
}
|
26
lib/ftl/mngt/ftl_mngt_shutdown.c
Normal file
26
lib/ftl/mngt/ftl_mngt_shutdown.c
Normal file
@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include "ftl_core.h"
|
||||
#include "ftl_mngt.h"
|
||||
#include "ftl_mngt_steps.h"
|
||||
|
||||
static const struct ftl_mngt_process_desc desc_shutdown = {
|
||||
.name = "FTL shutdown",
|
||||
.error_handler = ftl_mngt_rollback_device,
|
||||
.steps = {
|
||||
{
|
||||
.name = "Rollback FTL device",
|
||||
.action = ftl_mngt_rollback_device
|
||||
},
|
||||
{}
|
||||
}
|
||||
};
|
||||
|
||||
int
|
||||
ftl_mngt_call_dev_shutdown(struct spdk_ftl_dev *dev, ftl_mngt_completion cb, void *cb_cntx)
|
||||
{
|
||||
return ftl_mngt_process_execute(dev, &desc_shutdown, cb, cb_cntx);
|
||||
}
|
39
lib/ftl/mngt/ftl_mngt_startup.c
Normal file
39
lib/ftl/mngt/ftl_mngt_startup.c
Normal file
@ -0,0 +1,39 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include "ftl_core.h"
|
||||
#include "ftl_mngt.h"
|
||||
#include "ftl_mngt_steps.h"
|
||||
|
||||
static const struct ftl_mngt_process_desc desc_startup;
|
||||
|
||||
static const struct ftl_mngt_process_desc desc_startup = {
|
||||
.name = "FTL startup",
|
||||
.steps = {
|
||||
{
|
||||
.name = "Open base bdev",
|
||||
.action = ftl_mngt_open_base_bdev,
|
||||
.cleanup = ftl_mngt_close_base_bdev
|
||||
},
|
||||
{
|
||||
.name = "Open cache bdev",
|
||||
.action = ftl_mngt_open_cache_bdev,
|
||||
.cleanup = ftl_mngt_close_cache_bdev
|
||||
},
|
||||
{}
|
||||
}
|
||||
};
|
||||
|
||||
int
|
||||
ftl_mngt_call_dev_startup(struct spdk_ftl_dev *dev, ftl_mngt_completion cb, void *cb_cntx)
|
||||
{
|
||||
return ftl_mngt_process_execute(dev, &desc_startup, cb, cb_cntx);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_mngt_rollback_device(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||
{
|
||||
ftl_mngt_call_process_rollback(mngt, &desc_startup);
|
||||
}
|
21
lib/ftl/mngt/ftl_mngt_steps.h
Normal file
21
lib/ftl/mngt/ftl_mngt_steps.h
Normal file
@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef FTL_MNGT_STEPS_H
|
||||
#define FTL_MNGT_STEPS_H
|
||||
|
||||
#include "ftl_mngt.h"
|
||||
|
||||
void ftl_mngt_open_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||
|
||||
void ftl_mngt_close_base_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_rollback_device(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||
|
||||
#endif /* FTL_MNGT_STEPS_H */
|
@ -1,5 +1,10 @@
|
||||
{
|
||||
global:
|
||||
|
||||
# public functions
|
||||
spdk_ftl_dev_init;
|
||||
spdk_ftl_dev_free;
|
||||
spdk_ftl_get_default_conf;
|
||||
|
||||
local: *;
|
||||
};
|
||||
|
@ -7,14 +7,33 @@
|
||||
#include "ftl_conf.h"
|
||||
#include "ftl_core.h"
|
||||
|
||||
static const struct spdk_ftl_conf g_default_conf = {
|
||||
/* 20% spare blocks */
|
||||
.overprovisioning = 20,
|
||||
/* IO pool size per user thread (this should be adjusted to thread IO qdepth) */
|
||||
.user_io_pool_size = 2048,
|
||||
};
|
||||
|
||||
void
|
||||
spdk_ftl_get_default_conf(struct spdk_ftl_conf *conf)
|
||||
{
|
||||
*conf = g_default_conf;
|
||||
}
|
||||
|
||||
int
|
||||
ftl_conf_cpy(struct spdk_ftl_conf *dst, const struct spdk_ftl_conf *src)
|
||||
{
|
||||
char *name = NULL;
|
||||
char *core_mask = NULL;
|
||||
char *l2p_path = 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) {
|
||||
@ -34,18 +53,15 @@ ftl_conf_cpy(struct spdk_ftl_conf *dst, const struct spdk_ftl_conf *src)
|
||||
}
|
||||
}
|
||||
|
||||
free(dst->core_mask);
|
||||
free(dst->base_bdev);
|
||||
free(dst->cache_bdev);
|
||||
|
||||
*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(l2p_path);
|
||||
free(base_bdev);
|
||||
free(cache_bdev);
|
||||
return -ENOMEM;
|
||||
@ -54,7 +70,34 @@ error:
|
||||
void
|
||||
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 = ftl_conf_cpy(&dev->conf, conf);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -12,4 +12,6 @@ int ftl_conf_cpy(struct spdk_ftl_conf *dst, const struct spdk_ftl_conf *src);
|
||||
|
||||
void ftl_conf_deinit(struct spdk_ftl_conf *conf);
|
||||
|
||||
int ftl_conf_init_dev(struct spdk_ftl_dev *dev, const struct spdk_ftl_conf *conf);
|
||||
|
||||
#endif /* FTL_DEFS_H */
|
||||
|
@ -14,7 +14,7 @@
|
||||
{ \
|
||||
spdk_log(SPDK_LOG_##type, __FILE__, __LINE__, __func__, "[FTL] "format, ## __VA_ARGS__); \
|
||||
} else { \
|
||||
spdk_log(SPDK_LOG_##type, __FILE__, __LINE__, __func__, "[FTL][%s] "format, (dev)->name, ## __VA_ARGS__); \
|
||||
spdk_log(SPDK_LOG_##type, __FILE__, __LINE__, __func__, "[FTL][%s] "format, (dev)->conf.name, ## __VA_ARGS__); \
|
||||
} \
|
||||
|
||||
#define FTL_ERRLOG(dev, format, ...) \
|
||||
|
@ -60,7 +60,7 @@ DEPDIRS-blobfs := log thread blob trace util
|
||||
DEPDIRS-event := log util thread $(JSON_LIBS) trace init
|
||||
DEPDIRS-init := jsonrpc json log rpc thread util
|
||||
|
||||
DEPDIRS-ftl := log thread
|
||||
DEPDIRS-ftl := log util thread bdev
|
||||
DEPDIRS-nbd := log util thread $(JSON_LIBS) bdev
|
||||
DEPDIRS-nvmf := accel log sock util nvme thread $(JSON_LIBS) trace bdev
|
||||
ifeq ($(CONFIG_RDMA),y)
|
||||
|
Loading…
Reference in New Issue
Block a user