diff --git a/include/spdk/ftl.h b/include/spdk/ftl.h index 3ae8c3bff..f30700b5f 100644 --- a/include/spdk/ftl.h +++ b/include/spdk/ftl.h @@ -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 diff --git a/lib/ftl/Makefile b/lib/ftl/Makefile index aeb376ad2..af71bdf97 100644 --- a/lib/ftl/Makefile +++ b/lib/ftl/Makefile @@ -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) diff --git a/lib/ftl/ftl_core.h b/lib/ftl/ftl_core.h index 922887168..1fc6da0e2 100644 --- a/lib/ftl/ftl_core.h +++ b/lib/ftl/ftl_core.h @@ -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 */ diff --git a/lib/ftl/ftl_init.c b/lib/ftl/ftl_init.c new file mode 100644 index 000000000..92f6157b8 --- /dev/null +++ b/lib/ftl/ftl_init.c @@ -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) diff --git a/lib/ftl/ftl_internal.h b/lib/ftl/ftl_internal.h index 534444e0f..2e978e38e 100644 --- a/lib/ftl/ftl_internal.h +++ b/lib/ftl/ftl_internal.h @@ -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 diff --git a/lib/ftl/mngt/ftl_mngt.c b/lib/ftl/mngt/ftl_mngt.c index ca61acc58..b67b1eafb 100644 --- a/lib/ftl/mngt/ftl_mngt.c +++ b/lib/ftl/mngt/ftl_mngt.c @@ -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 diff --git a/lib/ftl/mngt/ftl_mngt.h b/lib/ftl/mngt/ftl_mngt.h index b78a6f79b..3484748b8 100644 --- a/lib/ftl/mngt/ftl_mngt.h +++ b/lib/ftl/mngt/ftl_mngt.h @@ -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 */ diff --git a/lib/ftl/mngt/ftl_mngt_bdev.c b/lib/ftl/mngt/ftl_mngt_bdev.c new file mode 100644 index 000000000..b209773c6 --- /dev/null +++ b/lib/ftl/mngt/ftl_mngt_bdev.c @@ -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); +} diff --git a/lib/ftl/mngt/ftl_mngt_shutdown.c b/lib/ftl/mngt/ftl_mngt_shutdown.c new file mode 100644 index 000000000..7f4f014a4 --- /dev/null +++ b/lib/ftl/mngt/ftl_mngt_shutdown.c @@ -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); +} diff --git a/lib/ftl/mngt/ftl_mngt_startup.c b/lib/ftl/mngt/ftl_mngt_startup.c new file mode 100644 index 000000000..c471cbd88 --- /dev/null +++ b/lib/ftl/mngt/ftl_mngt_startup.c @@ -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); +} diff --git a/lib/ftl/mngt/ftl_mngt_steps.h b/lib/ftl/mngt/ftl_mngt_steps.h new file mode 100644 index 000000000..8bda2069f --- /dev/null +++ b/lib/ftl/mngt/ftl_mngt_steps.h @@ -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 */ diff --git a/lib/ftl/spdk_ftl.map b/lib/ftl/spdk_ftl.map index 78b0dd0e7..0f2ee71cf 100644 --- a/lib/ftl/spdk_ftl.map +++ b/lib/ftl/spdk_ftl.map @@ -1,5 +1,10 @@ { + global: + # public functions + spdk_ftl_dev_init; + spdk_ftl_dev_free; + spdk_ftl_get_default_conf; local: *; }; diff --git a/lib/ftl/utils/ftl_conf.c b/lib/ftl/utils/ftl_conf.c index 0d7c552d7..30c0b851a 100644 --- a/lib/ftl/utils/ftl_conf.c +++ b/lib/ftl/utils/ftl_conf.c @@ -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; +} diff --git a/lib/ftl/utils/ftl_conf.h b/lib/ftl/utils/ftl_conf.h index a14e3d1fe..b399cc218 100644 --- a/lib/ftl/utils/ftl_conf.h +++ b/lib/ftl/utils/ftl_conf.h @@ -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 */ diff --git a/lib/ftl/utils/ftl_log.h b/lib/ftl/utils/ftl_log.h index ab0f5df10..65ce50dfb 100644 --- a/lib/ftl/utils/ftl_log.h +++ b/lib/ftl/utils/ftl_log.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, ...) \ diff --git a/mk/spdk.lib_deps.mk b/mk/spdk.lib_deps.mk index faaf0cebb..59529ebd5 100644 --- a/mk/spdk.lib_deps.mk +++ b/mk/spdk.lib_deps.mk @@ -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)