aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm/pblk-init.c
diff options
context:
space:
mode:
authorJavier González <javier@cnexlabs.com>2018-03-29 18:05:20 -0400
committerJens Axboe <axboe@kernel.dk>2018-03-29 19:29:09 -0400
commit32ef9412c1142c64b372b83d3740f234f4226317 (patch)
tree5622acbfa881736acb380c2cc819013ea7baf136 /drivers/lightnvm/pblk-init.c
parentbb845ae45c3d669ee814ce9f0ed51f2915ee55a0 (diff)
lightnvm: pblk: implement get log report chunk
In preparation of pblk supporting 2.0, implement the get log report chunk in pblk. Also, define the chunk states as given in the 2.0 spec. 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.c222
1 files changed, 158 insertions, 64 deletions
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 5b381700ef30..27b4974930b4 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -451,6 +451,7 @@ static void pblk_line_meta_free(struct pblk_line *line)
451{ 451{
452 kfree(line->blk_bitmap); 452 kfree(line->blk_bitmap);
453 kfree(line->erase_bitmap); 453 kfree(line->erase_bitmap);
454 kfree(line->chks);
454} 455}
455 456
456static void pblk_lines_free(struct pblk *pblk) 457static void pblk_lines_free(struct pblk *pblk)
@@ -495,55 +496,44 @@ static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun,
495 return 0; 496 return 0;
496} 497}
497 498
498static void *pblk_bb_get_log(struct pblk *pblk) 499static void *pblk_bb_get_meta(struct pblk *pblk)
499{ 500{
500 struct nvm_tgt_dev *dev = pblk->dev; 501 struct nvm_tgt_dev *dev = pblk->dev;
501 struct nvm_geo *geo = &dev->geo; 502 struct nvm_geo *geo = &dev->geo;
502 u8 *log; 503 u8 *meta;
503 int i, nr_blks, blk_per_lun; 504 int i, nr_blks, blk_per_lun;
504 int ret; 505 int ret;
505 506
506 blk_per_lun = geo->num_chk * geo->pln_mode; 507 blk_per_lun = geo->num_chk * geo->pln_mode;
507 nr_blks = blk_per_lun * geo->all_luns; 508 nr_blks = blk_per_lun * geo->all_luns;
508 509
509 log = kmalloc(nr_blks, GFP_KERNEL); 510 meta = kmalloc(nr_blks, GFP_KERNEL);
510 if (!log) 511 if (!meta)
511 return ERR_PTR(-ENOMEM); 512 return ERR_PTR(-ENOMEM);
512 513
513 for (i = 0; i < geo->all_luns; i++) { 514 for (i = 0; i < geo->all_luns; i++) {
514 struct pblk_lun *rlun = &pblk->luns[i]; 515 struct pblk_lun *rlun = &pblk->luns[i];
515 u8 *log_pos = log + i * blk_per_lun; 516 u8 *meta_pos = meta + i * blk_per_lun;
516 517
517 ret = pblk_bb_get_tbl(dev, rlun, log_pos, blk_per_lun); 518 ret = pblk_bb_get_tbl(dev, rlun, meta_pos, blk_per_lun);
518 if (ret) { 519 if (ret) {
519 kfree(log); 520 kfree(meta);
520 return ERR_PTR(-EIO); 521 return ERR_PTR(-EIO);
521 } 522 }
522 } 523 }
523 524
524 return log; 525 return meta;
525} 526}
526 527
527static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line, 528static void *pblk_chunk_get_meta(struct pblk *pblk)
528 u8 *bb_log, int blk_per_line)
529{ 529{
530 struct nvm_tgt_dev *dev = pblk->dev; 530 struct nvm_tgt_dev *dev = pblk->dev;
531 struct nvm_geo *geo = &dev->geo; 531 struct nvm_geo *geo = &dev->geo;
532 int i, bb_cnt = 0;
533 int blk_per_lun = geo->num_chk * geo->pln_mode;
534 532
535 for (i = 0; i < blk_per_line; i++) { 533 if (geo->version == NVM_OCSSD_SPEC_12)
536 struct pblk_lun *rlun = &pblk->luns[i]; 534 return pblk_bb_get_meta(pblk);
537 u8 *lun_bb_log = bb_log + i * blk_per_lun; 535 else
538 536 return pblk_chunk_get_info(pblk);
539 if (lun_bb_log[line->id] == NVM_BLK_T_FREE)
540 continue;
541
542 set_bit(pblk_ppa_to_pos(geo, rlun->bppa), line->blk_bitmap);
543 bb_cnt++;
544 }
545
546 return bb_cnt;
547} 537}
548 538
549static int pblk_luns_init(struct pblk *pblk) 539static int pblk_luns_init(struct pblk *pblk)
@@ -644,8 +634,131 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks)
644 atomic_set(&pblk->rl.free_user_blocks, nr_free_blks); 634 atomic_set(&pblk->rl.free_user_blocks, nr_free_blks);
645} 635}
646 636
647static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line, 637static int pblk_setup_line_meta_12(struct pblk *pblk, struct pblk_line *line,
648 void *chunk_log, long *nr_bad_blks) 638 void *chunk_meta)
639{
640 struct nvm_tgt_dev *dev = pblk->dev;
641 struct nvm_geo *geo = &dev->geo;
642 struct pblk_line_meta *lm = &pblk->lm;
643 int i, chk_per_lun, nr_bad_chks = 0;
644
645 chk_per_lun = geo->num_chk * geo->pln_mode;
646
647 for (i = 0; i < lm->blk_per_line; i++) {
648 struct pblk_lun *rlun = &pblk->luns[i];
649 struct nvm_chk_meta *chunk;
650 int pos = pblk_ppa_to_pos(geo, rlun->bppa);
651 u8 *lun_bb_meta = chunk_meta + pos * chk_per_lun;
652
653 chunk = &line->chks[pos];
654
655 /*
656 * In 1.2 spec. chunk state is not persisted by the device. Thus
657 * some of the values are reset each time pblk is instantiated.
658 */
659 if (lun_bb_meta[line->id] == NVM_BLK_T_FREE)
660 chunk->state = NVM_CHK_ST_FREE;
661 else
662 chunk->state = NVM_CHK_ST_OFFLINE;
663
664 chunk->type = NVM_CHK_TP_W_SEQ;
665 chunk->wi = 0;
666 chunk->slba = -1;
667 chunk->cnlb = geo->clba;
668 chunk->wp = 0;
669
670 if (!(chunk->state & NVM_CHK_ST_OFFLINE))
671 continue;
672
673 set_bit(pos, line->blk_bitmap);
674 nr_bad_chks++;
675 }
676
677 return nr_bad_chks;
678}
679
680static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line,
681 struct nvm_chk_meta *meta)
682{
683 struct nvm_tgt_dev *dev = pblk->dev;
684 struct nvm_geo *geo = &dev->geo;
685 struct pblk_line_meta *lm = &pblk->lm;
686 int i, nr_bad_chks = 0;
687
688 for (i = 0; i < lm->blk_per_line; i++) {
689 struct pblk_lun *rlun = &pblk->luns[i];
690 struct nvm_chk_meta *chunk;
691 struct nvm_chk_meta *chunk_meta;
692 struct ppa_addr ppa;
693 int pos;
694
695 ppa = rlun->bppa;
696 pos = pblk_ppa_to_pos(geo, ppa);
697 chunk = &line->chks[pos];
698
699 ppa.m.chk = line->id;
700 chunk_meta = pblk_chunk_get_off(pblk, meta, ppa);
701
702 chunk->state = chunk_meta->state;
703 chunk->type = chunk_meta->type;
704 chunk->wi = chunk_meta->wi;
705 chunk->slba = chunk_meta->slba;
706 chunk->cnlb = chunk_meta->cnlb;
707 chunk->wp = chunk_meta->wp;
708
709 if (!(chunk->state & NVM_CHK_ST_OFFLINE))
710 continue;
711
712 if (chunk->type & NVM_CHK_TP_SZ_SPEC) {
713 WARN_ONCE(1, "pblk: custom-sized chunks unsupported\n");
714 continue;
715 }
716
717 set_bit(pos, line->blk_bitmap);
718 nr_bad_chks++;
719 }
720
721 return nr_bad_chks;
722}
723
724static long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
725 void *chunk_meta, int line_id)
726{
727 struct nvm_tgt_dev *dev = pblk->dev;
728 struct nvm_geo *geo = &dev->geo;
729 struct pblk_line_mgmt *l_mg = &pblk->l_mg;
730 struct pblk_line_meta *lm = &pblk->lm;
731 long nr_bad_chks, chk_in_line;
732
733 line->pblk = pblk;
734 line->id = line_id;
735 line->type = PBLK_LINETYPE_FREE;
736 line->state = PBLK_LINESTATE_NEW;
737 line->gc_group = PBLK_LINEGC_NONE;
738 line->vsc = &l_mg->vsc_list[line_id];
739 spin_lock_init(&line->lock);
740
741 if (geo->version == NVM_OCSSD_SPEC_12)
742 nr_bad_chks = pblk_setup_line_meta_12(pblk, line, chunk_meta);
743 else
744 nr_bad_chks = pblk_setup_line_meta_20(pblk, line, chunk_meta);
745
746 chk_in_line = lm->blk_per_line - nr_bad_chks;
747 if (nr_bad_chks < 0 || nr_bad_chks > lm->blk_per_line ||
748 chk_in_line < lm->min_blk_line) {
749 line->state = PBLK_LINESTATE_BAD;
750 list_add_tail(&line->list, &l_mg->bad_list);
751 return 0;
752 }
753
754 atomic_set(&line->blk_in_line, chk_in_line);
755 list_add_tail(&line->list, &l_mg->free_list);
756 l_mg->nr_free_lines++;
757
758 return chk_in_line;
759}
760
761static int pblk_alloc_line_meta(struct pblk *pblk, struct pblk_line *line)
649{ 762{
650 struct pblk_line_meta *lm = &pblk->lm; 763 struct pblk_line_meta *lm = &pblk->lm;
651 764
@@ -659,7 +772,13 @@ static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
659 return -ENOMEM; 772 return -ENOMEM;
660 } 773 }
661 774
662 *nr_bad_blks = pblk_bb_line(pblk, line, chunk_log, lm->blk_per_line); 775 line->chks = kmalloc(lm->blk_per_line * sizeof(struct nvm_chk_meta),
776 GFP_KERNEL);
777 if (!line->chks) {
778 kfree(line->erase_bitmap);
779 kfree(line->blk_bitmap);
780 return -ENOMEM;
781 }
663 782
664 return 0; 783 return 0;
665} 784}
@@ -846,10 +965,9 @@ add_emeta_page:
846static int pblk_lines_init(struct pblk *pblk) 965static int pblk_lines_init(struct pblk *pblk)
847{ 966{
848 struct pblk_line_mgmt *l_mg = &pblk->l_mg; 967 struct pblk_line_mgmt *l_mg = &pblk->l_mg;
849 struct pblk_line_meta *lm = &pblk->lm;
850 struct pblk_line *line; 968 struct pblk_line *line;
851 void *chunk_log; 969 void *chunk_meta;
852 long nr_bad_blks = 0, nr_free_blks = 0; 970 long nr_free_chks = 0;
853 int i, ret; 971 int i, ret;
854 972
855 ret = pblk_line_meta_init(pblk); 973 ret = pblk_line_meta_init(pblk);
@@ -864,11 +982,9 @@ static int pblk_lines_init(struct pblk *pblk)
864 if (ret) 982 if (ret)
865 goto fail_free_meta; 983 goto fail_free_meta;
866 984
867 chunk_log = pblk_bb_get_log(pblk); 985 chunk_meta = pblk_chunk_get_meta(pblk);
868 if (IS_ERR(chunk_log)) { 986 if (IS_ERR(chunk_meta)) {
869 pr_err("pblk: could not get bad block log (%lu)\n", 987 ret = PTR_ERR(chunk_meta);
870 PTR_ERR(chunk_log));
871 ret = PTR_ERR(chunk_log);
872 goto fail_free_luns; 988 goto fail_free_luns;
873 } 989 }
874 990
@@ -876,52 +992,30 @@ static int pblk_lines_init(struct pblk *pblk)
876 GFP_KERNEL); 992 GFP_KERNEL);
877 if (!pblk->lines) { 993 if (!pblk->lines) {
878 ret = -ENOMEM; 994 ret = -ENOMEM;
879 goto fail_free_chunk_log; 995 goto fail_free_chunk_meta;
880 } 996 }
881 997
882 for (i = 0; i < l_mg->nr_lines; i++) { 998 for (i = 0; i < l_mg->nr_lines; i++) {
883 int chk_in_line;
884
885 line = &pblk->lines[i]; 999 line = &pblk->lines[i];
886 1000
887 line->pblk = pblk; 1001 ret = pblk_alloc_line_meta(pblk, line);
888 line->id = i;
889 line->type = PBLK_LINETYPE_FREE;
890 line->state = PBLK_LINESTATE_FREE;
891 line->gc_group = PBLK_LINEGC_NONE;
892 line->vsc = &l_mg->vsc_list[i];
893 spin_lock_init(&line->lock);
894
895 ret = pblk_setup_line_meta(pblk, line, chunk_log, &nr_bad_blks);
896 if (ret) 1002 if (ret)
897 goto fail_free_lines; 1003 goto fail_free_lines;
898 1004
899 chk_in_line = lm->blk_per_line - nr_bad_blks; 1005 nr_free_chks += pblk_setup_line_meta(pblk, line, chunk_meta, i);
900 if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line ||
901 chk_in_line < lm->min_blk_line) {
902 line->state = PBLK_LINESTATE_BAD;
903 list_add_tail(&line->list, &l_mg->bad_list);
904 continue;
905 }
906
907 nr_free_blks += chk_in_line;
908 atomic_set(&line->blk_in_line, chk_in_line);
909
910 l_mg->nr_free_lines++;
911 list_add_tail(&line->list, &l_mg->free_list);
912 } 1006 }
913 1007
914 pblk_set_provision(pblk, nr_free_blks); 1008 pblk_set_provision(pblk, nr_free_chks);
915 1009
916 kfree(chunk_log); 1010 kfree(chunk_meta);
917 return 0; 1011 return 0;
918 1012
919fail_free_lines: 1013fail_free_lines:
920 while (--i >= 0) 1014 while (--i >= 0)
921 pblk_line_meta_free(&pblk->lines[i]); 1015 pblk_line_meta_free(&pblk->lines[i]);
922 kfree(pblk->lines); 1016 kfree(pblk->lines);
923fail_free_chunk_log: 1017fail_free_chunk_meta:
924 kfree(chunk_log); 1018 kfree(chunk_meta);
925fail_free_luns: 1019fail_free_luns:
926 kfree(pblk->luns); 1020 kfree(pblk->luns);
927fail_free_meta: 1021fail_free_meta: