lib/ftl: Read partially lba map during relocation

Read requested range of lba map during relocation
instead whole lba map.

To read partial lba map range single move now has
three states: read, read_lba_map and write.

Free queue and write queue were merged to a single
move queue.

Change-Id: I86839f2286d42d4debf87cea40091370e5283b15
Signed-off-by: Wojciech Malikowski <wojciech.malikowski@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/454747
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Wojciech Malikowski 2019-05-14 09:21:33 -04:00 committed by Darek Stojaczyk
parent a1f1581968
commit 675c4aa743
2 changed files with 116 additions and 100 deletions

View File

@ -48,6 +48,12 @@
struct ftl_reloc; struct ftl_reloc;
struct ftl_band_reloc; struct ftl_band_reloc;
enum ftl_reloc_move_state {
FTL_RELOC_STATE_READ_LBA_MAP,
FTL_RELOC_STATE_READ,
FTL_RELOC_STATE_WRITE,
};
struct ftl_reloc_move { struct ftl_reloc_move {
struct ftl_band_reloc *breloc; struct ftl_band_reloc *breloc;
@ -60,6 +66,9 @@ struct ftl_reloc_move {
/* Data buffer */ /* Data buffer */
void *data; void *data;
/* Move state (read lba_map, read, write) */
enum ftl_reloc_move_state state;
/* IO associated with move */ /* IO associated with move */
struct ftl_io *io; struct ftl_io *io;
}; };
@ -88,14 +97,14 @@ struct ftl_band_reloc {
size_t chk_current; size_t chk_current;
} iter; } iter;
/* Number of outstanding moves */
size_t num_outstanding;
/* Pool of move objects */ /* Pool of move objects */
struct ftl_reloc_move *moves; struct ftl_reloc_move *moves;
/* Free IO queue */ /* Move queue */
struct spdk_ring *free_queue; struct spdk_ring *move_queue;
/* Queue of IO ready to be written */
struct spdk_ring *write_queue;
TAILQ_ENTRY(ftl_band_reloc) entry; TAILQ_ENTRY(ftl_band_reloc) entry;
}; };
@ -132,8 +141,6 @@ struct ftl_reloc {
TAILQ_HEAD(, ftl_band_reloc) pending_queue; TAILQ_HEAD(, ftl_band_reloc) pending_queue;
}; };
typedef int (*ftl_reloc_fn)(struct ftl_band_reloc *, struct ftl_reloc_move *);
static size_t static size_t
ftl_reloc_iter_chk_offset(struct ftl_band_reloc *breloc) ftl_reloc_iter_chk_offset(struct ftl_band_reloc *breloc)
{ {
@ -162,18 +169,6 @@ ftl_reloc_clr_lbk(struct ftl_band_reloc *breloc, size_t lbkoff)
breloc->num_lbks--; breloc->num_lbks--;
} }
static void
_ftl_reloc_prep(struct ftl_band_reloc *breloc)
{
struct ftl_reloc *reloc = breloc->parent;
struct ftl_reloc_move *move;
size_t i;
for (i = 0; i < reloc->max_qdepth; ++i) {
move = &breloc->moves[i];
spdk_ring_enqueue(breloc->free_queue, (void **)&move, 1, NULL);
}
}
static void static void
ftl_reloc_read_lba_map_cb(struct ftl_io *io, void *arg, int status) ftl_reloc_read_lba_map_cb(struct ftl_io *io, void *arg, int status)
@ -181,25 +176,20 @@ ftl_reloc_read_lba_map_cb(struct ftl_io *io, void *arg, int status)
struct ftl_reloc_move *move = arg; struct ftl_reloc_move *move = arg;
struct ftl_band_reloc *breloc = move->breloc; struct ftl_band_reloc *breloc = move->breloc;
breloc->num_outstanding--;
assert(status == 0); assert(status == 0);
_ftl_reloc_prep(breloc); move->state = FTL_RELOC_STATE_WRITE;
spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL);
} }
static int static int
ftl_reloc_read_lba_map(struct ftl_band_reloc *breloc) ftl_reloc_read_lba_map(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move)
{ {
struct ftl_band *band = breloc->band; struct ftl_band *band = breloc->band;
struct spdk_ftl_dev *dev = band->dev;
struct ftl_reloc_move *move = &breloc->moves[0];
move->breloc = breloc; breloc->num_outstanding++;
return ftl_band_read_lba_map(band, ftl_band_lbkoff_from_ppa(band, move->ppa),
if (ftl_band_alloc_lba_map(band)) { move->lbk_cnt, ftl_reloc_read_lba_map_cb, move);
assert(false);
}
return ftl_band_read_lba_map(band, 0, ftl_num_band_lbks(dev),
ftl_reloc_read_lba_map_cb, move);
} }
static void static void
@ -207,17 +197,23 @@ ftl_reloc_prep(struct ftl_band_reloc *breloc)
{ {
struct ftl_band *band = breloc->band; struct ftl_band *band = breloc->band;
struct ftl_reloc *reloc = breloc->parent; struct ftl_reloc *reloc = breloc->parent;
struct ftl_reloc_move *move;
size_t i;
breloc->active = 1; breloc->active = 1;
reloc->num_active++; reloc->num_active++;
if (!band->high_prio) { if (!band->high_prio) {
assert(band->lba_map.map == NULL); if (ftl_band_alloc_lba_map(band)) {
ftl_reloc_read_lba_map(breloc); assert(false);
return; }
} }
_ftl_reloc_prep(breloc); for (i = 0; i < reloc->max_qdepth; ++i) {
move = &breloc->moves[i];
move->state = FTL_RELOC_STATE_READ;
spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL);
}
} }
static void static void
@ -226,7 +222,8 @@ ftl_reloc_free_move(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move)
assert(move); assert(move);
spdk_dma_free(move->data); spdk_dma_free(move->data);
memset(move, 0, sizeof(*move)); memset(move, 0, sizeof(*move));
spdk_ring_enqueue(breloc->free_queue, (void **)&move, 1, NULL); move->state = FTL_RELOC_STATE_READ;
spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL);
} }
static void static void
@ -237,6 +234,8 @@ ftl_reloc_write_cb(struct ftl_io *io, void *arg, int status)
struct ftl_band_reloc *breloc = move->breloc; struct ftl_band_reloc *breloc = move->breloc;
size_t i; size_t i;
breloc->num_outstanding--;
if (status) { if (status) {
SPDK_ERRLOG("Reloc write failed with status: %d\n", status); SPDK_ERRLOG("Reloc write failed with status: %d\n", status);
assert(false); assert(false);
@ -258,6 +257,8 @@ ftl_reloc_read_cb(struct ftl_io *io, void *arg, int status)
struct ftl_reloc_move *move = arg; struct ftl_reloc_move *move = arg;
struct ftl_band_reloc *breloc = move->breloc; struct ftl_band_reloc *breloc = move->breloc;
breloc->num_outstanding--;
/* TODO: We should handle fail on relocation read. We need to inform */ /* TODO: We should handle fail on relocation read. We need to inform */
/* user that this group of blocks is bad (update l2p with bad block address and */ /* user that this group of blocks is bad (update l2p with bad block address and */
/* put it to lba_map/sector_lba). Maybe we could also retry read with smaller granularity? */ /* put it to lba_map/sector_lba). Maybe we could also retry read with smaller granularity? */
@ -267,8 +268,9 @@ ftl_reloc_read_cb(struct ftl_io *io, void *arg, int status)
return; return;
} }
move->state = FTL_RELOC_STATE_READ_LBA_MAP;
move->io = NULL; move->io = NULL;
spdk_ring_enqueue(breloc->write_queue, (void **)&move, 1, NULL); spdk_ring_enqueue(breloc->move_queue, (void **)&move, 1, NULL);
} }
static void static void
@ -448,6 +450,7 @@ ftl_reloc_write(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move)
} }
} }
breloc->num_outstanding++;
ftl_io_write(move->io); ftl_io_write(move->io);
return 0; return 0;
} }
@ -455,14 +458,13 @@ ftl_reloc_write(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move)
static int static int
ftl_reloc_read(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move) ftl_reloc_read(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move)
{ {
struct ftl_ppa ppa; struct ftl_ppa ppa = {};
move->lbk_cnt = ftl_reloc_next_lbks(breloc, &ppa); move->lbk_cnt = ftl_reloc_next_lbks(breloc, &ppa);
move->breloc = breloc; move->breloc = breloc;
move->ppa = ppa; move->ppa = ppa;
if (!move->lbk_cnt) { if (!move->lbk_cnt) {
spdk_ring_enqueue(breloc->free_queue, (void **)&move, 1, NULL);
return 0; return 0;
} }
@ -478,55 +480,50 @@ ftl_reloc_read(struct ftl_band_reloc *breloc, struct ftl_reloc_move *move)
return -1; return -1;
} }
breloc->num_outstanding++;
ftl_io_read(move->io); ftl_io_read(move->io);
return 0; return 0;
} }
static void static void
ftl_reloc_process_queue(struct ftl_band_reloc *breloc, struct spdk_ring *queue, ftl_reloc_process_moves(struct ftl_band_reloc *breloc)
ftl_reloc_fn fn)
{ {
int rc = 0;
size_t i, num_moves; size_t i, num_moves;
struct ftl_reloc_move *moves[FTL_RELOC_MAX_MOVES]; struct ftl_reloc_move *moves[FTL_RELOC_MAX_MOVES];
struct ftl_reloc *reloc = breloc->parent; struct ftl_reloc *reloc = breloc->parent;
struct ftl_reloc_move *move;
num_moves = spdk_ring_dequeue(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) {
if (fn(breloc, moves[i])) { move = moves[i];
SPDK_ERRLOG("Reloc queue processing failed\n"); switch (move->state) {
case FTL_RELOC_STATE_READ_LBA_MAP:
rc = ftl_reloc_read_lba_map(breloc, move);
break;
case FTL_RELOC_STATE_READ:
rc = ftl_reloc_read(breloc, move);
break;
case FTL_RELOC_STATE_WRITE:
rc = ftl_reloc_write(breloc, move);
break;
default:
assert(false);
break;
}
if (rc) {
SPDK_ERRLOG("Move queue processing failed\n");
assert(false); assert(false);
} }
} }
} }
static void static bool
ftl_reloc_process_write_queue(struct ftl_band_reloc *breloc)
{
ftl_reloc_process_queue(breloc, breloc->write_queue, ftl_reloc_write);
}
static void
ftl_reloc_process_free_queue(struct ftl_band_reloc *breloc)
{
ftl_reloc_process_queue(breloc, breloc->free_queue, ftl_reloc_read);
}
static int
ftl_reloc_done(struct ftl_band_reloc *breloc) ftl_reloc_done(struct ftl_band_reloc *breloc)
{ {
struct ftl_reloc *reloc = breloc->parent; return !breloc->num_outstanding && !spdk_ring_count(breloc->move_queue);
return spdk_ring_count(breloc->free_queue) == reloc->max_qdepth;
}
static void
ftl_reloc_release_moves(struct ftl_band_reloc *breloc)
{
struct ftl_reloc *reloc = breloc->parent;
struct ftl_reloc_move *moves[FTL_RELOC_MAX_MOVES];
spdk_ring_dequeue(breloc->free_queue, (void **)moves, reloc->max_qdepth);
} }
static void static void
@ -542,8 +539,8 @@ ftl_reloc_release(struct ftl_band_reloc *breloc)
TAILQ_REMOVE(&reloc->active_queue, breloc, entry); TAILQ_REMOVE(&reloc->active_queue, breloc, entry);
} }
ftl_reloc_release_moves(breloc);
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; breloc->active = 0;
@ -562,9 +559,7 @@ ftl_reloc_release(struct ftl_band_reloc *breloc)
static void static void
ftl_process_reloc(struct ftl_band_reloc *breloc) ftl_process_reloc(struct ftl_band_reloc *breloc)
{ {
ftl_reloc_process_free_queue(breloc); ftl_reloc_process_moves(breloc);
ftl_reloc_process_write_queue(breloc);
if (ftl_reloc_done(breloc)) { if (ftl_reloc_done(breloc)) {
ftl_reloc_release(breloc); ftl_reloc_release(breloc);
@ -591,18 +586,10 @@ ftl_band_reloc_init(struct ftl_reloc *reloc, struct ftl_band_reloc *breloc,
return -1; return -1;
} }
breloc->free_queue = spdk_ring_create(SPDK_RING_TYPE_MP_SC, breloc->move_queue = spdk_ring_create(SPDK_RING_TYPE_MP_SC,
reloc->max_qdepth * 2, reloc->max_qdepth * 2,
SPDK_ENV_SOCKET_ID_ANY); SPDK_ENV_SOCKET_ID_ANY);
if (!breloc->free_queue) { if (!breloc->move_queue) {
SPDK_ERRLOG("Failed to initialize reloc free queue");
return -1;
}
breloc->write_queue = spdk_ring_create(SPDK_RING_TYPE_MP_SC,
reloc->max_qdepth * 2,
SPDK_ENV_SOCKET_ID_ANY);
if (!breloc->write_queue) {
SPDK_ERRLOG("Failed to initialize reloc write queue"); SPDK_ERRLOG("Failed to initialize reloc write queue");
return -1; return -1;
} }
@ -626,21 +613,19 @@ ftl_band_reloc_free(struct ftl_band_reloc *breloc)
return; return;
} }
assert(breloc->num_outstanding == 0);
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->active) {
assert(reloc->halt); assert(reloc->halt);
num_moves = spdk_ring_dequeue(breloc->write_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) {
ftl_reloc_free_move(breloc, moves[i]); ftl_reloc_free_move(breloc, moves[i]);
} }
ftl_reloc_release_moves(breloc);
} }
spdk_ring_free(breloc->free_queue); spdk_ring_free(breloc->move_queue);
spdk_ring_free(breloc->write_queue);
spdk_bit_array_free(&breloc->reloc_map); spdk_bit_array_free(&breloc->reloc_map);
free(breloc->iter.chk_offset); free(breloc->iter.chk_offset);
free(breloc->moves); free(breloc->moves);

