Skip to content

Commit d624f37

Browse files
Javier Gonzálezaxboe
authored andcommitted
lightnvm: pblk: generalize erase path
Erase I/Os are scheduled with the following goals in mind: (i) minimize LUNs collisions with write I/Os, and (ii) even out the price of erasing on every write, instead of putting all the burden on when garbage collection runs. This works well on the current design, but is specific to the default mapping algorithm. This patch generalizes the erase path so that other mapping algorithms can select an arbitrary line to be erased instead. It also gets rid of the erase semaphore since it creates jittering for user writes. 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 c2e9f5d commit d624f37

File tree

6 files changed

+116
-90
lines changed

6 files changed

+116
-90
lines changed

drivers/lightnvm/pblk-core.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ static void pblk_end_io_erase(struct nvm_rq *rqd)
6161
{
6262
struct pblk *pblk = rqd->private;
6363

64-
up(&pblk->erase_sem);
6564
__pblk_end_io_erase(pblk, rqd);
6665
mempool_free(rqd, pblk->r_rq_pool);
6766
}
@@ -1373,7 +1372,8 @@ struct pblk_line *pblk_line_get_data(struct pblk *pblk)
13731372
return pblk->l_mg.data_line;
13741373
}
13751374

1376-
struct pblk_line *pblk_line_get_data_next(struct pblk *pblk)
1375+
/* For now, always erase next line */
1376+
struct pblk_line *pblk_line_get_erase(struct pblk *pblk)
13771377
{
13781378
return pblk->l_mg.data_next;
13791379
}

drivers/lightnvm/pblk-init.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ static int pblk_lines_init(struct pblk *pblk)
545545
struct pblk_line_meta *lm = &pblk->lm;
546546
struct pblk_line *line;
547547
unsigned int smeta_len, emeta_len;
548-
long nr_bad_blks, nr_meta_blks, nr_free_blks;
548+
long nr_bad_blks, nr_free_blks;
549549
int bb_distance;
550550
int i;
551551
int ret;
@@ -591,9 +591,8 @@ static int pblk_lines_init(struct pblk *pblk)
591591
}
592592
lm->emeta_bb = geo->nr_luns - i;
593593

594-
nr_meta_blks = (lm->smeta_sec + lm->emeta_sec +
595-
(geo->sec_per_blk / 2)) / geo->sec_per_blk;
596-
lm->min_blk_line = nr_meta_blks + 1;
594+
lm->min_blk_line = 1 + DIV_ROUND_UP(lm->smeta_sec + lm->emeta_sec,
595+
geo->sec_per_blk);
597596

598597
l_mg->nr_lines = geo->blks_per_lun;
599598
l_mg->log_line = l_mg->data_line = NULL;
@@ -716,8 +715,6 @@ static int pblk_lines_init(struct pblk *pblk)
716715

717716
pblk_set_provision(pblk, nr_free_blks);
718717

719-
sema_init(&pblk->erase_sem, 1);
720-
721718
/* Cleanup per-LUN bad block lists - managed within lines on run-time */
722719
for (i = 0; i < geo->nr_luns; i++)
723720
kfree(pblk->luns[i].bb_list);

