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

FTL: Add band state change functions

parent 7c9d3ea5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -145,6 +145,9 @@ int ftl_band_filled(struct ftl_band *band, size_t offset);
int ftl_band_write_prep(struct ftl_band *band);
size_t ftl_p2l_map_pool_elem_size(struct spdk_ftl_dev *dev);
ftl_addr ftl_band_p2l_map_addr(struct ftl_band *band);
void ftl_band_open(struct ftl_band *band, enum ftl_band_type type);
void ftl_band_close(struct ftl_band *band);
void ftl_band_free(struct ftl_band *band);
void ftl_band_rq_write(struct ftl_band *band, struct ftl_rq *rq);
void ftl_band_rq_read(struct ftl_band *band, struct ftl_rq *rq);
void ftl_band_basic_rq_write(struct ftl_band *band, struct ftl_basic_rq *brq);
+131 −0
Original line number Diff line number Diff line
@@ -251,6 +251,137 @@ ftl_band_basic_rq_read(struct ftl_band *band, struct ftl_basic_rq *brq)
	dev->io_activity_total += brq->num_blocks;
}

static void
band_open_cb(int status, void *cb_arg)
{
	struct ftl_band *band = cb_arg;

	if (spdk_unlikely(status)) {
		ftl_md_persist_entry_retry(&band->md_persist_entry_ctx);
		return;
	}

	ftl_band_set_state(band, FTL_BAND_STATE_OPEN);
}

void
ftl_band_open(struct ftl_band *band, enum ftl_band_type type)
{
	struct spdk_ftl_dev *dev = band->dev;
	struct ftl_md *md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_BAND_MD];
	struct ftl_layout_region *region = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_BAND_MD];
	struct ftl_p2l_map *p2l_map = &band->p2l_map;

	ftl_band_set_type(band, type);
	ftl_band_set_state(band, FTL_BAND_STATE_OPENING);

	memcpy(p2l_map->band_dma_md, band->md, region->entry_size * FTL_BLOCK_SIZE);
	p2l_map->band_dma_md->state = FTL_BAND_STATE_OPEN;
	p2l_map->band_dma_md->p2l_map_checksum = 0;

	if (spdk_unlikely(0 != band->p2l_map.num_valid)) {
		/*
		 * This is inconsistent state, a band with valid block,
		 * it could be moved on the free list
		 */
		assert(false && 0 == band->p2l_map.num_valid);
		ftl_abort();
	}

	ftl_md_persist_entry(md, band->id, p2l_map->band_dma_md, NULL,
			     band_open_cb, band, &band->md_persist_entry_ctx);
}

static void
band_close_cb(int status, void *cb_arg)
{
	struct ftl_band *band = cb_arg;

	if (spdk_unlikely(status)) {
		ftl_md_persist_entry_retry(&band->md_persist_entry_ctx);
		return;
	}

	band->md->p2l_map_checksum = band->p2l_map.band_dma_md->p2l_map_checksum;
	ftl_band_set_state(band, FTL_BAND_STATE_CLOSED);
}

static void
band_map_write_cb(struct ftl_basic_rq *brq)
{
	struct ftl_band *band = brq->io.band;
	struct ftl_p2l_map *p2l_map = &band->p2l_map;
	struct spdk_ftl_dev *dev = band->dev;
	struct ftl_layout_region *region = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_BAND_MD];
	struct ftl_md *md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_BAND_MD];
	uint32_t band_map_crc;

	if (spdk_likely(brq->success)) {

		band_map_crc = spdk_crc32c_update(p2l_map->band_map,
						  ftl_tail_md_num_blocks(dev) * FTL_BLOCK_SIZE, 0);
		memcpy(p2l_map->band_dma_md, band->md, region->entry_size * FTL_BLOCK_SIZE);
		p2l_map->band_dma_md->state = FTL_BAND_STATE_CLOSED;
		p2l_map->band_dma_md->p2l_map_checksum = band_map_crc;

		ftl_md_persist_entry(md, band->id, p2l_map->band_dma_md, NULL,
				     band_close_cb, band, &band->md_persist_entry_ctx);
	} else {
		/* Try to retry in case of failure */
		ftl_band_brq_bdev_write(brq);
		band->queue_depth++;
	}
}

void
ftl_band_close(struct ftl_band *band)
{
	struct spdk_ftl_dev *dev = band->dev;
	void *metadata = band->p2l_map.band_map;
	uint64_t num_blocks = ftl_tail_md_num_blocks(dev);

	/* Write LBA map first, after completion, set the state to close on nvcache, then internally */
	ftl_band_set_state(band, FTL_BAND_STATE_CLOSING);
	ftl_basic_rq_init(dev, &band->metadata_rq, metadata, num_blocks);
	ftl_basic_rq_set_owner(&band->metadata_rq, band_map_write_cb, band);

	ftl_band_basic_rq_write(band, &band->metadata_rq);
}

static void
band_free_cb(int status, void *ctx)
{
	struct ftl_band *band = (struct ftl_band *)ctx;

	if (spdk_unlikely(status)) {
		ftl_md_persist_entry_retry(&band->md_persist_entry_ctx);
		return;
	}

	ftl_band_release_p2l_map(band);
	FTL_DEBUGLOG(band->dev, "Band is going to free state. Band id: %u\n", band->id);
	ftl_band_set_state(band, FTL_BAND_STATE_FREE);
	assert(0 == band->p2l_map.ref_cnt);
}

void
ftl_band_free(struct ftl_band *band)
{
	struct spdk_ftl_dev *dev = band->dev;
	struct ftl_p2l_map *p2l_map = &band->p2l_map;
	struct ftl_md *md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_BAND_MD];
	struct ftl_layout_region *region = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_BAND_MD];

	memcpy(p2l_map->band_dma_md, band->md, region->entry_size * FTL_BLOCK_SIZE);
	p2l_map->band_dma_md->state = FTL_BAND_STATE_FREE;
	p2l_map->band_dma_md->p2l_map_checksum = 0;

	ftl_md_persist_entry(md, band->id, p2l_map->band_dma_md, NULL,
			     band_free_cb, band, &band->md_persist_entry_ctx);

	/* TODO: The whole band erase code should probably be done here instead */
}

static void
read_tail_md_cb(struct ftl_basic_rq *brq)
{