Commit ca53f5a6 authored by Kozlowski Mateusz's avatar Kozlowski Mateusz Committed by Jim Harris
Browse files

FTL: Band L2P recovery



Recovers L2P based on all non-free bands' P2L.

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


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent 40f556ca
Loading
Loading
Loading
Loading
+174 −1
Original line number Diff line number Diff line
@@ -248,6 +248,75 @@ ftl_mngt_recovery_restore_band_state(struct spdk_ftl_dev *dev, struct ftl_mngt_p
	ftl_md_restore(md);
}

struct band_md_ctx {
	int status;
	uint64_t qd;
	uint64_t id;
};

static void
ftl_mngt_recovery_walk_band_tail_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
				    ftl_band_md_cb cb)
{
	struct band_md_ctx *sctx = ftl_mngt_get_step_ctx(mngt);
	uint64_t num_bands = ftl_get_num_bands(dev);

	/*
	 * This function generates a high queue depth and will utilize ftl_mngt_continue_step during completions to make sure all bands
	 * are processed before returning an error (if any were found) or continuing on.
	 */
	if (0 == sctx->qd && sctx->id == num_bands) {
		if (sctx->status) {
			ftl_mngt_fail_step(mngt);
		} else {
			ftl_mngt_next_step(mngt);
		}
		return;
	}

	while (sctx->id < num_bands) {
		struct ftl_band *band = &dev->bands[sctx->id];

		if (FTL_BAND_STATE_FREE == band->md->state) {
			sctx->id++;
			continue;
		}

		if (FTL_BAND_STATE_OPEN == band->md->state || FTL_BAND_STATE_FULL == band->md->state) {
			/* This band is already open and has valid P2L map */
			sctx->id++;
			sctx->qd++;
			ftl_band_acquire_p2l_map(band);
			cb(band, mngt, FTL_MD_SUCCESS);
			continue;
		} else {
			if (dev->sb->ckpt_seq_id && (band->md->close_seq_id <= dev->sb->ckpt_seq_id)) {
				sctx->id++;
				continue;
			}

			band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
			if (ftl_band_alloc_p2l_map(band)) {
				/* No more free P2L map, try later */
				break;
			}
		}

		sctx->id++;
		ftl_band_read_tail_brq_md(band, cb, mngt);
		sctx->qd++;
	}

	if (0 == sctx->qd) {
		/*
		 * No QD could happen due to all leftover bands being in free state.
		 * For streamlining of all potential error handling (since many bands are reading P2L at the same time),
		 * we're using ftl_mngt_continue_step to arrive at the same spot of checking for mngt step end (see beginning of function).
		 */
		ftl_mngt_continue_step(mngt);
	}
}

