diff --git a/lib/ftl/ftl_band.h b/lib/ftl/ftl_band.h index 81febf719..7d8f0c43f 100644 --- a/lib/ftl/ftl_band.h +++ b/lib/ftl/ftl_band.h @@ -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); diff --git a/lib/ftl/ftl_band_ops.c b/lib/ftl/ftl_band_ops.c index a9d9f3bd3..0d594cf6a 100644 --- a/lib/ftl/ftl_band_ops.c +++ b/lib/ftl/ftl_band_ops.c @@ -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) {