lib/ftl: Keep state of single band relocation

Added states for keeping track on which reloc
queue band actually is.

Change-Id: Ib05ac4e925002728ddfed3195891f5328eebb0d0
Signed-off-by: Wojciech Malikowski <wojciech.malikowski@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/465072
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
This commit is contained in:
Wojciech Malikowski 2019-08-13 10:54:44 -04:00 committed by Tomasz Zawadzki
parent 7012a2760e
commit 93402cd144
2 changed files with 85 additions and 63 deletions

View File

@ -54,6 +54,13 @@ enum ftl_reloc_move_state {
FTL_RELOC_STATE_WRITE, FTL_RELOC_STATE_WRITE,
}; };
enum ftl_band_reloc_state {
FTL_BAND_RELOC_STATE_INACTIVE,
FTL_BAND_RELOC_STATE_PENDING,
FTL_BAND_RELOC_STATE_ACTIVE,
FTL_BAND_RELOC_STATE_HIGH_PRIO
};
struct ftl_reloc_move { struct ftl_reloc_move {
struct ftl_band_reloc *breloc; struct ftl_band_reloc *breloc;
@ -85,8 +92,9 @@ struct ftl_band_reloc {
/* Bitmap of logical blocks to be relocated */ /* Bitmap of logical blocks to be relocated */
struct spdk_bit_array *reloc_map; struct spdk_bit_array *reloc_map;
/* Indicates band being acitvely processed */ /* State of the band reloc */
int active; enum ftl_band_reloc_state state;
/* The band is being defragged */ /* The band is being defragged */
bool defrag; bool defrag;
@ -209,7 +217,6 @@ ftl_reloc_prep(struct ftl_band_reloc *breloc)
struct ftl_reloc_move *move; struct ftl_reloc_move *move;
size_t i; size_t i;
breloc->active = 1;
reloc->num_active++; reloc->num_active++;
if (!band->high_prio) { if (!band->high_prio) {
@ -220,6 +227,8 @@ ftl_reloc_prep(struct ftl_band_reloc *breloc)
} else { } else {
ftl_band_acquire_lba_map(band); ftl_band_acquire_lba_map(band);
} }
} else {
ftl_band_acquire_lba_map(band);
} }
for (i = 0; i < reloc->max_qdepth; ++i) { for (i = 0; i < reloc->max_qdepth; ++i) {
@ -551,23 +560,27 @@ ftl_reloc_release(struct ftl_band_reloc *breloc)
struct ftl_reloc *reloc = breloc->parent; struct ftl_reloc *reloc = breloc->parent;
struct ftl_band *band = breloc->band; struct ftl_band *band = breloc->band;
if (band->high_prio && breloc->num_lbks == 0) {
band->high_prio = 0;
TAILQ_REMOVE(&reloc->prio_queue, breloc, entry);
} else if (!band->high_prio) {
TAILQ_REMOVE(&reloc->active_queue, breloc, entry);
}
ftl_reloc_iter_reset(breloc); ftl_reloc_iter_reset(breloc);
ftl_band_release_lba_map(band); ftl_band_release_lba_map(band);
breloc->active = 0;
reloc->num_active--; reloc->num_active--;
if (!band->high_prio && breloc->num_lbks) { if (breloc->state == FTL_BAND_RELOC_STATE_HIGH_PRIO) {
TAILQ_INSERT_TAIL(&reloc->pending_queue, breloc, entry); /* High prio band must be relocated as a whole and ANM events will be ignored */
return; assert(breloc->num_lbks == 0 && ftl_band_empty(band));
TAILQ_REMOVE(&reloc->prio_queue, breloc, entry);
band->high_prio = 0;
breloc->state = FTL_BAND_RELOC_STATE_INACTIVE;
} else {
assert(breloc->state == FTL_BAND_RELOC_STATE_ACTIVE);
TAILQ_REMOVE(&reloc->active_queue, breloc, entry);
breloc->state = FTL_BAND_RELOC_STATE_INACTIVE;
/* If we got ANM event during relocation put such band back to pending queue */
if (breloc->num_lbks != 0) {
breloc->state = FTL_BAND_RELOC_STATE_PENDING;
TAILQ_INSERT_TAIL(&reloc->pending_queue, breloc, entry);
return;
}
} }
if (ftl_band_empty(band) && band->state == FTL_BAND_STATE_CLOSED) { if (ftl_band_empty(band) && band->state == FTL_BAND_STATE_CLOSED) {
@ -642,7 +655,8 @@ ftl_band_reloc_free(struct ftl_band_reloc *breloc)
reloc = breloc->parent; reloc = breloc->parent;
/* Drain write queue if there is active band relocation during shutdown */ /* Drain write queue if there is active band relocation during shutdown */
if (breloc->active) { if (breloc->state == FTL_BAND_RELOC_STATE_ACTIVE ||
breloc->state == FTL_BAND_RELOC_STATE_HIGH_PRIO) {
assert(reloc->halt); assert(reloc->halt);
num_moves = spdk_ring_dequeue(breloc->move_queue, (void **)&moves, reloc->max_qdepth); num_moves = spdk_ring_dequeue(breloc->move_queue, (void **)&moves, reloc->max_qdepth);
for (i = 0; i < num_moves; ++i) { for (i = 0; i < num_moves; ++i) {
@ -656,16 +670,6 @@ ftl_band_reloc_free(struct ftl_band_reloc *breloc)
free(breloc->moves); free(breloc->moves);
} }
static void
ftl_reloc_add_active_queue(struct ftl_band_reloc *breloc)
{
struct ftl_reloc *reloc = breloc->parent;
TAILQ_REMOVE(&reloc->pending_queue, breloc, entry);
TAILQ_INSERT_HEAD(&reloc->active_queue, breloc, entry);
ftl_reloc_prep(breloc);
}
struct ftl_reloc * struct ftl_reloc *
ftl_reloc_init(struct spdk_ftl_dev *dev) ftl_reloc_init(struct spdk_ftl_dev *dev)
{ {
@ -756,9 +760,6 @@ ftl_reloc(struct ftl_reloc *reloc)
/* Process first band from priority queue and return */ /* Process first band from priority queue and return */
breloc = TAILQ_FIRST(&reloc->prio_queue); breloc = TAILQ_FIRST(&reloc->prio_queue);
if (breloc) { if (breloc) {
if (!breloc->active) {
ftl_reloc_prep(breloc);
}
ftl_process_reloc(breloc); ftl_process_reloc(breloc);
return; return;
} }
@ -773,10 +774,15 @@ ftl_reloc(struct ftl_reloc *reloc)
continue; continue;
} }
ftl_reloc_add_active_queue(breloc); ftl_reloc_prep(breloc);
assert(breloc->state == FTL_BAND_RELOC_STATE_PENDING);
TAILQ_REMOVE(&reloc->pending_queue, breloc, entry);
breloc->state = FTL_BAND_RELOC_STATE_ACTIVE;
TAILQ_INSERT_HEAD(&reloc->active_queue, breloc, entry);
} }
TAILQ_FOREACH_SAFE(breloc, &reloc->active_queue, entry, tbreloc) { TAILQ_FOREACH_SAFE(breloc, &reloc->active_queue, entry, tbreloc) {
assert(breloc->state == FTL_BAND_RELOC_STATE_ACTIVE);
ftl_process_reloc(breloc); ftl_process_reloc(breloc);
} }
} }
@ -786,7 +792,7 @@ ftl_reloc_add(struct ftl_reloc *reloc, struct ftl_band *band, size_t offset,
size_t num_lbks, int prio, bool is_defrag) size_t num_lbks, int prio, bool is_defrag)
{ {
struct ftl_band_reloc *breloc = &reloc->brelocs[band->id]; struct ftl_band_reloc *breloc = &reloc->brelocs[band->id];
size_t i, prev_lbks = breloc->num_lbks; size_t i;
/* No need to add anything if already at high prio - whole band should be relocated */ /* No need to add anything if already at high prio - whole band should be relocated */
if (!prio && band->high_prio) { if (!prio && band->high_prio) {
@ -814,10 +820,6 @@ ftl_reloc_add(struct ftl_reloc *reloc, struct ftl_band *band, size_t offset,
breloc->num_lbks++; breloc->num_lbks++;
} }
if (!prio && prev_lbks == breloc->num_lbks) {
return;
}
/* If the band is coming from the defrag process, mark it appropriately */ /* If the band is coming from the defrag process, mark it appropriately */
if (is_defrag) { if (is_defrag) {
assert(offset == 0 && num_lbks == ftl_num_band_lbks(band->dev)); assert(offset == 0 && num_lbks == ftl_num_band_lbks(band->dev));
@ -825,29 +827,35 @@ ftl_reloc_add(struct ftl_reloc *reloc, struct ftl_band *band, size_t offset,
breloc->defrag = true; breloc->defrag = true;
} }
if (!prev_lbks && !prio && !breloc->active) { if (!prio) {
TAILQ_INSERT_HEAD(&reloc->pending_queue, breloc, entry); if (breloc->state == FTL_BAND_RELOC_STATE_INACTIVE) {
} breloc->state = FTL_BAND_RELOC_STATE_PENDING;
TAILQ_INSERT_HEAD(&reloc->pending_queue, breloc, entry);
if (prio) { }
struct ftl_band_reloc *iter_breloc; } else {
bool active = false;
/* If priority band is already on pending or active queue, remove it from it */ /* If priority band is already on pending or active queue, remove it from it */
TAILQ_FOREACH(iter_breloc, &reloc->pending_queue, entry) { switch (breloc->state) {
if (breloc == iter_breloc) { case FTL_BAND_RELOC_STATE_PENDING:
TAILQ_REMOVE(&reloc->pending_queue, breloc, entry); TAILQ_REMOVE(&reloc->pending_queue, breloc, entry);
break; break;
} case FTL_BAND_RELOC_STATE_ACTIVE:
} active = true;
TAILQ_REMOVE(&reloc->active_queue, breloc, entry);
TAILQ_FOREACH(iter_breloc, &reloc->active_queue, entry) { break;
if (breloc == iter_breloc) { default:
TAILQ_REMOVE(&reloc->active_queue, breloc, entry); break;
break;
}
} }
breloc->state = FTL_BAND_RELOC_STATE_HIGH_PRIO;
TAILQ_INSERT_TAIL(&reloc->prio_queue, breloc, entry); TAILQ_INSERT_TAIL(&reloc->prio_queue, breloc, entry);
ftl_band_acquire_lba_map(breloc->band);
/*
* If band has been already on active queue it doesn't need any additional
* resources
*/
if (!active) {
ftl_reloc_prep(breloc);
}
} }
} }

View File

@ -195,6 +195,14 @@ single_reloc_move(struct ftl_band_reloc *breloc)
ftl_process_reloc(breloc); ftl_process_reloc(breloc);
} }
static void
add_to_active_queue(struct ftl_reloc *reloc, struct ftl_band_reloc *breloc)
{
TAILQ_REMOVE(&reloc->pending_queue, breloc, entry);
breloc->state = FTL_BAND_RELOC_STATE_ACTIVE;
TAILQ_INSERT_HEAD(&reloc->active_queue, breloc, entry);
}
static void static void
setup_reloc(struct spdk_ftl_dev **_dev, struct ftl_reloc **_reloc, setup_reloc(struct spdk_ftl_dev **_dev, struct ftl_reloc **_reloc,
const struct spdk_ocssd_geometry_data *geo, const struct spdk_ftl_punit_range *range) const struct spdk_ocssd_geometry_data *geo, const struct spdk_ftl_punit_range *range)
@ -228,7 +236,7 @@ cleanup_reloc(struct spdk_ftl_dev *dev, struct ftl_reloc *reloc)
size_t i; size_t i;
for (i = 0; i < ftl_dev_num_bands(reloc->dev); ++i) { for (i = 0; i < ftl_dev_num_bands(reloc->dev); ++i) {
SPDK_CU_ASSERT_FATAL(reloc->brelocs[i].active == false); SPDK_CU_ASSERT_FATAL(reloc->brelocs[i].state == FTL_BAND_RELOC_STATE_INACTIVE);
} }
ftl_reloc_free(reloc); ftl_reloc_free(reloc);
@ -296,6 +304,7 @@ test_reloc_iter_full(void)
/* num_lbks should remain intact since all the blocks are valid */ /* num_lbks should remain intact since all the blocks are valid */
CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev)); CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev));
breloc->state = FTL_BAND_RELOC_STATE_INACTIVE;
cleanup_reloc(dev, reloc); cleanup_reloc(dev, reloc);
} }
@ -342,7 +351,8 @@ test_reloc_full_band(void)
CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev)); CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev));
ftl_reloc_add_active_queue(breloc); ftl_reloc_prep(breloc);
add_to_active_queue(reloc, breloc);
for (i = 1; i <= num_iters; ++i) { for (i = 1; i <= num_iters; ++i) {
single_reloc_move(breloc); single_reloc_move(breloc);
@ -376,7 +386,7 @@ test_reloc_scatter_band(void)
breloc = &reloc->brelocs[0]; breloc = &reloc->brelocs[0];
band = breloc->band; band = breloc->band;
num_iters = ftl_num_band_lbks(dev) / MAX_RELOC_QDEPTH; num_iters = spdk_divide_round_up(ftl_num_band_lbks(dev), MAX_RELOC_QDEPTH * 2);
for (i = 0; i < ftl_num_band_lbks(dev); ++i) { for (i = 0; i < ftl_num_band_lbks(dev); ++i) {
if (i % 2) { if (i % 2) {
@ -385,7 +395,8 @@ test_reloc_scatter_band(void)
} }
ftl_reloc_add(reloc, band, 0, ftl_num_band_lbks(dev), 0, true); ftl_reloc_add(reloc, band, 0, ftl_num_band_lbks(dev), 0, true);
ftl_reloc_add_active_queue(breloc); ftl_reloc_prep(breloc);
add_to_active_queue(reloc, breloc);
CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev)); CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev));
@ -393,9 +404,9 @@ test_reloc_scatter_band(void)
single_reloc_move(breloc); single_reloc_move(breloc);
} }
ftl_process_reloc(breloc);
CU_ASSERT_EQUAL(breloc->num_lbks, 0); CU_ASSERT_EQUAL(breloc->num_lbks, 0);
CU_ASSERT_TRUE(ftl_reloc_done(breloc)); CU_ASSERT_TRUE(ftl_reloc_done(breloc));
ftl_reloc_release(breloc);
cleanup_reloc(dev, reloc); cleanup_reloc(dev, reloc);
} }
@ -423,7 +434,9 @@ test_reloc_chunk(void)
ftl_reloc_add(reloc, band, ftl_dev_lbks_in_chunk(dev) * 3, ftl_reloc_add(reloc, band, ftl_dev_lbks_in_chunk(dev) * 3,
ftl_dev_lbks_in_chunk(dev), 1, false); ftl_dev_lbks_in_chunk(dev), 1, false);
ftl_reloc_add_active_queue(breloc);
ftl_reloc_prep(breloc);
add_to_active_queue(reloc, breloc);
CU_ASSERT_EQUAL(breloc->num_lbks, ftl_dev_lbks_in_chunk(dev)); CU_ASSERT_EQUAL(breloc->num_lbks, ftl_dev_lbks_in_chunk(dev));
@ -464,7 +477,8 @@ test_reloc_single_lbk(void)
ftl_reloc_add(reloc, band, TEST_RELOC_OFFSET, 1, 0, false); ftl_reloc_add(reloc, band, TEST_RELOC_OFFSET, 1, 0, false);
SPDK_CU_ASSERT_FATAL(breloc == TAILQ_FIRST(&reloc->pending_queue)); SPDK_CU_ASSERT_FATAL(breloc == TAILQ_FIRST(&reloc->pending_queue));
ftl_reloc_add_active_queue(breloc); ftl_reloc_prep(breloc);
add_to_active_queue(reloc, breloc);
CU_ASSERT_EQUAL(breloc->num_lbks, 1); CU_ASSERT_EQUAL(breloc->num_lbks, 1);