diff options
author | Javier González <jg@lightnvm.io> | 2017-07-07 15:08:52 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2017-07-07 15:17:34 -0400 |
commit | 3eaa11e2780dc38350c133bd998cac1df488d040 (patch) | |
tree | 72f51ca76c7ae028386bd614220faf97d56b1cfd | |
parent | 0e2ff11311d1d4c85dd9ad9ba4347775f628e94a (diff) |
lightnvm: pblk: control I/O flow also on tear down
When removing a pblk instance, control the write I/O flow to the
controller as we do in the fast path.
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>
-rw-r--r-- | drivers/lightnvm/pblk-core.c | 61 | ||||
-rw-r--r-- | drivers/lightnvm/pblk-recovery.c | 31 | ||||
-rw-r--r-- | drivers/lightnvm/pblk-write.c | 19 | ||||
-rw-r--r-- | drivers/lightnvm/pblk.h | 2 |
4 files changed, 78 insertions, 35 deletions
diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c index 11fe0c5b2a9c..81501644fb15 100644 --- a/drivers/lightnvm/pblk-core.c +++ b/drivers/lightnvm/pblk-core.c | |||
@@ -1670,13 +1670,10 @@ void pblk_line_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv, | |||
1670 | queue_work(wq, &line_ws->ws); | 1670 | queue_work(wq, &line_ws->ws); |
1671 | } | 1671 | } |
1672 | 1672 | ||
1673 | void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, | 1673 | static void __pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list, |
1674 | unsigned long *lun_bitmap) | 1674 | int nr_ppas, int pos) |
1675 | { | 1675 | { |
1676 | struct nvm_tgt_dev *dev = pblk->dev; | 1676 | struct pblk_lun *rlun = &pblk->luns[pos]; |
1677 | struct nvm_geo *geo = &dev->geo; | ||
1678 | struct pblk_lun *rlun; | ||
1679 | int pos = pblk_ppa_to_pos(geo, ppa_list[0]); | ||
1680 | int ret; | 1677 | int ret; |
1681 | 1678 | ||
1682 | /* | 1679 | /* |
@@ -1690,14 +1687,8 @@ void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, | |||
1690 | WARN_ON(ppa_list[0].g.lun != ppa_list[i].g.lun || | 1687 | WARN_ON(ppa_list[0].g.lun != ppa_list[i].g.lun || |
1691 | ppa_list[0].g.ch != ppa_list[i].g.ch); | 1688 | ppa_list[0].g.ch != ppa_list[i].g.ch); |
1692 | #endif | 1689 | #endif |
1693 | /* If the LUN has been locked for this same request, do no attempt to | ||
1694 | * lock it again | ||
1695 | */ | ||
1696 | if (test_and_set_bit(pos, lun_bitmap)) | ||
1697 | return; | ||
1698 | 1690 | ||
1699 | rlun = &pblk->luns[pos]; | 1691 | ret = down_timeout(&rlun->wr_sem, msecs_to_jiffies(30000)); |
1700 | ret = down_timeout(&rlun->wr_sem, msecs_to_jiffies(5000)); | ||
1701 | if (ret) { | 1692 | if (ret) { |
1702 | switch (ret) { | 1693 | switch (ret) { |
1703 | case -ETIME: | 1694 | case -ETIME: |
@@ -1710,6 +1701,50 @@ void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, | |||
1710 | } | 1701 | } |
1711 | } | 1702 | } |
1712 | 1703 | ||
1704 | void pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas) | ||
1705 | { | ||
1706 | struct nvm_tgt_dev *dev = pblk->dev; | ||
1707 | struct nvm_geo *geo = &dev->geo; | ||
1708 | int pos = pblk_ppa_to_pos(geo, ppa_list[0]); | ||
1709 | |||
1710 | __pblk_down_page(pblk, ppa_list, nr_ppas, pos); | ||
1711 | } | ||
1712 | |||
1713 | void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, | ||
1714 | unsigned long *lun_bitmap) | ||
1715 | { | ||
1716 | struct nvm_tgt_dev *dev = pblk->dev; | ||
1717 | struct nvm_geo *geo = &dev->geo; | ||
1718 | int pos = pblk_ppa_to_pos(geo, ppa_list[0]); | ||
1719 | |||
1720 | /* If the LUN has been locked for this same request, do no attempt to | ||
1721 | * lock it again | ||
1722 | */ | ||
1723 | if (test_and_set_bit(pos, lun_bitmap)) | ||
1724 | return; | ||
1725 | |||
1726 | __pblk_down_page(pblk, ppa_list, nr_ppas, pos); | ||
1727 | } | ||
1728 | |||
1729 | void pblk_up_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas) | ||
1730 | { | ||
1731 | struct nvm_tgt_dev *dev = pblk->dev; | ||
1732 | struct nvm_geo *geo = &dev->geo; | ||
1733 | struct pblk_lun *rlun; | ||
1734 | int pos = pblk_ppa_to_pos(geo, ppa_list[0]); | ||
1735 | |||
1736 | #ifdef CONFIG_NVM_DEBUG | ||
1737 | int i; | ||
1738 | |||
1739 | for (i = 1; i < nr_ppas; i++) | ||
1740 | WARN_ON(ppa_list[0].g.lun != ppa_list[i].g.lun || | ||
1741 | ppa_list[0].g.ch != ppa_list[i].g.ch); | ||
1742 | #endif | ||
1743 | |||
1744 | rlun = &pblk->luns[pos]; | ||
1745 | up(&rlun->wr_sem); | ||
1746 | } | ||
1747 | |||
1713 | void pblk_up_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, | 1748 | void pblk_up_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, |
1714 | unsigned long *lun_bitmap) | 1749 | unsigned long *lun_bitmap) |
1715 | { | 1750 | { |
diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c index 0e48d3e4e143..cb556e06673e 100644 --- a/drivers/lightnvm/pblk-recovery.c +++ b/drivers/lightnvm/pblk-recovery.c | |||
@@ -340,9 +340,14 @@ static void pblk_end_io_recov(struct nvm_rq *rqd) | |||
340 | struct pblk *pblk = pad_rq->pblk; | 340 | struct pblk *pblk = pad_rq->pblk; |
341 | struct nvm_tgt_dev *dev = pblk->dev; | 341 | struct nvm_tgt_dev *dev = pblk->dev; |
342 | 342 | ||
343 | kref_put(&pad_rq->ref, pblk_recov_complete); | 343 | pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); |
344 | |||
345 | bio_put(rqd->bio); | ||
344 | nvm_dev_dma_free(dev->parent, rqd->meta_list, rqd->dma_meta_list); | 346 | nvm_dev_dma_free(dev->parent, rqd->meta_list, rqd->dma_meta_list); |
345 | pblk_free_rqd(pblk, rqd, WRITE); | 347 | pblk_free_rqd(pblk, rqd, WRITE); |
348 | |||
349 | atomic_dec(&pblk->inflight_io); | ||
350 | kref_put(&pad_rq->ref, pblk_recov_complete); | ||
346 | } | 351 | } |
347 | 352 | ||
348 | static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line, | 353 | static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line, |
@@ -385,7 +390,7 @@ next_pad_rq: | |||
385 | rq_ppas = pblk_calc_secs(pblk, left_ppas, 0); | 390 | rq_ppas = pblk_calc_secs(pblk, left_ppas, 0); |
386 | if (rq_ppas < pblk->min_write_pgs) { | 391 | if (rq_ppas < pblk->min_write_pgs) { |
387 | pr_err("pblk: corrupted pad line %d\n", line->id); | 392 | pr_err("pblk: corrupted pad line %d\n", line->id); |
388 | goto free_rq; | 393 | goto fail_free_pad; |
389 | } | 394 | } |
390 | 395 | ||
391 | rq_len = rq_ppas * geo->sec_size; | 396 | rq_len = rq_ppas * geo->sec_size; |
@@ -393,7 +398,7 @@ next_pad_rq: | |||
393 | meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, &dma_meta_list); | 398 | meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, &dma_meta_list); |
394 | if (!meta_list) { | 399 | if (!meta_list) { |
395 | ret = -ENOMEM; | 400 | ret = -ENOMEM; |
396 | goto free_data; | 401 | goto fail_free_pad; |
397 | } | 402 | } |
398 | 403 | ||
399 | ppa_list = (void *)(meta_list) + pblk_dma_meta_size; | 404 | ppa_list = (void *)(meta_list) + pblk_dma_meta_size; |
@@ -404,9 +409,9 @@ next_pad_rq: | |||
404 | ret = PTR_ERR(rqd); | 409 | ret = PTR_ERR(rqd); |
405 | goto fail_free_meta; | 410 | goto fail_free_meta; |
406 | } | 411 | } |
407 | memset(rqd, 0, pblk_w_rq_size); | ||
408 | 412 | ||
409 | bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL); | 413 | bio = pblk_bio_map_addr(pblk, data, rq_ppas, rq_len, |
414 | PBLK_VMALLOC_META, GFP_KERNEL); | ||
410 | if (IS_ERR(bio)) { | 415 | if (IS_ERR(bio)) { |
411 | ret = PTR_ERR(bio); | 416 | ret = PTR_ERR(bio); |
412 | goto fail_free_rqd; | 417 | goto fail_free_rqd; |
@@ -453,15 +458,15 @@ next_pad_rq: | |||
453 | } | 458 | } |
454 | 459 | ||
455 | kref_get(&pad_rq->ref); | 460 | kref_get(&pad_rq->ref); |
461 | pblk_down_page(pblk, rqd->ppa_list, rqd->nr_ppas); | ||
456 | 462 | ||
457 | ret = pblk_submit_io(pblk, rqd); | 463 | ret = pblk_submit_io(pblk, rqd); |
458 | if (ret) { | 464 | if (ret) { |
459 | pr_err("pblk: I/O submission failed: %d\n", ret); | 465 | pr_err("pblk: I/O submission failed: %d\n", ret); |
460 | goto free_data; | 466 | pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); |
467 | goto fail_free_bio; | ||
461 | } | 468 | } |
462 | 469 | ||
463 | atomic_dec(&pblk->inflight_io); | ||
464 | |||
465 | left_line_ppas -= rq_ppas; | 470 | left_line_ppas -= rq_ppas; |
466 | left_ppas -= rq_ppas; | 471 | left_ppas -= rq_ppas; |
467 | if (left_ppas && left_line_ppas) | 472 | if (left_ppas && left_line_ppas) |
@@ -475,17 +480,23 @@ next_pad_rq: | |||
475 | ret = -ETIME; | 480 | ret = -ETIME; |
476 | } | 481 | } |
477 | 482 | ||
483 | if (!pblk_line_is_full(line)) | ||
484 | pr_err("pblk: corrupted padded line: %d\n", line->id); | ||
485 | |||
486 | vfree(data); | ||
478 | free_rq: | 487 | free_rq: |
479 | kfree(pad_rq); | 488 | kfree(pad_rq); |
480 | free_data: | ||
481 | vfree(data); | ||
482 | return ret; | 489 | return ret; |
483 | 490 | ||
491 | fail_free_bio: | ||
492 | bio_put(bio); | ||
484 | fail_free_rqd: | 493 | fail_free_rqd: |
485 | pblk_free_rqd(pblk, rqd, WRITE); | 494 | pblk_free_rqd(pblk, rqd, WRITE); |
486 | fail_free_meta: | 495 | fail_free_meta: |
487 | nvm_dev_dma_free(dev->parent, meta_list, dma_meta_list); | 496 | nvm_dev_dma_free(dev->parent, meta_list, dma_meta_list); |
497 | fail_free_pad: | ||
488 | kfree(pad_rq); | 498 | kfree(pad_rq); |
499 | vfree(data); | ||
489 | return ret; | 500 | return ret; |
490 | } | 501 | } |
491 | 502 | ||
diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c index d62a8f4faaf4..cc2b9414d17c 100644 --- a/drivers/lightnvm/pblk-write.c +++ b/drivers/lightnvm/pblk-write.c | |||
@@ -178,15 +178,12 @@ static void pblk_end_io_write_meta(struct nvm_rq *rqd) | |||
178 | { | 178 | { |
179 | struct pblk *pblk = rqd->private; | 179 | struct pblk *pblk = rqd->private; |
180 | struct nvm_tgt_dev *dev = pblk->dev; | 180 | struct nvm_tgt_dev *dev = pblk->dev; |
181 | struct nvm_geo *geo = &dev->geo; | ||
182 | struct pblk_g_ctx *m_ctx = nvm_rq_to_pdu(rqd); | 181 | struct pblk_g_ctx *m_ctx = nvm_rq_to_pdu(rqd); |
183 | struct pblk_line *line = m_ctx->private; | 182 | struct pblk_line *line = m_ctx->private; |
184 | struct pblk_emeta *emeta = line->emeta; | 183 | struct pblk_emeta *emeta = line->emeta; |
185 | int pos = pblk_ppa_to_pos(geo, rqd->ppa_list[0]); | ||
186 | struct pblk_lun *rlun = &pblk->luns[pos]; | ||
187 | int sync; | 184 | int sync; |
188 | 185 | ||
189 | up(&rlun->wr_sem); | 186 | pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); |
190 | 187 | ||
191 | if (rqd->error) { | 188 | if (rqd->error) { |
192 | pblk_log_write_err(pblk, rqd); | 189 | pblk_log_write_err(pblk, rqd); |
@@ -203,6 +200,7 @@ static void pblk_end_io_write_meta(struct nvm_rq *rqd) | |||
203 | pblk->close_wq); | 200 | pblk->close_wq); |
204 | 201 | ||
205 | bio_put(rqd->bio); | 202 | bio_put(rqd->bio); |
203 | nvm_dev_dma_free(dev->parent, rqd->meta_list, rqd->dma_meta_list); | ||
206 | pblk_free_rqd(pblk, rqd, READ); | 204 | pblk_free_rqd(pblk, rqd, READ); |
207 | 205 | ||
208 | atomic_dec(&pblk->inflight_io); | 206 | atomic_dec(&pblk->inflight_io); |
@@ -367,7 +365,6 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) | |||
367 | struct pblk_line_meta *lm = &pblk->lm; | 365 | struct pblk_line_meta *lm = &pblk->lm; |
368 | struct pblk_emeta *emeta = meta_line->emeta; | 366 | struct pblk_emeta *emeta = meta_line->emeta; |
369 | struct pblk_g_ctx *m_ctx; | 367 | struct pblk_g_ctx *m_ctx; |
370 | struct pblk_lun *rlun; | ||
371 | struct bio *bio; | 368 | struct bio *bio; |
372 | struct nvm_rq *rqd; | 369 | struct nvm_rq *rqd; |
373 | void *data; | 370 | void *data; |
@@ -411,13 +408,6 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) | |||
411 | rqd->ppa_list[i] = addr_to_gen_ppa(pblk, paddr, id); | 408 | rqd->ppa_list[i] = addr_to_gen_ppa(pblk, paddr, id); |
412 | } | 409 | } |
413 | 410 | ||
414 | rlun = &pblk->luns[pblk_ppa_to_pos(geo, rqd->ppa_list[0])]; | ||
415 | ret = down_timeout(&rlun->wr_sem, msecs_to_jiffies(5000)); | ||
416 | if (ret) { | ||
417 | pr_err("pblk: lun semaphore timed out (%d)\n", ret); | ||
418 | goto fail_free_bio; | ||
419 | } | ||
420 | |||
421 | emeta->mem += rq_len; | 411 | emeta->mem += rq_len; |
422 | if (emeta->mem >= lm->emeta_len[0]) { | 412 | if (emeta->mem >= lm->emeta_len[0]) { |
423 | spin_lock(&l_mg->close_lock); | 413 | spin_lock(&l_mg->close_lock); |
@@ -427,6 +417,8 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) | |||
427 | spin_unlock(&l_mg->close_lock); | 417 | spin_unlock(&l_mg->close_lock); |
428 | } | 418 | } |
429 | 419 | ||
420 | pblk_down_page(pblk, rqd->ppa_list, rqd->nr_ppas); | ||
421 | |||
430 | ret = pblk_submit_io(pblk, rqd); | 422 | ret = pblk_submit_io(pblk, rqd); |
431 | if (ret) { | 423 | if (ret) { |
432 | pr_err("pblk: emeta I/O submission failed: %d\n", ret); | 424 | pr_err("pblk: emeta I/O submission failed: %d\n", ret); |
@@ -436,10 +428,13 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) | |||
436 | return NVM_IO_OK; | 428 | return NVM_IO_OK; |
437 | 429 | ||
438 | fail_rollback: | 430 | fail_rollback: |
431 | pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); | ||
439 | spin_lock(&l_mg->close_lock); | 432 | spin_lock(&l_mg->close_lock); |
440 | pblk_dealloc_page(pblk, meta_line, rq_ppas); | 433 | pblk_dealloc_page(pblk, meta_line, rq_ppas); |
441 | list_add(&meta_line->list, &meta_line->list); | 434 | list_add(&meta_line->list, &meta_line->list); |
442 | spin_unlock(&l_mg->close_lock); | 435 | spin_unlock(&l_mg->close_lock); |
436 | |||
437 | nvm_dev_dma_free(dev->parent, rqd->meta_list, rqd->dma_meta_list); | ||
443 | fail_free_bio: | 438 | fail_free_bio: |
444 | if (likely(l_mg->emeta_alloc_type == PBLK_VMALLOC_META)) | 439 | if (likely(l_mg->emeta_alloc_type == PBLK_VMALLOC_META)) |
445 | bio_put(bio); | 440 | bio_put(bio); |
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h index 15931381348c..0c5692cc2f60 100644 --- a/drivers/lightnvm/pblk.h +++ b/drivers/lightnvm/pblk.h | |||
@@ -739,8 +739,10 @@ u64 pblk_alloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs); | |||
739 | u64 __pblk_alloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs); | 739 | u64 __pblk_alloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs); |
740 | int pblk_calc_secs(struct pblk *pblk, unsigned long secs_avail, | 740 | int pblk_calc_secs(struct pblk *pblk, unsigned long secs_avail, |
741 | unsigned long secs_to_flush); | 741 | unsigned long secs_to_flush); |
742 | void pblk_up_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas); | ||
742 | void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, | 743 | void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, |
743 | unsigned long *lun_bitmap); | 744 | unsigned long *lun_bitmap); |
745 | void pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas); | ||
744 | void pblk_up_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, | 746 | void pblk_up_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, |
745 | unsigned long *lun_bitmap); | 747 | unsigned long *lun_bitmap); |
746 | void pblk_end_bio_sync(struct bio *bio); | 748 | void pblk_end_bio_sync(struct bio *bio); |