From 77ddc70e1cc108d304a4a86f00cc0903aa9f8138 Mon Sep 17 00:00:00 2001 From: Konrad Sztyber Date: Thu, 30 May 2019 08:46:14 +0200 Subject: [PATCH] lib/ftl: restore non-volatile cache's metadata When restoring the device, read the first block of the non-volatile cache containing its metadata header and verify that it's indeed a device that was used as write cache. Change-Id: Idf113a9e8eb73160a2d9e6e882c9e026d3fafb3e Signed-off-by: Konrad Sztyber Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/458095 Tested-by: SPDK CI Jenkins Reviewed-by: Mateusz Kozlowski Reviewed-by: Darek Stojaczyk Reviewed-by: Ben Walker Reviewed-by: Shuhei Matsumoto --- lib/ftl/ftl_restore.c | 93 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/lib/ftl/ftl_restore.c b/lib/ftl/ftl_restore.c index 2831d271b..0b7de5105 100644 --- a/lib/ftl/ftl_restore.c +++ b/lib/ftl/ftl_restore.c @@ -36,6 +36,7 @@ #include "spdk/util.h" #include "spdk/likely.h" #include "spdk/string.h" +#include "spdk/crc32.h" #include "ftl_core.h" #include "ftl_band.h" @@ -371,6 +372,91 @@ ftl_restore_next_band(struct ftl_restore *restore) return NULL; } +static void +ftl_nv_cache_header_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) +{ + struct ftl_restore *restore = cb_arg; + struct spdk_ftl_dev *dev = restore->dev; + struct spdk_bdev *bdev; + struct ftl_nv_cache *nv_cache = &dev->nv_cache; + struct ftl_nv_cache_header *hdr; + struct iovec *iov = NULL; + int rc = 0, iov_cnt = 0; + uint32_t checksum; + + bdev = spdk_bdev_desc_get_bdev(nv_cache->bdev_desc); + spdk_bdev_io_get_iovec(bdev_io, &iov, &iov_cnt); + hdr = iov[0].iov_base; + + if (!success) { + SPDK_ERRLOG("Unable to read non-volatile cache metadata header\n"); + rc = -ENOTRECOVERABLE; + goto out; + } + + checksum = spdk_crc32c_update(hdr, offsetof(struct ftl_nv_cache_header, checksum), 0); + if (checksum != hdr->checksum) { + SPDK_ERRLOG("Invalid header checksum (found: %"PRIu32", expected: %"PRIu32")\n", + checksum, hdr->checksum); + rc = -ENOTRECOVERABLE; + goto out; + } + + if (hdr->version != FTL_NV_CACHE_HEADER_VERSION) { + SPDK_ERRLOG("Invalid header version (found: %"PRIu32", expected: %"PRIu32")\n", + hdr->version, FTL_NV_CACHE_HEADER_VERSION); + rc = -ENOTRECOVERABLE; + goto out; + } + + if (hdr->size != spdk_bdev_get_num_blocks(bdev)) { + SPDK_ERRLOG("Unexpected size of the non-volatile cache bdev (%"PRIu64", expected: %" + PRIu64")\n", hdr->size, spdk_bdev_get_num_blocks(bdev)); + rc = -ENOTRECOVERABLE; + goto out; + } + + if (spdk_uuid_compare(&hdr->uuid, &dev->uuid)) { + SPDK_ERRLOG("Invalid device UUID\n"); + rc = -ENOTRECOVERABLE; + goto out; + } +out: + ftl_restore_complete(restore, rc); + spdk_bdev_free_io(bdev_io); + spdk_dma_free(hdr); +} + +static void +ftl_restore_nv_cache(struct ftl_restore *restore) +{ + struct spdk_ftl_dev *dev = restore->dev; + struct spdk_bdev *bdev; + struct ftl_nv_cache *nv_cache = &dev->nv_cache; + struct ftl_io_channel *ioch; + void *buf; + int rc; + + ioch = spdk_io_channel_get_ctx(dev->ioch); + bdev = spdk_bdev_desc_get_bdev(nv_cache->bdev_desc); + + buf = spdk_dma_zmalloc(spdk_bdev_get_block_size(bdev), spdk_bdev_get_buf_align(bdev), NULL); + if (spdk_unlikely(!buf)) { + SPDK_ERRLOG("Memory allocation failure\n"); + ftl_restore_complete(restore, -ENOMEM); + return; + } + + rc = spdk_bdev_read_blocks(nv_cache->bdev_desc, ioch->cache_ioch, buf, 0, 1, + ftl_nv_cache_header_cb, restore); + if (spdk_unlikely(rc != 0)) { + SPDK_ERRLOG("Failed to read non-volatile cache metadata header: %s\n", + spdk_strerror(-rc)); + ftl_restore_complete(restore, rc); + spdk_dma_free(buf); + } +} + static bool ftl_pad_chunk_pad_finish(struct ftl_restore_band *rband, bool direct_access) { @@ -572,7 +658,7 @@ ftl_restore_tail_md_cb(struct ftl_io *io, void *ctx, int status) { struct ftl_restore_band *rband = ctx; struct ftl_restore *restore = rband->parent; - struct spdk_ftl_dev *dev = rband->band->dev; + struct spdk_ftl_dev *dev = restore->dev; if (status) { if (!dev->conf.allow_open_bands) { @@ -604,9 +690,12 @@ ftl_restore_tail_md_cb(struct ftl_io *io, void *ctx, int status) if (!STAILQ_EMPTY(&restore->pad_bands)) { spdk_thread_send_msg(ftl_get_core_thread(dev), ftl_restore_pad_open_bands, restore); + } else if (dev->nv_cache.bdev_desc) { + ftl_restore_nv_cache(restore); } else { - ftl_restore_complete(restore, status); + ftl_restore_complete(restore, 0); } + return; }