drivers/lightnvm/pblk-map.c

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,9 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
9292
{
9393
struct nvm_tgt_dev *dev = pblk->dev;
9494
struct nvm_geo *geo = &dev->geo;
95-
struct pblk_line *e_line = pblk_line_get_data_next(pblk);
95+
struct pblk_line_meta *lm = &pblk->lm;
9696
struct pblk_sec_meta *meta_list = rqd->meta_list;
97+
struct pblk_line *e_line, *d_line;
9798
unsigned int map_secs;
9899
int min = pblk->min_write_pgs;
99100
int i, erase_lun;
@@ -106,32 +107,49 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
106107
erase_lun = rqd->ppa_list[i].g.lun * geo->nr_chnls +
107108
rqd->ppa_list[i].g.ch;
108109

110+
/* line can change after page map */
111+
e_line = pblk_line_get_erase(pblk);
112+
spin_lock(&e_line->lock);
109113
if (!test_bit(erase_lun, e_line->erase_bitmap)) {
110-
if (down_trylock(&pblk->erase_sem))
111-
continue;
112-
113114
set_bit(erase_lun, e_line->erase_bitmap);
114115
atomic_dec(&e_line->left_eblks);
116+
115117
*erase_ppa = rqd->ppa_list[i];
116118
erase_ppa->g.blk = e_line->id;
117119

120+
spin_unlock(&e_line->lock);
121+
118122
/* Avoid evaluating e_line->left_eblks */
119123
return pblk_map_rq(pblk, rqd, sentry, lun_bitmap,
120124
valid_secs, i + min);
121125
}
126+
spin_unlock(&e_line->lock);
122127
}
123128

124-
/* Erase blocks that are bad in this line but might not be in next */
125-
if (unlikely(ppa_empty(*erase_ppa))) {
126-
struct pblk_line_meta *lm = &pblk->lm;
129+
e_line = pblk_line_get_erase(pblk);
130+
d_line = pblk_line_get_data(pblk);
127131

128-
i = find_first_zero_bit(e_line->erase_bitmap, lm->blk_per_line);
129-
if (i == lm->blk_per_line)
132+
/* Erase blocks that are bad in this line but might not be in next */
133+
if (unlikely(ppa_empty(*erase_ppa)) &&
134+
bitmap_weight(d_line->blk_bitmap, lm->blk_per_line)) {
135+
int bit = -1;
136+
137+
retry:
138+
bit = find_next_bit(d_line->blk_bitmap,
139+
lm->blk_per_line, bit + 1);
140+
if (bit >= lm->blk_per_line)
130141
return;
131142

132-
set_bit(i, e_line->erase_bitmap);
143+
spin_lock(&e_line->lock);
144+
if (test_bit(bit, e_line->erase_bitmap)) {
145+
spin_unlock(&e_line->lock);
146+
goto retry;
147+
}
148+
spin_unlock(&e_line->lock);
149+
150+
set_bit(bit, e_line->erase_bitmap);
133151
atomic_dec(&e_line->left_eblks);
134-
*erase_ppa = pblk->luns[i].bppa; /* set ch and lun */
152+
*erase_ppa = pblk->luns[bit].bppa; /* set ch and lun */
135153
erase_ppa->g.blk = e_line->id;
136154
}
137155
}

drivers/lightnvm/pblk-rb.c

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -521,20 +521,19 @@ unsigned int pblk_rb_read_to_bio_list(struct pblk_rb *rb, struct bio *bio,
521521
* This function is used by the write thread to form the write bio that will
522522
* persist data on the write buffer to the media.
523523
*/
524-
unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct bio *bio,
525-
struct pblk_c_ctx *c_ctx,
526-
unsigned int pos,
527-
unsigned int nr_entries,
528-
unsigned int count)
524+
unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct nvm_rq *rqd,
525+
struct bio *bio, unsigned int pos,
526+
unsigned int nr_entries, unsigned int count)
529527
{
530528
struct pblk *pblk = container_of(rb, struct pblk, rwb);
529+
struct request_queue *q = pblk->dev->q;
530+
struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd);
531531
struct pblk_rb_entry *entry;
532532
struct page *page;
533-
unsigned int pad = 0, read = 0, to_read = nr_entries;
533+
unsigned int pad = 0, to_read = nr_entries;
534534
unsigned int user_io = 0, gc_io = 0;
535535
unsigned int i;
536536
int flags;
537-
int ret;
538537

