From 93402cd1446f9979265fda1d5ae35e6baaeaf579 Mon Sep 17 00:00:00 2001 From: Wojciech Malikowski Date: Tue, 13 Aug 2019 10:54:44 -0400 Subject: [PATCH] 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 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/465072 Tested-by: SPDK CI Jenkins Reviewed-by: Shuhei Matsumoto Reviewed-by: Tomasz Zawadzki --- lib/ftl/ftl_reloc.c | 120 ++++++++++--------- test/unit/lib/ftl/ftl_reloc.c/ftl_reloc_ut.c | 28 +++-- 2 files changed, 85 insertions(+), 63 deletions(-) diff --git a/lib/ftl/ftl_reloc.c b/lib/ftl/ftl_reloc.c index 3775972f0..1fcb46971 100644 --- a/lib/ftl/ftl_reloc.c +++ b/lib/ftl/ftl_reloc.c @@ -54,6 +54,13 @@ enum ftl_reloc_move_state { 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_band_reloc *breloc; @@ -85,8 +92,9 @@ struct ftl_band_reloc { /* Bitmap of logical blocks to be relocated */ struct spdk_bit_array *reloc_map; - /* Indicates band being acitvely processed */ - int active; + /* State of the band reloc */ + enum ftl_band_reloc_state state; + /* The band is being defragged */ bool defrag; @@ -209,7 +217,6 @@ ftl_reloc_prep(struct ftl_band_reloc *breloc) struct ftl_reloc_move *move; size_t i; - breloc->active = 1; reloc->num_active++; if (!band->high_prio) { @@ -220,6 +227,8 @@ ftl_reloc_prep(struct ftl_band_reloc *breloc) } else { ftl_band_acquire_lba_map(band); } + } else { + ftl_band_acquire_lba_map(band); } 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_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_band_release_lba_map(band); - - breloc->active = 0; reloc->num_active--; - if (!band->high_prio && breloc->num_lbks) { - TAILQ_INSERT_TAIL(&reloc->pending_queue, breloc, entry); - return; + if (breloc->state == FTL_BAND_RELOC_STATE_HIGH_PRIO) { + /* High prio band must be relocated as a whole and ANM events will be ignored */ + 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) { @@ -642,7 +655,8 @@ ftl_band_reloc_free(struct ftl_band_reloc *breloc) reloc = breloc->parent; /* 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); num_moves = spdk_ring_dequeue(breloc->move_queue, (void **)&moves, reloc->max_qdepth); for (i = 0; i < num_moves; ++i) { @@ -656,16 +670,6 @@ ftl_band_reloc_free(struct ftl_band_reloc *breloc) 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 * 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 */ breloc = TAILQ_FIRST(&reloc->prio_queue); if (breloc) { - if (!breloc->active) { - ftl_reloc_prep(breloc); - } ftl_process_reloc(breloc); return; } @@ -773,10 +774,15 @@ ftl_reloc(struct ftl_reloc *reloc) 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) { + assert(breloc->state == FTL_BAND_RELOC_STATE_ACTIVE); 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) { 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 */ 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++; } - if (!prio && prev_lbks == breloc->num_lbks) { - return; - } - /* If the band is coming from the defrag process, mark it appropriately */ if (is_defrag) { 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; } - if (!prev_lbks && !prio && !breloc->active) { - TAILQ_INSERT_HEAD(&reloc->pending_queue, breloc, entry); - } - - if (prio) { - struct ftl_band_reloc *iter_breloc; - + if (!prio) { + if (breloc->state == FTL_BAND_RELOC_STATE_INACTIVE) { + breloc->state = FTL_BAND_RELOC_STATE_PENDING; + TAILQ_INSERT_HEAD(&reloc->pending_queue, breloc, entry); + } + } else { + bool active = false; /* If priority band is already on pending or active queue, remove it from it */ - TAILQ_FOREACH(iter_breloc, &reloc->pending_queue, entry) { - if (breloc == iter_breloc) { - TAILQ_REMOVE(&reloc->pending_queue, breloc, entry); - break; - } - } - - TAILQ_FOREACH(iter_breloc, &reloc->active_queue, entry) { - if (breloc == iter_breloc) { - TAILQ_REMOVE(&reloc->active_queue, breloc, entry); - break; - } + switch (breloc->state) { + case FTL_BAND_RELOC_STATE_PENDING: + TAILQ_REMOVE(&reloc->pending_queue, breloc, entry); + break; + case FTL_BAND_RELOC_STATE_ACTIVE: + active = true; + TAILQ_REMOVE(&reloc->active_queue, breloc, entry); + break; + default: + break; } + breloc->state = FTL_BAND_RELOC_STATE_HIGH_PRIO; 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); + } } } diff --git a/test/unit/lib/ftl/ftl_reloc.c/ftl_reloc_ut.c b/test/unit/lib/ftl/ftl_reloc.c/ftl_reloc_ut.c index 53eeb11c4..40b95ebd7 100644 --- a/test/unit/lib/ftl/ftl_reloc.c/ftl_reloc_ut.c +++ b/test/unit/lib/ftl/ftl_reloc.c/ftl_reloc_ut.c @@ -195,6 +195,14 @@ single_reloc_move(struct ftl_band_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 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) @@ -228,7 +236,7 @@ cleanup_reloc(struct spdk_ftl_dev *dev, struct ftl_reloc *reloc) size_t 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); @@ -296,6 +304,7 @@ test_reloc_iter_full(void) /* num_lbks should remain intact since all the blocks are valid */ CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev)); + breloc->state = FTL_BAND_RELOC_STATE_INACTIVE; cleanup_reloc(dev, reloc); } @@ -342,7 +351,8 @@ test_reloc_full_band(void) 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) { single_reloc_move(breloc); @@ -376,7 +386,7 @@ test_reloc_scatter_band(void) breloc = &reloc->brelocs[0]; 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) { 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_active_queue(breloc); + ftl_reloc_prep(breloc); + add_to_active_queue(reloc, breloc); CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev)); @@ -393,9 +404,9 @@ test_reloc_scatter_band(void) single_reloc_move(breloc); } + ftl_process_reloc(breloc); CU_ASSERT_EQUAL(breloc->num_lbks, 0); CU_ASSERT_TRUE(ftl_reloc_done(breloc)); - ftl_reloc_release(breloc); 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_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)); @@ -464,7 +477,8 @@ test_reloc_single_lbk(void) ftl_reloc_add(reloc, band, TEST_RELOC_OFFSET, 1, 0, false); 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);