View File

@ -183,6 +183,17 @@ ftl_io_reinit(struct ftl_io *io, ftl_io_fn fn, void *ctx, int flags, int type)
io->type = type; io->type = type;
} }
static void
single_reloc_move(struct ftl_band_reloc *breloc)
{
/* Process read */
ftl_process_reloc(breloc);
/* Process lba map read */
ftl_process_reloc(breloc);
/* Process write */
ftl_process_reloc(breloc);
}
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)
@ -318,14 +329,14 @@ test_reloc_full_band(void)
struct ftl_reloc *reloc; struct ftl_reloc *reloc;
struct ftl_band_reloc *breloc; struct ftl_band_reloc *breloc;
struct ftl_band *band; struct ftl_band *band;
size_t num_io, num_iters, num_lbk, i; size_t num_moves, num_iters, num_lbk, i;
setup_reloc(&dev, &reloc, &g_geo, &g_range); setup_reloc(&dev, &reloc, &g_geo, &g_range);
breloc = &reloc->brelocs[0]; breloc = &reloc->brelocs[0];
band = breloc->band; band = breloc->band;
num_io = MAX_RELOC_QDEPTH * reloc->xfer_size; num_moves = MAX_RELOC_QDEPTH * reloc->xfer_size;
num_iters = ftl_num_band_lbks(dev) / num_io; num_iters = ftl_num_band_lbks(dev) / num_moves;
set_band_valid_map(band, 0, ftl_num_band_lbks(dev)); set_band_valid_map(band, 0, ftl_num_band_lbks(dev));
@ -333,16 +344,23 @@ 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));
for (i = 0; i < num_iters; ++i) { ftl_reloc_add_active_queue(breloc);
num_lbk = ftl_num_band_lbks(dev) - (i * num_io);
for (i = 1; i <= num_iters; ++i) {
single_reloc_move(breloc);
num_lbk = ftl_num_band_lbks(dev) - (i * num_moves);
CU_ASSERT_EQUAL(breloc->num_lbks, num_lbk); CU_ASSERT_EQUAL(breloc->num_lbks, num_lbk);
ftl_reloc(reloc);
} }
ftl_reloc(reloc); /* Process reminder lbks */
single_reloc_move(breloc);
/* Drain move queue */
ftl_reloc_process_moves(breloc);
CU_ASSERT_EQUAL(breloc->num_lbks, 0); CU_ASSERT_EQUAL(breloc->num_lbks, 0);
CU_ASSERT_TRUE(ftl_reloc_done(breloc));
ftl_reloc_release(breloc);
cleanup_reloc(dev, reloc); cleanup_reloc(dev, reloc);
} }
@ -369,14 +387,17 @@ test_reloc_scatter_band(void)
} }
ftl_reloc_add(reloc, band, 0, ftl_num_band_lbks(dev), 0); ftl_reloc_add(reloc, band, 0, ftl_num_band_lbks(dev), 0);
ftl_reloc_add_active_queue(breloc);
CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev)); CU_ASSERT_EQUAL(breloc->num_lbks, ftl_num_band_lbks(dev));
for (i = 0; i < num_iters ; ++i) { for (i = 0; i < num_iters ; ++i) {
ftl_reloc(reloc); single_reloc_move(breloc);
} }
CU_ASSERT_EQUAL(breloc->num_lbks, 0); CU_ASSERT_EQUAL(breloc->num_lbks, 0);
CU_ASSERT_TRUE(ftl_reloc_done(breloc));
ftl_reloc_release(breloc);
cleanup_reloc(dev, reloc); cleanup_reloc(dev, reloc);
} }
@ -401,20 +422,25 @@ 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); ftl_dev_lbks_in_chunk(dev), 1);
ftl_reloc_add_active_queue(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));
for (i = 0; i < num_iters ; ++i) { for (i = 1; i <= num_iters ; ++i) {
ftl_reloc(reloc); single_reloc_move(breloc);
num_lbk = ftl_dev_lbks_in_chunk(dev) - (i * num_io); num_lbk = ftl_dev_lbks_in_chunk(dev) - (i * num_io);
CU_ASSERT_EQUAL(breloc->num_lbks, num_lbk); CU_ASSERT_EQUAL(breloc->num_lbks, num_lbk);
} }
/* In case num_lbks_in_chunk % num_io != 0 one extra iteration is needed */ /* In case num_lbks_in_chunk % num_io != 0 one extra iteration is needed */
ftl_reloc(reloc); single_reloc_move(breloc);
/* Drain move queue */
ftl_reloc_process_moves(breloc);
CU_ASSERT_EQUAL(breloc->num_lbks, 0); CU_ASSERT_EQUAL(breloc->num_lbks, 0);
CU_ASSERT_TRUE(ftl_reloc_done(breloc));
ftl_reloc_release(breloc);
cleanup_reloc(dev, reloc); cleanup_reloc(dev, reloc);
} }
@ -436,12 +462,17 @@ test_reloc_single_lbk(void)
set_band_valid_map(band, TEST_RELOC_OFFSET, 1); set_band_valid_map(band, TEST_RELOC_OFFSET, 1);
ftl_reloc_add(reloc, band, TEST_RELOC_OFFSET, 1, 0); ftl_reloc_add(reloc, band, TEST_RELOC_OFFSET, 1, 0);
ftl_reloc_add_active_queue(breloc);
CU_ASSERT_EQUAL(breloc->num_lbks, 1); CU_ASSERT_EQUAL(breloc->num_lbks, 1);
ftl_reloc(reloc); single_reloc_move(breloc);
/* Drain move queue */
ftl_reloc_process_moves(breloc);
CU_ASSERT_EQUAL(breloc->num_lbks, 0); CU_ASSERT_EQUAL(breloc->num_lbks, 0);
CU_ASSERT_TRUE(ftl_reloc_done(breloc));
ftl_reloc_release(breloc);
cleanup_reloc(dev, reloc); cleanup_reloc(dev, reloc);
} }