aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm/pblk-init.c
diff options
context:
space:
mode:
authorJavier González <jg@lightnvm.io>2018-03-29 18:04:59 -0400
committerJens Axboe <axboe@kernel.dk>2018-03-29 19:29:09 -0400
commite411b33117d1967d2a5784ed32385e566a871d12 (patch)
tree449847038892b6fe9203e467cf144684f85bd38e /drivers/lightnvm/pblk-init.c
parent3c05ef115c696392d9703be3fe014100ec77864d (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.c209
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
368static void pblk_free_line_bitmaps(struct pblk_line *line) 368static 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
386static 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
390static void pblk_line_meta_free(struct pblk *pblk) 408static 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
408static 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;
437out:
438 kfree(blks);
439 return ret;
440} 427}
441 428
442static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line, 429static 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
463static int pblk_alloc_line_bitmaps(struct pblk *pblk, struct pblk_line *line) 458static 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
480static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns) 479static 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
684static 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
692static int pblk_lines_init(struct pblk *pblk) 704static 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;
870fail_free_lines: 880
881fail_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]);
873fail_free_bb_aux: 885fail_free_bb_aux:
874 kfree(l_mg->bb_aux); 886 kfree(l_mg->bb_aux);
875fail_free_bb_template: 887fail_free_bb_template:
876 kfree(l_mg->bb_template); 888 kfree(l_mg->bb_template);
877fail_free_meta: 889fail_free_meta:
878 pblk_line_meta_free(pblk); 890 pblk_line_mg_free(pblk);
879fail:
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:
1110fail_free_pad_dist: 1119fail_free_pad_dist:
1111 kfree(pblk->pad_dist); 1120 kfree(pblk->pad_dist);
1112fail_free_line_meta: 1121fail_free_line_meta:
1113 pblk_line_meta_free(pblk); 1122 pblk_line_mg_free(pblk);
1114fail_free_luns: 1123fail_free_luns:
1115 pblk_luns_free(pblk); 1124 pblk_luns_free(pblk);
1116fail: 1125fail: