Commit ef93cc38 authored by Kozlowski Mateusz's avatar Kozlowski Mateusz Committed by Ben Walker
Browse files

FTL: Persist metadata on clean shutdown



Add an extra step during FTL shutdown to save all metadata.

Signed-off-by: default avatarKozlowski Mateusz <mateusz.kozlowski@intel.com>
Signed-off-by: default avatarArtur Paszkiewicz <artur.paszkiewicz@intel.com>
Change-Id: Idc2f77e15bbd02028548cc88355cd450175830e8
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13359


Community-CI: Mellanox Build Bot
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
parent b4b70e83
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -81,6 +81,12 @@ ftl_l2p_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
	FTL_L2P_OP(clear)(dev, cb, cb_ctx);
}

void
ftl_l2p_persist(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
{
	FTL_L2P_OP(persist)(dev, cb, cb_ctx);
}

void
ftl_l2p_process(struct spdk_ftl_dev *dev)
{
+1 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ ftl_addr ftl_l2p_get(struct spdk_ftl_dev *dev, uint64_t lba);

void ftl_l2p_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx);
void ftl_l2p_restore(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx);
void ftl_l2p_persist(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx);
void ftl_l2p_process(struct spdk_ftl_dev *dev);
bool ftl_l2p_is_halted(struct spdk_ftl_dev *dev);
void ftl_l2p_halt(struct spdk_ftl_dev *dev);
+136 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
struct ftl_l2p_cache_page_io_ctx {
	struct ftl_l2p_cache *cache;
	uint64_t updates;
	spdk_bdev_io_completion_cb cb;
	struct spdk_bdev_io_wait_entry bdev_io_wait;
};

@@ -509,6 +510,99 @@ ftl_l2p_cache_deinit(struct spdk_ftl_dev *dev)
	dev->l2p = 0;
}

static void
process_init_ctx(struct spdk_ftl_dev *dev, struct ftl_l2p_cache *cache,
		 ftl_l2p_cb cb, void *cb_ctx)
{
	struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;

	assert(NULL == ctx->cb_ctx);
	assert(0 == cache->l2_pgs_evicting);

	memset(ctx, 0, sizeof(*ctx));

	ctx->cb = cb;
	ctx->cb_ctx = cb_ctx;
}

static void
process_finish(struct ftl_l2p_cache *cache)
{
	struct ftl_l2p_cache_process_ctx ctx = cache->mctx;

	assert(cache->l2_pgs_avail == cache->l2_pgs_resident_max);
	assert(0 == ctx.qd);

	memset(&cache->mctx, 0, sizeof(cache->mctx));
	ctx.cb(cache->dev, ctx.status, ctx.cb_ctx);
}

static void process_page_out_retry(void *_page);
static void process_persist(struct ftl_l2p_cache *cache);

static void
process_persist_page_out_cb(struct spdk_bdev_io *bdev_io, bool success, void *arg)
{
	struct ftl_l2p_page *page = arg;
	struct ftl_l2p_cache *cache = page->ctx.cache;
	struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;

	assert(bdev_io);
	spdk_bdev_free_io(bdev_io);

	if (!success) {
		ctx->status = -EIO;
	}

	ftl_l2p_cache_page_remove(cache, page);

	ctx->qd--;
	process_persist(cache);
}

static void
process_page_out(struct ftl_l2p_page *page, spdk_bdev_io_completion_cb cb)
{
	struct spdk_bdev *bdev;
	struct spdk_bdev_io_wait_entry *bdev_io_wait;
	struct ftl_l2p_cache *cache = page->ctx.cache;
	struct spdk_ftl_dev *dev = cache->dev;
	int rc;

	assert(page->page_buffer);

	rc = ftl_nv_cache_bdev_write_blocks_with_md(dev, ftl_l2p_cache_get_bdev_desc(cache),
			ftl_l2p_cache_get_bdev_iochannel(cache),
			page->page_buffer, NULL, ftl_l2p_cache_page_get_bdev_offset(cache, page),
			1, cb, page);

	if (spdk_likely(0 == rc)) {
		return;
	}

	if (rc == -ENOMEM) {
		bdev = spdk_bdev_desc_get_bdev(ftl_l2p_cache_get_bdev_desc(cache));
		bdev_io_wait = &page->ctx.bdev_io_wait;
		bdev_io_wait->bdev = bdev;
		bdev_io_wait->cb_fn = process_page_out_retry;
		bdev_io_wait->cb_arg = page;
		page->ctx.cb = cb;

		rc = spdk_bdev_queue_io_wait(bdev, ftl_l2p_cache_get_bdev_iochannel(cache), bdev_io_wait);
		ftl_bug(rc);
	} else {
		ftl_abort();
	}
}

static void
process_page_out_retry(void *_page)
{
	struct ftl_l2p_page *page = _page;

	process_page_out(page, page->ctx.cb);
}

static void
clear_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
{
@@ -531,6 +625,48 @@ ftl_l2p_cache_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
	ftl_md_clear(md, invalid_addr, NULL);
}

static void
process_persist(struct ftl_l2p_cache *cache)
{
	struct ftl_l2p_cache_process_ctx *ctx = &cache->mctx;

	while (ctx->idx < cache->num_pages && ctx->qd < 64) {
		struct ftl_l2p_page *page = get_l2p_page_by_df_id(cache, ctx->idx);
		ctx->idx++;

		if (!page) {
			continue;
		}

		if (page->on_lru_list) {
			ftl_l2p_cache_lru_remove_page(cache, page);
		}

		if (page->updates) {
			/* Need to persist the page */
			page->state = L2P_CACHE_PAGE_PERSISTING;
			page->ctx.cache = cache;
			ctx->qd++;
			process_page_out(page, process_persist_page_out_cb);
		} else {
			ftl_l2p_cache_page_remove(cache, page);
		}
	}

	if (0 == ctx->qd) {
		process_finish(cache);
	}
}

void
ftl_l2p_cache_persist(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
{
	struct ftl_l2p_cache *cache = (struct ftl_l2p_cache *)dev->l2p;

	process_init_ctx(dev, cache, cb, cb_ctx);
	process_persist(cache);
}

bool
ftl_l2p_cache_is_halted(struct spdk_ftl_dev *dev)
{
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ void ftl_l2p_cache_unpin(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t count)
ftl_addr ftl_l2p_cache_get(struct spdk_ftl_dev *dev, uint64_t lba);
void ftl_l2p_cache_set(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr addr);
void ftl_l2p_cache_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx);
void ftl_l2p_cache_persist(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx);
void ftl_l2p_cache_process(struct spdk_ftl_dev *dev);
bool ftl_l2p_cache_is_halted(struct spdk_ftl_dev *dev);
void ftl_l2p_cache_halt(struct spdk_ftl_dev *dev);
+12 −0
Original line number Diff line number Diff line
@@ -80,6 +80,18 @@ ftl_l2p_flat_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
	ftl_md_persist(md);
}

void
ftl_l2p_flat_persist(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
{
	struct ftl_md *md;

	md = get_l2p_md(dev);
	md->cb = md_cb;
	md->owner.cb_ctx = cb_ctx;
	md->owner.private = cb;
	ftl_md_persist(md);
}

static int
ftl_l2p_flat_init_dram(struct spdk_ftl_dev *dev, struct ftl_l2p_flat *l2p_flat,
		       size_t l2p_size)
Loading