diff options
author | Javier González <jg@lightnvm.io> | 2018-03-29 18:04:59 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-03-29 19:29:09 -0400 |
commit | e411b33117d1967d2a5784ed32385e566a871d12 (patch) | |
tree | 449847038892b6fe9203e467cf144684f85bd38e /drivers/lightnvm/pblk-init.c | |
parent | 3c05ef115c696392d9703be3fe014100ec77864d (diff) |
lightnvm: pblk: refactor bad block identification
In preparation for the OCSSD 2.0 spec. bad block identification,
refactor the current code to generalize bad block get/set functions and
structures.
Signed-off-by: Javier González <javier@cnexlabs.com>
Signed-off-by: Matias Bjørling <mb@lightnvm.io>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/lightnvm/pblk-init.c')
-rw-r--r-- | drivers/lightnvm/pblk-init.c | 209 |
1 files changed, 109 insertions, 100 deletions
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c index 49c65f1dd48b..141036bd6afa 100644 --- a/drivers/lightnvm/pblk-init.c +++ b/drivers/lightnvm/pblk-init.c | |||
@@ -365,7 +365,25 @@ static void pblk_luns_free(struct pblk *pblk) | |||
365 | kfree(pblk->luns); | 365 | kfree(pblk->luns); |
366 | } | 366 | } |
367 | 367 | ||
368 | static void pblk_free_line_bitmaps(struct pblk_line *line) | 368 | static void pblk_line_mg_free(struct pblk *pblk) |
369 | { | ||
370 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; | ||
371 | int i; | ||
372 | |||
373 | kfree(l_mg->bb_template); | ||
374 | kfree(l_mg->bb_aux); | ||
375 | kfree(l_mg->vsc_list); | ||
376 | |||
377 | for (i = 0; i < PBLK_DATA_LINES; i++) { | ||
378 | kfree(l_mg->sline_meta[i]); | ||
379 | pblk_mfree(l_mg->eline_meta[i]->buf, l_mg->emeta_alloc_type); | ||
380 | kfree(l_mg->eline_meta[i]); | ||
381 | } | ||
382 | |||
383 | kfree(pblk->lines); | ||
384 | } | ||
385 | |||
386 | static void pblk_line_meta_free(struct pblk_line *line) | ||
369 | { | 387 | { |
370 | kfree(line->blk_bitmap); | 388 | kfree(line->blk_bitmap); |
371 | kfree(line->erase_bitmap); | 389 | kfree(line->erase_bitmap); |
@@ -382,40 +400,16 @@ static void pblk_lines_free(struct pblk *pblk) | |||
382 | line = &pblk->lines[i]; | 400 | line = &pblk->lines[i]; |
383 | 401 | ||
384 | pblk_line_free(pblk, line); | 402 | pblk_line_free(pblk, line); |
385 | pblk_free_line_bitmaps(line); | 403 | pblk_line_meta_free(line); |
386 | } | 404 | } |
387 | spin_unlock(&l_mg->free_lock); | 405 | spin_unlock(&l_mg->free_lock); |
388 | } | 406 | } |
389 | 407 | ||
390 | static void pblk_line_meta_free(struct pblk *pblk) | 408 | static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun, |
391 | { | 409 | u8 *blks, int nr_blks) |
392 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; | ||
393 | int i; | ||
394 | |||
395 | kfree(l_mg->bb_template); | ||
396 | kfree(l_mg->bb_aux); | ||
397 | kfree(l_mg->vsc_list); | ||
398 | |||
399 | for (i = 0; i < PBLK_DATA_LINES; i++) { | ||
400 | kfree(l_mg->sline_meta[i]); | ||
401 | pblk_mfree(l_mg->eline_meta[i]->buf, l_mg->emeta_alloc_type); | ||
402 | kfree(l_mg->eline_meta[i]); | ||
403 | } | ||
404 | |||
405 | kfree(pblk->lines); | ||
406 | } | ||
407 | |||
408 | static int pblk_bb_discovery(struct nvm_tgt_dev *dev, struct pblk_lun *rlun) | ||
409 | { | 410 | { |
410 | struct nvm_geo *geo = &dev->geo; | ||
411 | struct ppa_addr ppa; | 411 | struct ppa_addr ppa; |
412 | u8 *blks; | 412 | int ret; |
413 | int nr_blks, ret; | ||
414 | |||
415 | nr_blks = geo->nr_chks * geo->plane_mode; | ||
416 | blks = kmalloc(nr_blks, GFP_KERNEL); | ||
417 | if (!blks) | ||
418 | return -ENOMEM; | ||
419 | 413 | ||
420 | ppa.ppa = 0; | 414 | ppa.ppa = 0; |
421 | ppa.g.ch = rlun->bppa.g.ch; | 415 | ppa.g.ch = rlun->bppa.g.ch; |
@@ -423,58 +417,63 @@ static int pblk_bb_discovery(struct nvm_tgt_dev *dev, struct pblk_lun *rlun) | |||
423 | 417 | ||
424 | ret = nvm_get_tgt_bb_tbl(dev, ppa, blks); | 418 | ret = nvm_get_tgt_bb_tbl(dev, ppa, blks); |
425 | if (ret) | 419 | if (ret) |
426 | goto out; | 420 | return ret; |
427 | 421 | ||
428 | nr_blks = nvm_bb_tbl_fold(dev->parent, blks, nr_blks); | 422 | nr_blks = nvm_bb_tbl_fold(dev->parent, blks, nr_blks); |
429 | if (nr_blks < 0) { | 423 | if (nr_blks < 0) |
430 | ret = nr_blks; | 424 | return -EIO; |
431 | goto out; | ||
432 | } | ||
433 | |||
434 | rlun->bb_list = blks; | ||
435 | 425 | ||
436 | return 0; | 426 | return 0; |
437 | out: | ||
438 | kfree(blks); | ||
439 | return ret; | ||
440 | } | 427 | } |
441 | 428 | ||
442 | static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line, | 429 | static void *pblk_bb_get_log(struct pblk *pblk) |
443 | int blk_per_line) | ||
444 | { | 430 | { |
445 | struct nvm_tgt_dev *dev = pblk->dev; | 431 | struct nvm_tgt_dev *dev = pblk->dev; |
446 | struct nvm_geo *geo = &dev->geo; | 432 | struct nvm_geo *geo = &dev->geo; |
447 | struct pblk_lun *rlun; | 433 | u8 *log; |
448 | int bb_cnt = 0; | 434 | int i, nr_blks, blk_per_lun; |
449 | int i; | 435 | int ret; |
450 | 436 | ||
451 | for (i = 0; i < blk_per_line; i++) { | 437 | blk_per_lun = geo->nr_chks * geo->plane_mode; |
452 | rlun = &pblk->luns[i]; | 438 | nr_blks = blk_per_lun * geo->all_luns; |
453 | if (rlun->bb_list[line->id] == NVM_BLK_T_FREE) | ||
454 | continue; | ||
455 | 439 | ||
456 | set_bit(pblk_ppa_to_pos(geo, rlun->bppa), line->blk_bitmap); | 440 | log = kmalloc(nr_blks, GFP_KERNEL); |
457 | bb_cnt++; | 441 | if (!log) |
442 | return ERR_PTR(-ENOMEM); | ||
443 | |||
444 | for (i = 0; i < geo->all_luns; i++) { | ||
445 | struct pblk_lun *rlun = &pblk->luns[i]; | ||
446 | u8 *log_pos = log + i * blk_per_lun; | ||
447 | |||
448 | ret = pblk_bb_get_tbl(dev, rlun, log_pos, blk_per_lun); | ||
449 | if (ret) { | ||
450 | kfree(log); | ||
451 | return ERR_PTR(-EIO); | ||
452 | } | ||
458 | } | 453 | } |
459 | 454 | ||
460 | return bb_cnt; | 455 | return log; |
461 | } | 456 | } |
462 | 457 | ||
463 | static int pblk_alloc_line_bitmaps(struct pblk *pblk, struct pblk_line *line) | 458 | static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line, |
459 | u8 *bb_log, int blk_per_line) | ||
464 | { | 460 | { |
465 | struct pblk_line_meta *lm = &pblk->lm; | 461 | struct nvm_tgt_dev *dev = pblk->dev; |
462 | struct nvm_geo *geo = &dev->geo; | ||
463 | int i, bb_cnt = 0; | ||
466 | 464 | ||
467 | line->blk_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL); | 465 | for (i = 0; i < blk_per_line; i++) { |
468 | if (!line->blk_bitmap) | 466 | struct pblk_lun *rlun = &pblk->luns[i]; |
469 | return -ENOMEM; | 467 | u8 *lun_bb_log = bb_log + i * blk_per_line; |
470 | 468 | ||
471 | line->erase_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL); | 469 | if (lun_bb_log[line->id] == NVM_BLK_T_FREE) |
472 | if (!line->erase_bitmap) { | 470 | continue; |
473 | kfree(line->blk_bitmap); | 471 | |
474 | return -ENOMEM; | 472 | set_bit(pblk_ppa_to_pos(geo, rlun->bppa), line->blk_bitmap); |
473 | bb_cnt++; | ||
475 | } | 474 | } |
476 | 475 | ||
477 | return 0; | 476 | return bb_cnt; |
478 | } | 477 | } |
479 | 478 | ||
480 | static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns) | 479 | static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns) |
@@ -482,7 +481,7 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns) | |||
482 | struct nvm_tgt_dev *dev = pblk->dev; | 481 | struct nvm_tgt_dev *dev = pblk->dev; |
483 | struct nvm_geo *geo = &dev->geo; | 482 | struct nvm_geo *geo = &dev->geo; |
484 | struct pblk_lun *rlun; | 483 | struct pblk_lun *rlun; |
485 | int i, ret; | 484 | int i; |
486 | 485 | ||
487 | /* TODO: Implement unbalanced LUN support */ | 486 | /* TODO: Implement unbalanced LUN support */ |
488 | if (geo->nr_luns < 0) { | 487 | if (geo->nr_luns < 0) { |
@@ -505,13 +504,6 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns) | |||
505 | rlun->bppa = luns[lunid]; | 504 | rlun->bppa = luns[lunid]; |
506 | 505 | ||
507 | sema_init(&rlun->wr_sem, 1); | 506 | sema_init(&rlun->wr_sem, 1); |
508 | |||
509 | ret = pblk_bb_discovery(dev, rlun); | ||
510 | if (ret) { | ||
511 | while (--i >= 0) | ||
512 | kfree(pblk->luns[i].bb_list); | ||
513 | return ret; | ||
514 | } | ||
515 | } | 507 | } |
516 | 508 | ||
517 | return 0; | 509 | return 0; |
@@ -689,6 +681,26 @@ fail_free_smeta: | |||
689 | return -ENOMEM; | 681 | return -ENOMEM; |
690 | } | 682 | } |
691 | 683 | ||
684 | static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line, | ||
685 | void *chunk_log, long *nr_bad_blks) | ||
686 | { | ||
687 | struct pblk_line_meta *lm = &pblk->lm; | ||
688 | |||
689 | line->blk_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL); | ||
690 | if (!line->blk_bitmap) | ||
691 | return -ENOMEM; | ||
692 | |||
693 | line->erase_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL); | ||
694 | if (!line->erase_bitmap) { | ||
695 | kfree(line->blk_bitmap); | ||
696 | return -ENOMEM; | ||
697 | } | ||
698 | |||
699 | *nr_bad_blks = pblk_bb_line(pblk, line, chunk_log, lm->blk_per_line); | ||
700 | |||
701 | return 0; | ||
702 | } | ||
703 | |||
692 | static int pblk_lines_init(struct pblk *pblk) | 704 | static int pblk_lines_init(struct pblk *pblk) |
693 | { | 705 | { |
694 | struct nvm_tgt_dev *dev = pblk->dev; | 706 | struct nvm_tgt_dev *dev = pblk->dev; |
@@ -696,8 +708,9 @@ static int pblk_lines_init(struct pblk *pblk) | |||
696 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; | 708 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; |
697 | struct pblk_line_meta *lm = &pblk->lm; | 709 | struct pblk_line_meta *lm = &pblk->lm; |
698 | struct pblk_line *line; | 710 | struct pblk_line *line; |
711 | void *chunk_log; | ||
699 | unsigned int smeta_len, emeta_len; | 712 | unsigned int smeta_len, emeta_len; |
700 | long nr_bad_blks, nr_free_blks; | 713 | long nr_bad_blks = 0, nr_free_blks = 0; |
701 | int bb_distance, max_write_ppas, mod; | 714 | int bb_distance, max_write_ppas, mod; |
702 | int i, ret; | 715 | int i, ret; |
703 | 716 | ||
@@ -771,13 +784,12 @@ add_emeta_page: | |||
771 | if (lm->min_blk_line > lm->blk_per_line) { | 784 | if (lm->min_blk_line > lm->blk_per_line) { |
772 | pr_err("pblk: config. not supported. Min. LUN in line:%d\n", | 785 | pr_err("pblk: config. not supported. Min. LUN in line:%d\n", |
773 | lm->blk_per_line); | 786 | lm->blk_per_line); |
774 | ret = -EINVAL; | 787 | return -EINVAL; |
775 | goto fail; | ||
776 | } | 788 | } |
777 | 789 | ||
778 | ret = pblk_lines_alloc_metadata(pblk); | 790 | ret = pblk_lines_alloc_metadata(pblk); |
779 | if (ret) | 791 | if (ret) |
780 | goto fail; | 792 | return ret; |
781 | 793 | ||
782 | l_mg->bb_template = kzalloc(lm->sec_bitmap_len, GFP_KERNEL); | 794 | l_mg->bb_template = kzalloc(lm->sec_bitmap_len, GFP_KERNEL); |
783 | if (!l_mg->bb_template) { | 795 | if (!l_mg->bb_template) { |
@@ -821,9 +833,16 @@ add_emeta_page: | |||
821 | goto fail_free_bb_aux; | 833 | goto fail_free_bb_aux; |
822 | } | 834 | } |
823 | 835 | ||
824 | nr_free_blks = 0; | 836 | chunk_log = pblk_bb_get_log(pblk); |
837 | if (IS_ERR(chunk_log)) { | ||
838 | pr_err("pblk: could not get bad block log (%lu)\n", | ||
839 | PTR_ERR(chunk_log)); | ||
840 | ret = PTR_ERR(chunk_log); | ||
841 | goto fail_free_bb_aux; | ||
842 | } | ||
843 | |||
825 | for (i = 0; i < l_mg->nr_lines; i++) { | 844 | for (i = 0; i < l_mg->nr_lines; i++) { |
826 | int blk_in_line; | 845 | int chk_in_line; |
827 | 846 | ||
828 | line = &pblk->lines[i]; | 847 | line = &pblk->lines[i]; |
829 | 848 | ||
@@ -835,26 +854,20 @@ add_emeta_page: | |||
835 | line->vsc = &l_mg->vsc_list[i]; | 854 | line->vsc = &l_mg->vsc_list[i]; |
836 | spin_lock_init(&line->lock); | 855 | spin_lock_init(&line->lock); |
837 | 856 | ||
838 | ret = pblk_alloc_line_bitmaps(pblk, line); | 857 | ret = pblk_setup_line_meta(pblk, line, chunk_log, &nr_bad_blks); |
839 | if (ret) | 858 | if (ret) |
840 | goto fail_free_lines; | 859 | goto fail_free_chunk_log; |
841 | 860 | ||
842 | nr_bad_blks = pblk_bb_line(pblk, line, lm->blk_per_line); | 861 | chk_in_line = lm->blk_per_line - nr_bad_blks; |
843 | if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line) { | 862 | if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line || |
844 | pblk_free_line_bitmaps(line); | 863 | chk_in_line < lm->min_blk_line) { |
845 | ret = -EINVAL; | ||
846 | goto fail_free_lines; | ||
847 | } | ||
848 | |||
849 | blk_in_line = lm->blk_per_line - nr_bad_blks; | ||
850 | if (blk_in_line < lm->min_blk_line) { | ||
851 | line->state = PBLK_LINESTATE_BAD; | 864 | line->state = PBLK_LINESTATE_BAD; |
852 | list_add_tail(&line->list, &l_mg->bad_list); | 865 | list_add_tail(&line->list, &l_mg->bad_list); |
853 | continue; | 866 | continue; |
854 | } | 867 | } |
855 | 868 | ||
856 | nr_free_blks += blk_in_line; | 869 | nr_free_blks += chk_in_line; |
857 | atomic_set(&line->blk_in_line, blk_in_line); | 870 | atomic_set(&line->blk_in_line, chk_in_line); |
858 | 871 | ||
859 | l_mg->nr_free_lines++; | 872 | l_mg->nr_free_lines++; |
860 | list_add_tail(&line->list, &l_mg->free_list); | 873 | list_add_tail(&line->list, &l_mg->free_list); |
@@ -862,23 +875,19 @@ add_emeta_page: | |||
862 | 875 | ||
863 | pblk_set_provision(pblk, nr_free_blks); | 876 | pblk_set_provision(pblk, nr_free_blks); |
864 | 877 | ||
865 | /* Cleanup per-LUN bad block lists - managed within lines on run-time */ | 878 | kfree(chunk_log); |
866 | for (i = 0; i < geo->all_luns; i++) | ||
867 | kfree(pblk->luns[i].bb_list); | ||
868 | |||
869 | return 0; | 879 | return 0; |
870 | fail_free_lines: | 880 | |
881 | fail_free_chunk_log: | ||
882 | kfree(chunk_log); | ||
871 | while (--i >= 0) | 883 | while (--i >= 0) |
872 | pblk_free_line_bitmaps(&pblk->lines[i]); | 884 | pblk_line_meta_free(&pblk->lines[i]); |
873 | fail_free_bb_aux: | 885 | fail_free_bb_aux: |
874 | kfree(l_mg->bb_aux); | 886 | kfree(l_mg->bb_aux); |
875 | fail_free_bb_template: | 887 | fail_free_bb_template: |
876 | kfree(l_mg->bb_template); | 888 | kfree(l_mg->bb_template); |
877 | fail_free_meta: | 889 | fail_free_meta: |
878 | pblk_line_meta_free(pblk); | 890 | pblk_line_mg_free(pblk); |
879 | fail: | ||
880 | for (i = 0; i < geo->all_luns; i++) | ||
881 | kfree(pblk->luns[i].bb_list); | ||
882 | 891 | ||
883 | return ret; | 892 | return ret; |
884 | } | 893 | } |
@@ -922,7 +931,7 @@ static void pblk_free(struct pblk *pblk) | |||
922 | pblk_luns_free(pblk); | 931 | pblk_luns_free(pblk); |
923 | pblk_lines_free(pblk); | 932 | pblk_lines_free(pblk); |
924 | kfree(pblk->pad_dist); | 933 | kfree(pblk->pad_dist); |
925 | pblk_line_meta_free(pblk); | 934 | pblk_line_mg_free(pblk); |
926 | pblk_core_free(pblk); | 935 | pblk_core_free(pblk); |
927 | pblk_l2p_free(pblk); | 936 | pblk_l2p_free(pblk); |
928 | 937 | ||
@@ -1110,7 +1119,7 @@ fail_free_core: | |||
1110 | fail_free_pad_dist: | 1119 | fail_free_pad_dist: |
1111 | kfree(pblk->pad_dist); | 1120 | kfree(pblk->pad_dist); |
1112 | fail_free_line_meta: | 1121 | fail_free_line_meta: |
1113 | pblk_line_meta_free(pblk); | 1122 | pblk_line_mg_free(pblk); |
1114 | fail_free_luns: | 1123 | fail_free_luns: |
1115 | pblk_luns_free(pblk); | 1124 | pblk_luns_free(pblk); |
1116 | fail: | 1125 | fail: |