From c139a7d9ba8edb15fbc48bff4b48d056bbbe3ee2 Mon Sep 17 00:00:00 2001 From: Konrad Sztyber Date: Tue, 26 Mar 2019 16:33:45 +0100 Subject: [PATCH] lib/ftl: persistent cache initialization Change-Id: I608d420bd115a70d60ee6995220dbfafb7a00731 Signed-off-by: Konrad Sztyber Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/449242 Tested-by: SPDK CI Jenkins Reviewed-by: Darek Stojaczyk Reviewed-by: Jim Harris --- lib/ftl/ftl_core.c | 2 +- lib/ftl/ftl_core.h | 16 +++++- lib/ftl/ftl_init.c | 119 ++++++++++++++++++++++++++++++++++++--------- lib/ftl/ftl_io.h | 3 +- 4 files changed, 114 insertions(+), 26 deletions(-) diff --git a/lib/ftl/ftl_core.c b/lib/ftl/ftl_core.c index 1e61a9acc..96a4b1925 100644 --- a/lib/ftl/ftl_core.c +++ b/lib/ftl/ftl_core.c @@ -1400,7 +1400,7 @@ spdk_ftl_dev_get_attrs(const struct spdk_ftl_dev *dev, struct spdk_ftl_attrs *at attrs->lbk_cnt = dev->num_lbas; attrs->lbk_size = FTL_BLOCK_SIZE; attrs->range = dev->range; - attrs->cache_bdev_desc = dev->cache_bdev_desc; + attrs->cache_bdev_desc = dev->nv_cache.bdev_desc; } static void diff --git a/lib/ftl/ftl_core.h b/lib/ftl/ftl_core.h index e2c8a0440..1dc35fad3 100644 --- a/lib/ftl/ftl_core.h +++ b/lib/ftl/ftl_core.h @@ -103,6 +103,17 @@ struct ftl_global_md { uint64_t num_lbas; }; +struct ftl_nv_cache { + /* Write buffer cache bdev */ + struct spdk_bdev_desc *bdev_desc; + /* Write pointer */ + uint64_t current_addr; + /* Number of available blocks left */ + uint64_t num_available; + /* Cache lock */ + pthread_spinlock_t lock; +}; + struct spdk_ftl_dev { /* Device instance */ struct spdk_uuid uuid; @@ -137,8 +148,9 @@ struct spdk_ftl_dev { struct spdk_nvme_ns *ns; /* NVMe transport ID */ struct spdk_nvme_transport_id trid; - /* Write buffer cache */ - struct spdk_bdev_desc *cache_bdev_desc; + + /* Non-volatile write buffer cache */ + struct ftl_nv_cache nv_cache; /* LBA map memory pool */ struct spdk_mempool *lba_pool; diff --git a/lib/ftl/ftl_init.c b/lib/ftl/ftl_init.c index dca259aca..daaabf213 100644 --- a/lib/ftl/ftl_init.c +++ b/lib/ftl/ftl_init.c @@ -452,6 +452,46 @@ ftl_dev_nvme_init(struct spdk_ftl_dev *dev, const struct spdk_ftl_dev_init_opts return 0; } +static int +ftl_dev_init_nv_cache(struct spdk_ftl_dev *dev, struct spdk_bdev_desc *bdev_desc) +{ + struct spdk_bdev *bdev; + + if (!bdev_desc) { + return 0; + } + + bdev = spdk_bdev_desc_get_bdev(bdev_desc); + SPDK_INFOLOG(SPDK_LOG_FTL_INIT, "Using %s as write buffer cache\n", + spdk_bdev_get_name(bdev)); + + if (spdk_bdev_get_block_size(bdev) != FTL_BLOCK_SIZE) { + SPDK_ERRLOG("Unsupported block size (%d)\n", spdk_bdev_get_block_size(bdev)); + return -1; + } + + /* The cache needs to be capable of storing at least two full bands. This requirement comes + * from the fact that cache works as a protection against power loss, so before the data + * inside the cache can be overwritten, the band it's stored on has to be closed. + */ + if (spdk_bdev_get_num_blocks(bdev) < ftl_num_band_lbks(dev) * 2) { + SPDK_ERRLOG("Insufficient number of blocks for write buffer cache(%"PRIu64"\n", + spdk_bdev_get_num_blocks(bdev)); + return -1; + } + + if (pthread_spin_init(&dev->nv_cache.lock, PTHREAD_PROCESS_PRIVATE)) { + SPDK_ERRLOG("Failed to initialize cache lock\n"); + return -1; + } + + dev->nv_cache.bdev_desc = bdev_desc; + dev->nv_cache.current_addr = 0; + dev->nv_cache.num_available = spdk_bdev_get_num_blocks(bdev); + + return 0; +} + void spdk_ftl_conf_init_defaults(struct spdk_ftl_conf *conf) { @@ -790,31 +830,61 @@ ftl_restore_state(struct spdk_ftl_dev *dev, const struct spdk_ftl_dev_init_opts static int ftl_io_channel_create_cb(void *io_device, void *ctx) { - struct ftl_io_channel *ch = ctx; - char mempool_name[32]; struct spdk_ftl_dev *dev = io_device; + struct ftl_io_channel *ioch = ctx; + char mempool_name[32]; - snprintf(mempool_name, sizeof(mempool_name), "ftl_io_%p", ch); - ch->elem_size = sizeof(struct ftl_md_io); - ch->io_pool = spdk_mempool_create(mempool_name, - dev->conf.user_io_pool_size, - ch->elem_size, - 0, - SPDK_ENV_SOCKET_ID_ANY); - - if (!ch->io_pool) { + snprintf(mempool_name, sizeof(mempool_name), "ftl_io_%p", ioch); + ioch->cache_ioch = NULL; + ioch->elem_size = sizeof(struct ftl_md_io); + ioch->io_pool = spdk_mempool_create(mempool_name, + dev->conf.user_io_pool_size, + ioch->elem_size, + 0, + SPDK_ENV_SOCKET_ID_ANY); + if (!ioch->io_pool) { + SPDK_ERRLOG("Failed to create IO channel's IO pool\n"); return -1; } + if (dev->nv_cache.bdev_desc) { + ioch->cache_ioch = spdk_bdev_get_io_channel(dev->nv_cache.bdev_desc); + if (!ioch->cache_ioch) { + SPDK_ERRLOG("Failed to create cache IO channel\n"); + spdk_mempool_free(ioch->io_pool); + return -1; + } + } + return 0; } static void ftl_io_channel_destroy_cb(void *io_device, void *ctx) { - struct ftl_io_channel *ch = ctx; + struct ftl_io_channel *ioch = ctx; - spdk_mempool_free(ch->io_pool); + spdk_mempool_free(ioch->io_pool); + + if (ioch->cache_ioch) { + spdk_put_io_channel(ioch->cache_ioch); + } +} + +static int +ftl_dev_init_io_channel(struct spdk_ftl_dev *dev) +{ + spdk_io_device_register(dev, ftl_io_channel_create_cb, ftl_io_channel_destroy_cb, + sizeof(struct ftl_io_channel), + NULL); + + dev->ioch = spdk_get_io_channel(dev); + if (!dev->ioch) { + spdk_io_device_unregister(dev, NULL); + return -1; + } + + return 0; } int @@ -832,18 +902,12 @@ spdk_ftl_dev_init(const struct spdk_ftl_dev_init_opts *_opts, spdk_ftl_init_fn c opts.conf = &g_default_conf; } - spdk_io_device_register(dev, ftl_io_channel_create_cb, ftl_io_channel_destroy_cb, - sizeof(struct ftl_io_channel), - NULL); - TAILQ_INIT(&dev->retry_queue); dev->conf = *opts.conf; - dev->ioch = spdk_get_io_channel(dev); dev->init_cb = cb; dev->init_arg = cb_arg; dev->range = opts.range; dev->limit = SPDK_FTL_LIMIT_MAX; - dev->cache_bdev_desc = opts.cache_bdev_desc; dev->name = strdup(opts.name); if (!dev->name) { @@ -883,6 +947,11 @@ spdk_ftl_dev_init(const struct spdk_ftl_dev_init_opts *_opts, spdk_ftl_init_fn c goto fail_sync; } + if (ftl_dev_init_nv_cache(dev, opts.cache_bdev_desc)) { + SPDK_ERRLOG("Unable to initialize persistent cache\n"); + goto fail_sync; + } + dev->rwb = ftl_rwb_init(&dev->conf, dev->geo.ws_opt, dev->md_size); if (!dev->rwb) { SPDK_ERRLOG("Unable to initialize rwb structures\n"); @@ -895,6 +964,11 @@ spdk_ftl_dev_init(const struct spdk_ftl_dev_init_opts *_opts, spdk_ftl_init_fn c goto fail_sync; } + if (ftl_dev_init_io_channel(dev)) { + SPDK_ERRLOG("Unable to initialize IO channels\n"); + goto fail_sync; + } + if (ftl_dev_init_threads(dev, &opts)) { SPDK_ERRLOG("Unable to initialize device threads\n"); goto fail_sync; @@ -905,7 +979,6 @@ spdk_ftl_dev_init(const struct spdk_ftl_dev_init_opts *_opts, spdk_ftl_init_fn c SPDK_ERRLOG("Failed to setup initial state of the device\n"); goto fail_async; } - } else { if (ftl_restore_state(dev, &opts)) { SPDK_ERRLOG("Unable to restore device's state from the SSD\n"); @@ -952,8 +1025,10 @@ ftl_dev_free_sync(struct spdk_ftl_dev *dev) ftl_dev_dump_bands(dev); ftl_dev_dump_stats(dev); - spdk_put_io_channel(dev->ioch); - spdk_io_device_unregister(dev, NULL); + if (dev->ioch) { + spdk_put_io_channel(dev->ioch); + spdk_io_device_unregister(dev, NULL); + } if (dev->bands) { for (i = 0; i < ftl_dev_num_bands(dev); ++i) { diff --git a/lib/ftl/ftl_io.h b/lib/ftl/ftl_io.h index 61b7ea7b7..bf8a1d419 100644 --- a/lib/ftl/ftl_io.h +++ b/lib/ftl/ftl_io.h @@ -129,9 +129,10 @@ struct ftl_cb { struct ftl_io_channel { /* IO pool element size */ size_t elem_size; - /* IO pool */ struct spdk_mempool *io_pool; + /* Persistent cache IO channel */ + struct spdk_io_channel *cache_ioch; }; /* General IO descriptor */