539538
if (count < nr_entries) {
540539
pad = nr_entries - count;
@@ -570,17 +569,17 @@ unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct bio *bio,
570569
flags |= PBLK_SUBMITTED_ENTRY;
571570
/* Release flags on context. Protect from writes */
572571
smp_store_release(&entry->w_ctx.flags, flags);
573-
goto out;
572+
return NVM_IO_ERR;
574573
}
575574

576-
ret = bio_add_page(bio, page, rb->seg_size, 0);
577-
if (ret != rb->seg_size) {
575+
if (bio_add_pc_page(q, bio, page, rb->seg_size, 0) !=
576+
rb->seg_size) {
578577
pr_err("pblk: could not add page to write bio\n");
579578
flags &= ~PBLK_WRITTEN_DATA;
580579
flags |= PBLK_SUBMITTED_ENTRY;
581580
/* Release flags on context. Protect from writes */
582581
smp_store_release(&entry->w_ctx.flags, flags);
583-
goto out;
582+
return NVM_IO_ERR;
584583
}
585584

586585
if (flags & PBLK_FLUSH_ENTRY) {
@@ -607,14 +606,20 @@ unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct bio *bio,
607606
pos = (pos + 1) & (rb->nr_entries - 1);
608607
}
609608

610-
read = to_read;
609+
if (pad) {
610+
if (pblk_bio_add_pages(pblk, bio, GFP_KERNEL, pad)) {
611+
pr_err("pblk: could not pad page in write bio\n");
612+
return NVM_IO_ERR;
613+
}
614+
}
615+
611616
pblk_rl_out(&pblk->rl, user_io, gc_io);
612617
#ifdef CONFIG_NVM_DEBUG
613618
atomic_long_add(pad, &((struct pblk *)
614619
(container_of(rb, struct pblk, rwb)))->padded_writes);
615620
#endif
616-
out:
617-
return read;
621+
622+
return NVM_IO_OK;
618623
}
619624

