From c69529d45292d58e875ee307dde42b51948852ce Mon Sep 17 00:00:00 2001 From: Konrad Sztyber Date: Thu, 30 May 2019 15:08:45 +0200 Subject: [PATCH] lib/ftl: block nv_cache until header is written After filling whole non-volatile cache, block all further writes until the header with metadata is written. This means that metadata stored on the device will always be up-to-date with the most recent write sequence. Change-Id: I15b724b52814289622374ce77e5c3b23173a75c6 Signed-off-by: Konrad Sztyber Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/458097 Tested-by: SPDK CI Jenkins Reviewed-by: Darek Stojaczyk Reviewed-by: Ben Walker Reviewed-by: Shuhei Matsumoto Reviewed-by: Wojciech Malikowski --- lib/ftl/ftl_core.c | 51 ++++++++++++++++++++++++++++++++++++++++++- lib/ftl/ftl_core.h | 4 ++++ lib/ftl/ftl_init.c | 10 +++++++++ lib/ftl/ftl_restore.c | 4 ++++ 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/lib/ftl/ftl_core.c b/lib/ftl/ftl_core.c index 62d1938b6..00afa83b1 100644 --- a/lib/ftl/ftl_core.c +++ b/lib/ftl/ftl_core.c @@ -39,6 +39,7 @@ #include "spdk/string.h" #include "spdk_internal/log.h" #include "spdk/ftl.h" +#include "spdk/crc32.h" #include "ftl_core.h" #include "ftl_band.h" @@ -944,6 +945,52 @@ ftl_process_flush(struct spdk_ftl_dev *dev, struct ftl_rwb_batch *batch) } } +static void +ftl_nv_cache_wrap_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) +{ + struct ftl_nv_cache *nv_cache = cb_arg; + + if (!success) { + SPDK_ERRLOG("Unable to write non-volatile cache metadata header\n"); + /* TODO: go into read-only mode */ + assert(0); + } + + pthread_spin_lock(&nv_cache->lock); + nv_cache->ready = true; + pthread_spin_unlock(&nv_cache->lock); + + spdk_bdev_free_io(bdev_io); +} + +static void +ftl_nv_cache_wrap(void *ctx) +{ + struct spdk_ftl_dev *dev = ctx; + struct ftl_nv_cache *nv_cache = &dev->nv_cache; + struct ftl_nv_cache_header *hdr = nv_cache->dma_buf; + struct ftl_io_channel *ioch; + struct spdk_bdev *bdev; + int rc; + + ioch = spdk_io_channel_get_ctx(dev->ioch); + bdev = spdk_bdev_desc_get_bdev(nv_cache->bdev_desc); + + hdr->uuid = dev->uuid; + hdr->size = spdk_bdev_get_num_blocks(bdev); + hdr->version = FTL_NV_CACHE_HEADER_VERSION; + hdr->checksum = spdk_crc32c_update(hdr, offsetof(struct ftl_nv_cache_header, checksum), 0); + + rc = spdk_bdev_write_blocks(nv_cache->bdev_desc, ioch->cache_ioch, hdr, 0, 1, + ftl_nv_cache_wrap_cb, nv_cache); + if (spdk_unlikely(rc != 0)) { + SPDK_ERRLOG("Unable to write non-volatile cache metadata header: %s\n", + spdk_strerror(-rc)); + /* TODO: go into read-only mode */ + assert(0); + } +} + static uint64_t ftl_reserve_nv_cache(struct ftl_nv_cache *nv_cache, size_t *num_lbks) { @@ -954,7 +1001,7 @@ ftl_reserve_nv_cache(struct ftl_nv_cache *nv_cache, size_t *num_lbks) cache_size = spdk_bdev_get_num_blocks(bdev); pthread_spin_lock(&nv_cache->lock); - if (spdk_unlikely(nv_cache->num_available == 0)) { + if (spdk_unlikely(nv_cache->num_available == 0 || !nv_cache->ready)) { goto out; } @@ -973,6 +1020,8 @@ ftl_reserve_nv_cache(struct ftl_nv_cache *nv_cache, size_t *num_lbks) if (nv_cache->current_addr == spdk_bdev_get_num_blocks(bdev)) { nv_cache->current_addr = FTL_NV_CACHE_DATA_OFFSET; + nv_cache->ready = false; + spdk_thread_send_msg(ftl_get_core_thread(dev), ftl_nv_cache_wrap, dev); } out: pthread_spin_unlock(&nv_cache->lock); diff --git a/lib/ftl/ftl_core.h b/lib/ftl/ftl_core.h index deb3aba1f..87ab72f10 100644 --- a/lib/ftl/ftl_core.h +++ b/lib/ftl/ftl_core.h @@ -112,8 +112,12 @@ struct ftl_nv_cache { uint64_t num_available; /* Maximum number of blocks */ uint64_t num_data_blocks; + /* Indicates that the data can be written to the cache */ + bool ready; /* Metadata pool */ struct spdk_mempool *md_pool; + /* DMA buffer for writing the header */ + void *dma_buf; /* Cache lock */ pthread_spinlock_t lock; }; diff --git a/lib/ftl/ftl_init.c b/lib/ftl/ftl_init.c index 837951fce..95b738730 100644 --- a/lib/ftl/ftl_init.c +++ b/lib/ftl/ftl_init.c @@ -557,6 +557,12 @@ ftl_dev_init_nv_cache(struct spdk_ftl_dev *dev, struct spdk_bdev_desc *bdev_desc return -1; } + nv_cache->dma_buf = spdk_dma_zmalloc(FTL_BLOCK_SIZE, spdk_bdev_get_buf_align(bdev), NULL); + if (!nv_cache->dma_buf) { + SPDK_ERRLOG("Memory allocation failure\n"); + return -1; + } + if (pthread_spin_init(&nv_cache->lock, PTHREAD_PROCESS_PRIVATE)) { SPDK_ERRLOG("Failed to initialize cache lock\n"); return -1; @@ -566,6 +572,7 @@ ftl_dev_init_nv_cache(struct spdk_ftl_dev *dev, struct spdk_bdev_desc *bdev_desc nv_cache->current_addr = FTL_NV_CACHE_DATA_OFFSET; nv_cache->num_data_blocks = spdk_bdev_get_num_blocks(bdev) - 1; nv_cache->num_available = nv_cache->num_data_blocks; + nv_cache->ready = false; return 0; } @@ -867,6 +874,7 @@ ftl_write_nv_cache_md_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_ar return; } + dev->nv_cache.ready = true; ftl_init_complete(dev); } @@ -1236,6 +1244,8 @@ ftl_dev_free_sync(struct spdk_ftl_dev *dev) } } + spdk_dma_free(dev->nv_cache.dma_buf); + spdk_mempool_free(dev->lba_pool); spdk_mempool_free(dev->nv_cache.md_pool); if (dev->lba_request_pool) { diff --git a/lib/ftl/ftl_restore.c b/lib/ftl/ftl_restore.c index 0b7de5105..378674b2c 100644 --- a/lib/ftl/ftl_restore.c +++ b/lib/ftl/ftl_restore.c @@ -421,6 +421,10 @@ ftl_nv_cache_header_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) rc = -ENOTRECOVERABLE; goto out; } + + pthread_spin_lock(&nv_cache->lock); + nv_cache->ready = true; + pthread_spin_unlock(&nv_cache->lock); out: ftl_restore_complete(restore, rc); spdk_bdev_free_io(bdev_io);