summaryrefslogtreecommitdiff
path: root/drivers/lightnvm/pblk-gc.c
diff options
context:
space:
mode:
authorJavier González <jg@lightnvm.io>2017-06-26 12:57:17 +0300
committerJens Axboe <axboe@kernel.dk>2017-06-27 01:27:39 +0300
commitdd2a43437337a71c4e26fbbe93a423b731bf69c7 (patch)
tree872eee148f23d19d7e67503b22286af638685f3b /drivers/lightnvm/pblk-gc.c
parent084ec9ba07a00d5ee1218339aab4d52569e35c9b (diff)
downloadlinux-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.c41
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);