620625
/*

drivers/lightnvm/pblk-write.c

Lines changed: 59 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -219,52 +219,34 @@ static int pblk_alloc_w_rq(struct pblk *pblk, struct nvm_rq *rqd,
219219
}
220220

221221
static int pblk_setup_w_rq(struct pblk *pblk, struct nvm_rq *rqd,
222-
struct pblk_c_ctx *c_ctx)
222+
struct pblk_c_ctx *c_ctx, struct ppa_addr *erase_ppa)
223223
{
224224
struct pblk_line_meta *lm = &pblk->lm;
225-
struct pblk_line *e_line = pblk_line_get_data_next(pblk);
226-
struct ppa_addr erase_ppa;
225+
struct pblk_line *e_line = pblk_line_get_erase(pblk);
227226
unsigned int valid = c_ctx->nr_valid;
228227
unsigned int padded = c_ctx->nr_padded;
229228
unsigned int nr_secs = valid + padded;
230229
unsigned long *lun_bitmap;
231230
int ret = 0;
232231

233232
lun_bitmap = kzalloc(lm->lun_bitmap_len, GFP_KERNEL);
234-
if (!lun_bitmap) {
235-
ret = -ENOMEM;
236-
goto out;
237-
}
233+
if (!lun_bitmap)
234+
return -ENOMEM;
238235
c_ctx->lun_bitmap = lun_bitmap;
239236

240237
ret = pblk_alloc_w_rq(pblk, rqd, nr_secs);
241238
if (ret) {
242239
kfree(lun_bitmap);
243-
goto out;
240+
return ret;
244241
}
245242

246-
ppa_set_empty(&erase_ppa);
247-
if (likely(!e_line || !atomic_read(&e_line->left_eblks)))
243+
if (likely(!atomic_read(&e_line->left_eblks) || !e_line))
248244
pblk_map_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, valid, 0);
249245
else
250246
pblk_map_erase_rq(pblk, rqd, c_ctx->sentry, lun_bitmap,
251-
valid, &erase_ppa);
247+
valid, erase_ppa);
252248

253-
out:
254-
if (unlikely(e_line && !ppa_empty(erase_ppa))) {
255-
if (pblk_blk_erase_async(pblk, erase_ppa)) {
256-
struct nvm_tgt_dev *dev = pblk->dev;
257-
struct nvm_geo *geo = &dev->geo;
258-
int bit;
259-
260-
atomic_inc(&e_line->left_eblks);
261-
bit = erase_ppa.g.lun * geo->nr_chnls + erase_ppa.g.ch;
262-
WARN_ON(!test_and_clear_bit(bit, e_line->erase_bitmap));
263-
up(&pblk->erase_sem);
264-
}
265-
}
266-
267-
return ret;
249+
return 0;
268250
}
269251

270252
int pblk_setup_w_rec_rq(struct pblk *pblk, struct nvm_rq *rqd,
@@ -311,16 +293,60 @@ static int pblk_calc_secs_to_sync(struct pblk *pblk, unsigned int secs_avail,
311293
return secs_to_sync;
312294
}
313295

296+
static int pblk_submit_io_set(struct pblk *pblk, struct nvm_rq *rqd)
297+
{
298+
struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd);
299+
struct ppa_addr erase_ppa;
300+
int err;
301+
302+
ppa_set_empty(&erase_ppa);
303+
304+
/* Assign lbas to ppas and populate request structure */
305+
err = pblk_setup_w_rq(pblk, rqd, c_ctx, &erase_ppa);
306+
if (err) {
307+
pr_err("pblk: could not setup write request: %d\n", err);
308+
return NVM_IO_ERR;
309+
}
310+
311+
/* Submit write for current data line */
312+
err = pblk_submit_io(pblk, rqd);
313+
if (err) {
314+
pr_err("pblk: I/O submission failed: %d\n", err);
315+
return NVM_IO_ERR;
316+
}
317+
318+
/* Submit available erase for next data line */
319+
if (unlikely(!ppa_empty(erase_ppa)) &&
320+
pblk_blk_erase_async(pblk, erase_ppa)) {
321+
struct pblk_line *e_line = pblk_line_get_erase(pblk);
322+
struct nvm_tgt_dev *dev = pblk->dev;
323+
struct nvm_geo *geo = &dev->geo;
324+
int bit;
325+
326+
atomic_inc(&e_line->left_eblks);
327+
bit = erase_ppa.g.lun * geo->nr_chnls + erase_ppa.g.ch;
328+
WARN_ON(!test_and_clear_bit(bit, e_line->erase_bitmap));
329+
}
330+
331+
return NVM_IO_OK;
332+
}
333+
334+
static void pblk_free_write_rqd(struct pblk *pblk, struct nvm_rq *rqd)
335+
{
336+
struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd);
337+
struct bio *bio = rqd->bio;
338+
339+
if (c_ctx->nr_padded)
340+
pblk_bio_free_pages(pblk, bio, rqd->nr_ppas, c_ctx->nr_padded);
341+
}
342+
314343
static int pblk_submit_write(struct pblk *pblk)
315344
{
316345
struct bio *bio;
317346
struct nvm_rq *rqd;
318-
struct pblk_c_ctx *c_ctx;
319-
unsigned int pgs_read;
320347
unsigned int secs_avail, secs_to_sync, secs_to_com;
321348
unsigned int secs_to_flush;
322349
unsigned long pos;
323-
int err;
324350

325351
/* If there are no sectors in the cache, flushes (bios without data)
326352
* will be cleared on the cache threads
@@ -338,7 +364,6 @@ static int pblk_submit_write(struct pblk *pblk)
338364
pr_err("pblk: cannot allocate write req.\n");
339365
return 1;
340366
}
341-
c_ctx = nvm_rq_to_pdu(rqd);
342367

343368
bio = bio_alloc(GFP_KERNEL, pblk->max_write_pgs);
344369
if (!bio) {
@@ -358,29 +383,14 @@ static int pblk_submit_write(struct pblk *pblk)
358383
secs_to_com = (secs_to_sync > secs_avail) ? secs_avail : secs_to_sync;
359384
pos = pblk_rb_read_commit(&pblk->rwb, secs_to_com);
360385

361-
pgs_read = pblk_rb_read_to_bio(&pblk->rwb, bio, c_ctx, pos,
362-
secs_to_sync, secs_avail);
363-
if (!pgs_read) {
386+
if (pblk_rb_read_to_bio(&pblk->rwb, rqd, bio, pos, secs_to_sync,
387+
secs_avail)) {
364388
pr_err("pblk: corrupted write bio\n");
365389
goto fail_put_bio;
366390
}
367391

368-
if (c_ctx->nr_padded)
369-
if (pblk_bio_add_pages(pblk, bio, GFP_KERNEL, c_ctx->nr_padded))
370-
goto fail_put_bio;
371-
372-
/* Assign lbas to ppas and populate request structure */
373-
err = pblk_setup_w_rq(pblk, rqd, c_ctx);
374-
if (err) {
375-
pr_err("pblk: could not setup write request\n");
392+
if (pblk_submit_io_set(pblk, rqd))
376393
goto fail_free_bio;
377-
}
378-
379-
err = pblk_submit_io(pblk, rqd);
380-
if (err) {
381-
pr_err("pblk: I/O submission failed: %d\n", err);
382-
goto fail_free_bio;
383-
}
384394

385395
#ifdef CONFIG_NVM_DEBUG
386396
atomic_long_add(secs_to_sync, &pblk->sub_writes);
@@ -389,8 +399,7 @@ static int pblk_submit_write(struct pblk *pblk)
389399
return 0;
390400

391401
fail_free_bio:
392-
if (c_ctx->nr_padded)
393-
pblk_bio_free_pages(pblk, bio, secs_to_sync, c_ctx->nr_padded);
402+
pblk_free_write_rqd(pblk, rqd);
394403
fail_put_bio:
395404
bio_put(bio);
396405
fail_free_rqd:

drivers/lightnvm/pblk.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,6 @@ struct pblk {
500500
struct pblk_rl rl;
501501

502502
int sec_per_write;
503-
struct semaphore erase_sem;
504503

505504
unsigned char instance_uuid[16];
506505
#ifdef CONFIG_NVM_DEBUG
@@ -583,11 +582,9 @@ void pblk_rb_write_entry_gc(struct pblk_rb *rb, void *data,
583582
struct pblk_w_ctx *pblk_rb_w_ctx(struct pblk_rb *rb, unsigned int pos);
584583

585584
void pblk_rb_sync_l2p(struct pblk_rb *rb);
586-
unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct bio *bio,
587-
struct pblk_c_ctx *c_ctx,
588-
unsigned int pos,
589-
unsigned int nr_entries,
590-
unsigned int count);
585+
unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct nvm_rq *rqd,
586+
struct bio *bio, unsigned int pos,
587+
unsigned int nr_entries, unsigned int count);
591588
unsigned int pblk_rb_read_to_bio_list(struct pblk_rb *rb, struct bio *bio,
592589
struct list_head *list,
593590
unsigned int max);
@@ -633,7 +630,7 @@ struct pblk_line *pblk_line_replace_data(struct pblk *pblk);
633630
int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line);
634631
void pblk_line_recov_close(struct pblk *pblk, struct pblk_line *line);
635632
struct pblk_line *pblk_line_get_data(struct pblk *pblk);
636-
struct pblk_line *pblk_line_get_data_next(struct pblk *pblk);
633+
struct pblk_line *pblk_line_get_erase(struct pblk *pblk);
637634
int pblk_line_erase(struct pblk *pblk, struct pblk_line *line);
638635
int pblk_line_is_full(struct pblk_line *line);
639636
void pblk_line_free(struct pblk *pblk, struct pblk_line *line);

0 commit comments

Comments
 (0)