diff options
author | Javier González <jg@lightnvm.io> | 2017-06-26 12:57:17 +0300 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2017-06-27 01:27:39 +0300 |
commit | dd2a43437337a71c4e26fbbe93a423b731bf69c7 (patch) | |
tree | 872eee148f23d19d7e67503b22286af638685f3b /drivers/lightnvm/pblk-gc.c | |
parent | 084ec9ba07a00d5ee1218339aab4d52569e35c9b (diff) | |
download | linux-dd2a43437337a71c4e26fbbe93a423b731bf69c7.tar.xz |
lightnvm: pblk: sched. metadata on write thread
At the moment, line metadata is persisted on a separate work queue, that
is kicked each time that a line is closed. The assumption when designing
this was that freeing the write thread from creating a new write request
was better than the potential impact of writes colliding on the media
(user I/O and metadata I/O). Experimentation has proven that this
assumption is wrong; collision can cause up to 25% of bandwidth and
introduce long tail latencies on the write thread, which potentially
cause user write threads to spend more time spinning to get a free entry
on the write buffer.
This patch moves the metadata logic to the write thread. When a line is
closed, remaining metadata is written in memory and is placed on a
metadata queue. The write thread then takes the metadata corresponding
to the previous line, creates the write request and schedules it to
minimize collisions on the media. Using this approach, we see that we
can saturate the media's bandwidth, which helps reducing both write
latencies and the spinning time for user writer threads.
Signed-off-by: Javier González <javier@cnexlabs.com>
Signed-off-by: Matias Bjørling <matias@cnexlabs.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/lightnvm/pblk-gc.c')
-rw-r--r-- | drivers/lightnvm/pblk-gc.c | 41 |
1 files changed, 21 insertions, 20 deletions
diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c index eaf479c6b63c..2e7fb7a51854 100644 --- a/drivers/lightnvm/pblk-gc.c +++ b/drivers/lightnvm/pblk-gc.c @@ -156,7 +156,8 @@ static void pblk_gc_line_ws(struct work_struct *work) struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line *line = line_ws->line; struct pblk_line_meta *lm = &pblk->lm; - __le64 *lba_list = line_ws->priv; + struct line_emeta *emeta_buf = line_ws->priv; + __le64 *lba_list; u64 *gc_list; int sec_left; int nr_ppas, bit; @@ -164,8 +165,18 @@ static void pblk_gc_line_ws(struct work_struct *work) pr_debug("pblk: line '%d' being reclaimed for GC\n", line->id); + /* If this read fails, it means that emeta is corrupted. For now, leave + * the line untouched. TODO: Implement a recovery routine that scans and + * moves all sectors on the line. + */ + lba_list = pblk_recov_get_lba_list(pblk, emeta_buf); + if (!lba_list) { + pr_err("pblk: could not interpret emeta (line %d)\n", line->id); + goto out; + } + spin_lock(&line->lock); - sec_left = line->vsc; + sec_left = le32_to_cpu(*line->vsc); if (!sec_left) { /* Lines are erased before being used (l_mg->data_/log_next) */ spin_unlock(&line->lock); @@ -206,7 +217,7 @@ next_rq: if (pblk_gc_move_valid_secs(pblk, line, gc_list, nr_ppas)) { pr_err("pblk: could not GC all sectors: line:%d (%d/%d/%d)\n", - line->id, line->vsc, + line->id, *line->vsc, nr_ppas, nr_ppas); put_line = 0; pblk_put_line_back(pblk, line); @@ -218,7 +229,7 @@ next_rq: goto next_rq; out: - pblk_mfree(line->emeta, l_mg->emeta_alloc_type); + pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); mempool_free(line_ws, pblk->line_ws_pool); atomic_dec(&pblk->gc.inflight_gc); if (put_line) @@ -229,37 +240,27 @@ static int pblk_gc_line(struct pblk *pblk, struct pblk_line *line) { struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_meta *lm = &pblk->lm; + struct line_emeta *emeta_buf; struct pblk_line_ws *line_ws; - __le64 *lba_list; int ret; line_ws = mempool_alloc(pblk->line_ws_pool, GFP_KERNEL); - line->emeta = pblk_malloc(lm->emeta_len, l_mg->emeta_alloc_type, + emeta_buf = pblk_malloc(lm->emeta_len[0], l_mg->emeta_alloc_type, GFP_KERNEL); - if (!line->emeta) { + if (!emeta_buf) { pr_err("pblk: cannot use GC emeta\n"); goto fail_free_ws; } - ret = pblk_line_read_emeta(pblk, line); + ret = pblk_line_read_emeta(pblk, line, emeta_buf); if (ret) { pr_err("pblk: line %d read emeta failed (%d)\n", line->id, ret); goto fail_free_emeta; } - /* If this read fails, it means that emeta is corrupted. For now, leave - * the line untouched. TODO: Implement a recovery routine that scans and - * moves all sectors on the line. - */ - lba_list = pblk_recov_get_lba_list(pblk, line->emeta); - if (!lba_list) { - pr_err("pblk: could not interpret emeta (line %d)\n", line->id); - goto fail_free_emeta; - } - line_ws->pblk = pblk; line_ws->line = line; - line_ws->priv = lba_list; + line_ws->priv = emeta_buf; INIT_WORK(&line_ws->ws, pblk_gc_line_ws); queue_work(pblk->gc.gc_reader_wq, &line_ws->ws); @@ -267,7 +268,7 @@ static int pblk_gc_line(struct pblk *pblk, struct pblk_line *line) return 0; fail_free_emeta: - pblk_mfree(line->emeta, l_mg->emeta_alloc_type); + pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); fail_free_ws: mempool_free(line_ws, pblk->line_ws_pool); pblk_put_line_back(pblk, line); |