Skip to content

Commit dd2a434

Browse files
Javier Gonzálezaxboe
authored andcommitted
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 <[email protected]> Signed-off-by: Matias Bjørling <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 084ec9b commit dd2a434

File tree

8 files changed

+673
-285
lines changed

8 files changed

+673
-285
lines changed

drivers/lightnvm/pblk-core.c

Lines changed: 137 additions & 79 deletions
Large diffs are not rendered by default.

drivers/lightnvm/pblk-gc.c

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,27 @@ static void pblk_gc_line_ws(struct work_struct *work)
156156
struct pblk_line_mgmt *l_mg = &pblk->l_mg;
157157
struct pblk_line *line = line_ws->line;
158158
struct pblk_line_meta *lm = &pblk->lm;
159-
__le64 *lba_list = line_ws->priv;
159+
struct line_emeta *emeta_buf = line_ws->priv;
160+
__le64 *lba_list;
160161
u64 *gc_list;
161162
int sec_left;
162163
int nr_ppas, bit;
163164
int put_line = 1;
164165

165166
pr_debug("pblk: line '%d' being reclaimed for GC\n", line->id);
166167

168+
/* If this read fails, it means that emeta is corrupted. For now, leave
169+
* the line untouched. TODO: Implement a recovery routine that scans and
170+
* moves all sectors on the line.
171+
*/
172+
lba_list = pblk_recov_get_lba_list(pblk, emeta_buf);
173+
if (!lba_list) {
174+
pr_err("pblk: could not interpret emeta (line %d)\n", line->id);
175+
goto out;
176+
}
177+
167178
spin_lock(&line->lock);
168-
sec_left = line->vsc;
179+
sec_left = le32_to_cpu(*line->vsc);
169180
if (!sec_left) {
170181
/* Lines are erased before being used (l_mg->data_/log_next) */
171182
spin_unlock(&line->lock);
@@ -206,7 +217,7 @@ static void pblk_gc_line_ws(struct work_struct *work)
206217

207218
if (pblk_gc_move_valid_secs(pblk, line, gc_list, nr_ppas)) {
208219
pr_err("pblk: could not GC all sectors: line:%d (%d/%d/%d)\n",
209-
line->id, line->vsc,
220+
line->id, *line->vsc,
210221
nr_ppas, nr_ppas);
211222
put_line = 0;
212223
pblk_put_line_back(pblk, line);
@@ -218,7 +229,7 @@ static void pblk_gc_line_ws(struct work_struct *work)
218229
goto next_rq;
219230

220231
out:
221-
pblk_mfree(line->emeta, l_mg->emeta_alloc_type);
232+
pblk_mfree(emeta_buf, l_mg->emeta_alloc_type);
222233
mempool_free(line_ws, pblk->line_ws_pool);
223234
atomic_dec(&pblk->gc.inflight_gc);
224235
if (put_line)
@@ -229,45 +240,35 @@ static int pblk_gc_line(struct pblk *pblk, struct pblk_line *line)
229240
{
230241
struct pblk_line_mgmt *l_mg = &pblk->l_mg;
231242
struct pblk_line_meta *lm = &pblk->lm;
243+
struct line_emeta *emeta_buf;
232244
struct pblk_line_ws *line_ws;
233-
__le64 *lba_list;
234245
int ret;
235246

236247
line_ws = mempool_alloc(pblk->line_ws_pool, GFP_KERNEL);
237-
line->emeta = pblk_malloc(lm->emeta_len, l_mg->emeta_alloc_type,
248+
emeta_buf = pblk_malloc(lm->emeta_len[0], l_mg->emeta_alloc_type,
238249
GFP_KERNEL);
239-
if (!line->emeta) {
250+
if (!emeta_buf) {
240251
pr_err("pblk: cannot use GC emeta\n");
241252
goto fail_free_ws;
242253
}
243254

244-
ret = pblk_line_read_emeta(pblk, line);
255+
ret = pblk_line_read_emeta(pblk, line, emeta_buf);
245256
if (ret) {
246257
pr_err("pblk: line %d read emeta failed (%d)\n", line->id, ret);
247258
goto fail_free_emeta;
248259
}
249260

250-
/* If this read fails, it means that emeta is corrupted. For now, leave
251-
* the line untouched. TODO: Implement a recovery routine that scans and
252-
* moves all sectors on the line.
253-
*/
254-
lba_list = pblk_recov_get_lba_list(pblk, line->emeta);
255-
if (!lba_list) {
256-
pr_err("pblk: could not interpret emeta (line %d)\n", line->id);
257-
goto fail_free_emeta;
258-
}
259-
260261
line_ws->pblk = pblk;
261262
line_ws->line = line;
262-
line_ws->priv = lba_list;
263+
line_ws->priv = emeta_buf;
263264

264265
INIT_WORK(&line_ws->ws, pblk_gc_line_ws);
265266
queue_work(pblk->gc.gc_reader_wq, &line_ws->ws);
266267

267268
return 0;
268269

269270
fail_free_emeta:
270-
pblk_mfree(line->emeta, l_mg->emeta_alloc_type);
271+
pblk_mfree(emeta_buf, l_mg->emeta_alloc_type);
271272
fail_free_ws:
272273
mempool_free(line_ws, pblk->line_ws_pool);
273274
pblk_put_line_back(pblk, line);

0 commit comments

Comments
 (0)