static void
ftl_mngt_recovery_iteration_init_seq_ids(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
@@ -304,6 +373,105 @@ ftl_mngt_recovery_iteration_save_l2p(struct spdk_ftl_dev *dev, struct ftl_mngt_p
	ftl_md_persist(md);
}

static void
restore_band_l2p_cb(struct ftl_band *band, void *cntx, enum ftl_md_status status)
{
	struct ftl_mngt_process *mngt = cntx;
	struct ftl_mngt_recovery_ctx *pctx = ftl_mngt_get_caller_ctx(mngt);
	struct band_md_ctx *sctx = ftl_mngt_get_step_ctx(mngt);
	struct spdk_ftl_dev *dev = band->dev;
	ftl_addr addr, curr_addr;
	uint64_t i, lba, seq_id, num_blks_in_band;
	uint32_t band_map_crc;
	int rc = 0;

	if (status != FTL_MD_SUCCESS) {
		FTL_ERRLOG(dev, "L2P band restore error, failed to read P2L map\n");
		rc = -EIO;
		goto cleanup;
	}

	band_map_crc = spdk_crc32c_update(band->p2l_map.band_map,
					  ftl_tail_md_num_blocks(band->dev) * FTL_BLOCK_SIZE, 0);

	/* P2L map is only valid if the band state is closed */
	if (FTL_BAND_STATE_CLOSED == band->md->state && band->md->p2l_map_checksum != band_map_crc) {
		FTL_ERRLOG(dev, "L2P band restore error, inconsistent P2L map CRC\n");
		rc = -EINVAL;
		goto cleanup;
	}

	num_blks_in_band = ftl_get_num_blocks_in_band(dev);
	for (i = 0; i < num_blks_in_band; ++i) {
		uint64_t lba_off;
		lba = band->p2l_map.band_map[i].lba;
		seq_id = band->p2l_map.band_map[i].seq_id;

		if (lba == FTL_LBA_INVALID) {
			continue;
		}
		if (lba >= dev->num_lbas) {
			FTL_ERRLOG(dev, "L2P band restore ERROR, LBA out of range\n");
			rc = -EINVAL;
			break;
		}
		if (lba < pctx->iter.lba_first || lba >= pctx->iter.lba_last) {
			continue;
		}

		lba_off = lba - pctx->iter.lba_first;
		if (seq_id < pctx->l2p_snippet.seq_id[lba_off]) {

			/* Overlapped band/chunk has newer data - invalidate P2L map on open/full band  */
			if (FTL_BAND_STATE_OPEN == band->md->state || FTL_BAND_STATE_FULL == band->md->state) {
				addr = ftl_band_addr_from_block_offset(band, i);
				ftl_band_set_p2l(band, FTL_LBA_INVALID, addr, 0);
			}

			/* Newer data already recovered */
			continue;
		}

		addr = ftl_band_addr_from_block_offset(band, i);

		curr_addr = ftl_addr_load(dev, pctx->l2p_snippet.l2p, lba_off);

		/* Overlapped band/chunk has newer data - invalidate P2L map on open/full band  */
		if (curr_addr != FTL_ADDR_INVALID && !ftl_addr_in_nvc(dev, curr_addr) && curr_addr != addr) {
			struct ftl_band *curr_band = ftl_band_from_addr(dev, curr_addr);

			if (FTL_BAND_STATE_OPEN == curr_band->md->state || FTL_BAND_STATE_FULL == curr_band->md->state) {
				size_t prev_offset = ftl_band_block_offset_from_addr(curr_band, curr_addr);
				if (curr_band->p2l_map.band_map[prev_offset].lba == lba &&
				    seq_id >= curr_band->p2l_map.band_map[prev_offset].seq_id) {
					ftl_band_set_p2l(curr_band, FTL_LBA_INVALID, curr_addr, 0);
				}
			}
		}

		ftl_addr_store(dev, pctx->l2p_snippet.l2p, lba_off, addr);
		pctx->l2p_snippet.seq_id[lba_off] = seq_id;
	}


cleanup:
	ftl_band_release_p2l_map(band);

	sctx->qd--;
	if (rc) {
		sctx->status = rc;
	}

	ftl_mngt_continue_step(mngt);
}

static void
ftl_mngt_recovery_iteration_restore_band_l2p(struct spdk_ftl_dev *dev,
		struct ftl_mngt_process *mngt)
{
	ftl_mngt_recovery_walk_band_tail_md(dev, mngt, restore_band_l2p_cb);
}

static void
ftl_mngt_recovery_iteration_restore_valid_map(struct spdk_ftl_dev *dev,
		struct ftl_mngt_process *mngt)
@@ -418,7 +586,7 @@ ftl_mngt_recovery_open_bands_p2l(struct spdk_ftl_dev *dev, struct ftl_mngt_proce
		TAILQ_FOREACH(band, &pctx->open_bands, queue_entry) {
			band->md->df_p2l_map = FTL_DF_OBJ_ID_INVALID;
			if (ftl_band_alloc_p2l_map(band)) {
				FTL_ERRLOG(dev, "Open band recovery ERROR, Cannot allocate LBA map\n");
				FTL_ERRLOG(dev, "Open band recovery ERROR, Cannot allocate P2L map\n");
				ftl_mngt_fail_step(mngt);
				return;
			}
@@ -493,6 +661,11 @@ static const struct ftl_mngt_process_desc g_desc_recovery_iteration = {
			.name = "Initialize sequence IDs",
			.action = ftl_mngt_recovery_iteration_init_seq_ids,
		},
		{
			.name = "Restore band L2P",
			.ctx_size = sizeof(struct band_md_ctx),
			.action = ftl_mngt_recovery_iteration_restore_band_l2p,
		},
		{
			.name = "Restore valid map",
			.action = ftl_mngt_recovery_iteration_restore_valid_map,