lib/ftl: store non-volatile cache's current write address
Remember current write position within the cache when shutting down. It allows for faster recovery after clean shutdown (no need to scan the device) as well as grants a quick way to distinguish between clean and dirty shutdowns. Change-Id: I79c22caa0b1ca4373951ac43f747b085d331cdd0 Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com> Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/460796 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Wojciech Malikowski <wojciech.malikowski@intel.com> Reviewed-by: Mateusz Kozlowski <mateusz.kozlowski@intel.com>
This commit is contained in:
parent
3e911e17c7
commit
fb15434659
@ -1064,7 +1064,7 @@ ftl_nv_cache_wrap(void *ctx)
|
||||
struct ftl_nv_cache *nv_cache = ctx;
|
||||
int rc;
|
||||
|
||||
rc = ftl_nv_cache_write_header(nv_cache, ftl_nv_cache_wrap_cb, nv_cache);
|
||||
rc = ftl_nv_cache_write_header(nv_cache, false, 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));
|
||||
@ -1254,8 +1254,8 @@ ftl_write_nv_cache(struct ftl_io *parent)
|
||||
}
|
||||
|
||||
int
|
||||
ftl_nv_cache_write_header(struct ftl_nv_cache *nv_cache, spdk_bdev_io_completion_cb cb_fn,
|
||||
void *cb_arg)
|
||||
ftl_nv_cache_write_header(struct ftl_nv_cache *nv_cache, bool shutdown,
|
||||
spdk_bdev_io_completion_cb cb_fn, void *cb_arg)
|
||||
{
|
||||
struct spdk_ftl_dev *dev = SPDK_CONTAINEROF(nv_cache, struct spdk_ftl_dev, nv_cache);
|
||||
struct ftl_nv_cache_header *hdr = nv_cache->dma_buf;
|
||||
@ -1271,6 +1271,7 @@ ftl_nv_cache_write_header(struct ftl_nv_cache *nv_cache, spdk_bdev_io_completion
|
||||
hdr->size = spdk_bdev_get_num_blocks(bdev);
|
||||
hdr->uuid = dev->uuid;
|
||||
hdr->version = FTL_NV_CACHE_HEADER_VERSION;
|
||||
hdr->current_addr = shutdown ? nv_cache->current_addr : FTL_LBA_INVALID;
|
||||
hdr->checksum = spdk_crc32c_update(hdr, offsetof(struct ftl_nv_cache_header, checksum), 0);
|
||||
|
||||
return spdk_bdev_write_blocks(nv_cache->bdev_desc, ioch->cache_ioch, hdr, 0, 1,
|
||||
|
@ -262,6 +262,8 @@ struct ftl_nv_cache_header {
|
||||
struct spdk_uuid uuid;
|
||||
/* Size of the non-volatile cache (in blocks) */
|
||||
uint64_t size;
|
||||
/* Contains the next address to be written after clean shutdown, invalid LBA otherwise */
|
||||
uint64_t current_addr;
|
||||
/* Current phase */
|
||||
uint8_t phase;
|
||||
/* Checksum of the header, needs to be last element */
|
||||
@ -294,8 +296,8 @@ int ftl_retrieve_chunk_info(struct spdk_ftl_dev *dev, struct ftl_ppa ppa,
|
||||
unsigned int num_entries);
|
||||
bool ftl_ppa_is_written(struct ftl_band *band, struct ftl_ppa ppa);
|
||||
int ftl_flush_active_bands(struct spdk_ftl_dev *dev, spdk_ftl_fn cb_fn, void *cb_arg);
|
||||
int ftl_nv_cache_write_header(struct ftl_nv_cache *nv_cache, spdk_bdev_io_completion_cb cb_fn,
|
||||
void *cb_arg);
|
||||
int ftl_nv_cache_write_header(struct ftl_nv_cache *nv_cache, bool shutdown,
|
||||
spdk_bdev_io_completion_cb cb_fn, void *cb_arg);
|
||||
int ftl_nv_cache_scrub(struct ftl_nv_cache *nv_cache, spdk_bdev_io_completion_cb cb_fn,
|
||||
void *cb_arg);
|
||||
|
||||
|
@ -899,7 +899,7 @@ ftl_clear_nv_cache_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
|
||||
}
|
||||
|
||||
nv_cache->phase = 1;
|
||||
if (ftl_nv_cache_write_header(nv_cache, ftl_write_nv_cache_md_cb, dev)) {
|
||||
if (ftl_nv_cache_write_header(nv_cache, false, ftl_write_nv_cache_md_cb, dev)) {
|
||||
SPDK_ERRLOG("Unable to write non-volatile cache metadata header\n");
|
||||
ftl_init_fail(dev);
|
||||
}
|
||||
@ -1260,15 +1260,46 @@ ftl_dev_free_sync(struct spdk_ftl_dev *dev)
|
||||
}
|
||||
|
||||
static void
|
||||
ftl_call_fini_complete_cb(void *_ctx)
|
||||
ftl_call_fini_complete(struct spdk_ftl_dev *dev, int status)
|
||||
{
|
||||
struct spdk_ftl_dev *dev = _ctx;
|
||||
struct ftl_init_context ctx = dev->fini_ctx;
|
||||
|
||||
ftl_dev_free_sync(dev);
|
||||
|
||||
if (ctx.cb_fn != NULL) {
|
||||
ctx.cb_fn(NULL, ctx.cb_arg, 0);
|
||||
ctx.cb_fn(NULL, ctx.cb_arg, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ftl_nv_cache_header_fini_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
spdk_bdev_free_io(bdev_io);
|
||||
if (spdk_unlikely(!success)) {
|
||||
SPDK_ERRLOG("Failed to write non-volatile cache metadata header\n");
|
||||
status = -EIO;
|
||||
}
|
||||
|
||||
ftl_call_fini_complete((struct spdk_ftl_dev *)cb_arg, status);
|
||||
}
|
||||
|
||||
static void
|
||||
ftl_halt_complete_cb(void *ctx)
|
||||
{
|
||||
struct spdk_ftl_dev *dev = ctx;
|
||||
struct ftl_nv_cache *nv_cache = &dev->nv_cache;
|
||||
int rc = 0;
|
||||
|
||||
if (!ftl_dev_has_nv_cache(dev)) {
|
||||
ftl_call_fini_complete(dev, 0);
|
||||
} else {
|
||||
rc = ftl_nv_cache_write_header(nv_cache, true, ftl_nv_cache_header_fini_cb, dev);
|
||||
if (spdk_unlikely(rc != 0)) {
|
||||
SPDK_ERRLOG("Failed to write non-volatile cache metadata header: %s\n",
|
||||
spdk_strerror(-rc));
|
||||
ftl_call_fini_complete(dev, rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1285,7 +1316,7 @@ ftl_halt_poller(void *ctx)
|
||||
|
||||
ftl_anm_unregister_device(dev);
|
||||
|
||||
spdk_thread_send_msg(dev->fini_ctx.thread, ftl_call_fini_complete_cb, dev);
|
||||
spdk_thread_send_msg(dev->fini_ctx.thread, ftl_halt_complete_cb, dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -106,8 +106,6 @@ struct ftl_nv_cache_restore {
|
||||
size_t num_outstanding;
|
||||
/* Recovery/scan status */
|
||||
int status;
|
||||
/* Recover the data from non-volatile cache */
|
||||
bool recovery;
|
||||
/* Current phase of the recovery */
|
||||
unsigned int phase;
|
||||
};
|
||||
@ -491,7 +489,7 @@ ftl_nv_cache_scrub_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
|
||||
}
|
||||
|
||||
nv_cache->phase = 1;
|
||||
rc = ftl_nv_cache_write_header(nv_cache, ftl_nv_cache_write_header_cb, restore);
|
||||
rc = ftl_nv_cache_write_header(nv_cache, false, ftl_nv_cache_write_header_cb, restore);
|
||||
if (spdk_unlikely(rc != 0)) {
|
||||
SPDK_ERRLOG("Unable to write the non-volatile cache metadata header: %s\n",
|
||||
spdk_strerror(-rc));
|
||||
@ -538,7 +536,7 @@ ftl_nv_cache_band_flush_cb(void *ctx, int status)
|
||||
* this process, we'll know it needs to be resumed.
|
||||
*/
|
||||
nv_cache->phase = 0;
|
||||
rc = ftl_nv_cache_write_header(nv_cache, ftl_nv_cache_scrub_header_cb, restore);
|
||||
rc = ftl_nv_cache_write_header(nv_cache, false, ftl_nv_cache_scrub_header_cb, restore);
|
||||
if (spdk_unlikely(rc != 0)) {
|
||||
SPDK_ERRLOG("Unable to write non-volatile cache metadata header: %s\n",
|
||||
spdk_strerror(-rc));
|
||||
@ -770,10 +768,8 @@ ftl_nv_cache_scan_done(struct ftl_nv_cache_restore *restore)
|
||||
}
|
||||
assert(num_blocks == nv_cache->num_data_blocks);
|
||||
#endif
|
||||
if (!restore->recovery) {
|
||||
ftl_nv_cache_recovery_done(restore);
|
||||
} else {
|
||||
restore->phase = ftl_nv_cache_prev_phase(nv_cache->phase);
|
||||
|
||||
/*
|
||||
* Only the latest two phases need to be recovered. The third one, even if present,
|
||||
* already has to be stored on the main storage, as it's already started to be
|
||||
@ -783,7 +779,6 @@ ftl_nv_cache_scan_done(struct ftl_nv_cache_restore *restore)
|
||||
restore->range[restore->phase].recovery = true;
|
||||
|
||||
ftl_nv_cache_recover_range(restore);
|
||||
}
|
||||
}
|
||||
|
||||
static int ftl_nv_cache_scan_block(struct ftl_nv_cache_block *block);
|
||||
@ -863,6 +858,21 @@ ftl_nv_cache_scan_block(struct ftl_nv_cache_block *block)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ftl_nv_cache_clean_header_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
|
||||
{
|
||||
struct ftl_nv_cache_restore *restore = cb_arg;
|
||||
|
||||
spdk_bdev_free_io(bdev_io);
|
||||
if (spdk_unlikely(!success)) {
|
||||
SPDK_ERRLOG("Unable to write the non-volatile cache metadata header\n");
|
||||
ftl_nv_cache_restore_complete(restore, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
ftl_nv_cache_restore_done(restore, restore->current_addr);
|
||||
}
|
||||
|
||||
static bool
|
||||
ftl_nv_cache_header_valid(struct spdk_ftl_dev *dev, const struct ftl_nv_cache_header *hdr)
|
||||
{
|
||||
@ -897,6 +907,14 @@ ftl_nv_cache_header_valid(struct spdk_ftl_dev *dev, const struct ftl_nv_cache_he
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((hdr->current_addr >= spdk_bdev_get_num_blocks(bdev) ||
|
||||
hdr->current_addr < FTL_NV_CACHE_DATA_OFFSET) &&
|
||||
(hdr->current_addr != FTL_LBA_INVALID)) {
|
||||
SPDK_ERRLOG("Unexpected value of non-volatile cache's current address: %"PRIu64"\n",
|
||||
hdr->current_addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -943,6 +961,25 @@ ftl_nv_cache_read_header_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Valid current_addr means that the shutdown was clean, so we just need to overwrite the
|
||||
* header to make sure that any power loss occurring before the cache is wrapped won't be
|
||||
* mistaken for a clean shutdown.
|
||||
*/
|
||||
if (hdr->current_addr != FTL_LBA_INVALID) {
|
||||
restore->nv_cache.current_addr = hdr->current_addr;
|
||||
|
||||
rc = ftl_nv_cache_write_header(nv_cache, false, ftl_nv_cache_clean_header_cb,
|
||||
&restore->nv_cache);
|
||||
if (spdk_unlikely(rc != 0)) {
|
||||
SPDK_ERRLOG("Failed to overwrite the non-volatile cache header: %s\n",
|
||||
spdk_strerror(-rc));
|
||||
ftl_restore_complete(restore, -ENOTRECOVERABLE);
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Otherwise the shutdown was unexpected, so we need to recover the data from the cache */
|
||||
restore->nv_cache.current_addr = FTL_NV_CACHE_DATA_OFFSET;
|
||||
|
||||
for (i = 0; i < FTL_NV_CACHE_RESTORE_DEPTH; ++i) {
|
||||
@ -1218,7 +1255,6 @@ ftl_restore_tail_md_cb(struct ftl_io *io, void *ctx, int status)
|
||||
SPDK_ERRLOG("%s while restoring tail md. Will attempt to pad band %u.\n",
|
||||
spdk_strerror(-status), rband->band->id);
|
||||
STAILQ_INSERT_TAIL(&restore->pad_bands, rband, stailq);
|
||||
restore->nv_cache.recovery = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user