diff options
author | Javier González <javier@cnexlabs.com> | 2018-03-29 18:05:09 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-03-29 19:29:09 -0400 |
commit | 43d47127219de1dd674b917c1835baa14c4c1768 (patch) | |
tree | 5521c1fdc92b57192aaecd570bf26f44a7395268 | |
parent | 9d7aa4a484872cb2b4dc81bd6f058cb8351ca9ed (diff) |
lightnvm: pblk: refactor init/exit sequences
Refactor init and exit sequences to eliminate dependencies among init
modules and improve readability.
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>
-rw-r--r-- | drivers/lightnvm/pblk-init.c | 405 |
1 files changed, 202 insertions, 203 deletions
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c index ee936c1ff764..8f1d622801df 100644 --- a/drivers/lightnvm/pblk-init.c +++ b/drivers/lightnvm/pblk-init.c | |||
@@ -103,7 +103,40 @@ static void pblk_l2p_free(struct pblk *pblk) | |||
103 | vfree(pblk->trans_map); | 103 | vfree(pblk->trans_map); |
104 | } | 104 | } |
105 | 105 | ||
106 | static int pblk_l2p_init(struct pblk *pblk) | 106 | static int pblk_l2p_recover(struct pblk *pblk, bool factory_init) |
107 | { | ||
108 | struct pblk_line *line = NULL; | ||
109 | |||
110 | if (factory_init) { | ||
111 | pblk_setup_uuid(pblk); | ||
112 | } else { | ||
113 | line = pblk_recov_l2p(pblk); | ||
114 | if (IS_ERR(line)) { | ||
115 | pr_err("pblk: could not recover l2p table\n"); | ||
116 | return -EFAULT; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | #ifdef CONFIG_NVM_DEBUG | ||
121 | pr_info("pblk init: L2P CRC: %x\n", pblk_l2p_crc(pblk)); | ||
122 | #endif | ||
123 | |||
124 | /* Free full lines directly as GC has not been started yet */ | ||
125 | pblk_gc_free_full_lines(pblk); | ||
126 | |||
127 | if (!line) { | ||
128 | /* Configure next line for user data */ | ||
129 | line = pblk_line_get_first_data(pblk); | ||
130 | if (!line) { | ||
131 | pr_err("pblk: line list corrupted\n"); | ||
132 | return -EFAULT; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static int pblk_l2p_init(struct pblk *pblk, bool factory_init) | ||
107 | { | 140 | { |
108 | sector_t i; | 141 | sector_t i; |
109 | struct ppa_addr ppa; | 142 | struct ppa_addr ppa; |
@@ -119,7 +152,7 @@ static int pblk_l2p_init(struct pblk *pblk) | |||
119 | for (i = 0; i < pblk->rl.nr_secs; i++) | 152 | for (i = 0; i < pblk->rl.nr_secs; i++) |
120 | pblk_trans_map_set(pblk, i, ppa); | 153 | pblk_trans_map_set(pblk, i, ppa); |
121 | 154 | ||
122 | return 0; | 155 | return pblk_l2p_recover(pblk, factory_init); |
123 | } | 156 | } |
124 | 157 | ||
125 | static void pblk_rwb_free(struct pblk *pblk) | 158 | static void pblk_rwb_free(struct pblk *pblk) |
@@ -159,7 +192,13 @@ static int pblk_set_ppaf(struct pblk *pblk) | |||
159 | struct nvm_tgt_dev *dev = pblk->dev; | 192 | struct nvm_tgt_dev *dev = pblk->dev; |
160 | struct nvm_geo *geo = &dev->geo; | 193 | struct nvm_geo *geo = &dev->geo; |
161 | struct nvm_addr_format ppaf = geo->ppaf; | 194 | struct nvm_addr_format ppaf = geo->ppaf; |
162 | int power_len; | 195 | int mod, power_len; |
196 | |||
197 | div_u64_rem(geo->sec_per_chk, pblk->min_write_pgs, &mod); | ||
198 | if (mod) { | ||
199 | pr_err("pblk: bad configuration of sectors/pages\n"); | ||
200 | return -EINVAL; | ||
201 | } | ||
163 | 202 | ||
164 | /* Re-calculate channel and lun format to adapt to configuration */ | 203 | /* Re-calculate channel and lun format to adapt to configuration */ |
165 | power_len = get_count_order(geo->nr_chnls); | 204 | power_len = get_count_order(geo->nr_chnls); |
@@ -252,13 +291,40 @@ static int pblk_core_init(struct pblk *pblk) | |||
252 | { | 291 | { |
253 | struct nvm_tgt_dev *dev = pblk->dev; | 292 | struct nvm_tgt_dev *dev = pblk->dev; |
254 | struct nvm_geo *geo = &dev->geo; | 293 | struct nvm_geo *geo = &dev->geo; |
294 | int max_write_ppas; | ||
295 | |||
296 | atomic64_set(&pblk->user_wa, 0); | ||
297 | atomic64_set(&pblk->pad_wa, 0); | ||
298 | atomic64_set(&pblk->gc_wa, 0); | ||
299 | pblk->user_rst_wa = 0; | ||
300 | pblk->pad_rst_wa = 0; | ||
301 | pblk->gc_rst_wa = 0; | ||
302 | |||
303 | atomic64_set(&pblk->nr_flush, 0); | ||
304 | pblk->nr_flush_rst = 0; | ||
255 | 305 | ||
256 | pblk->pgs_in_buffer = NVM_MEM_PAGE_WRITE * geo->sec_per_pg * | 306 | pblk->pgs_in_buffer = NVM_MEM_PAGE_WRITE * geo->sec_per_pg * |
257 | geo->nr_planes * geo->all_luns; | 307 | geo->nr_planes * geo->all_luns; |
258 | 308 | ||
259 | if (pblk_init_global_caches(pblk)) | 309 | pblk->min_write_pgs = geo->sec_per_pl * (geo->sec_size / PAGE_SIZE); |
310 | max_write_ppas = pblk->min_write_pgs * geo->all_luns; | ||
311 | pblk->max_write_pgs = min_t(int, max_write_ppas, NVM_MAX_VLBA); | ||
312 | pblk_set_sec_per_write(pblk, pblk->min_write_pgs); | ||
313 | |||
314 | if (pblk->max_write_pgs > PBLK_MAX_REQ_ADDRS) { | ||
315 | pr_err("pblk: vector list too big(%u > %u)\n", | ||
316 | pblk->max_write_pgs, PBLK_MAX_REQ_ADDRS); | ||
317 | return -EINVAL; | ||
318 | } | ||
319 | |||
320 | pblk->pad_dist = kzalloc((pblk->min_write_pgs - 1) * sizeof(atomic64_t), | ||
321 | GFP_KERNEL); | ||
322 | if (!pblk->pad_dist) | ||
260 | return -ENOMEM; | 323 | return -ENOMEM; |
261 | 324 | ||
325 | if (pblk_init_global_caches(pblk)) | ||
326 | goto fail_free_pad_dist; | ||
327 | |||
262 | /* Internal bios can be at most the sectors signaled by the device. */ | 328 | /* Internal bios can be at most the sectors signaled by the device. */ |
263 | pblk->page_bio_pool = mempool_create_page_pool(NVM_MAX_VLBA, 0); | 329 | pblk->page_bio_pool = mempool_create_page_pool(NVM_MAX_VLBA, 0); |
264 | if (!pblk->page_bio_pool) | 330 | if (!pblk->page_bio_pool) |
@@ -307,10 +373,8 @@ static int pblk_core_init(struct pblk *pblk) | |||
307 | if (pblk_set_ppaf(pblk)) | 373 | if (pblk_set_ppaf(pblk)) |
308 | goto free_r_end_wq; | 374 | goto free_r_end_wq; |
309 | 375 | ||
310 | if (pblk_rwb_init(pblk)) | ||
311 | goto free_r_end_wq; | ||
312 | |||
313 | INIT_LIST_HEAD(&pblk->compl_list); | 376 | INIT_LIST_HEAD(&pblk->compl_list); |
377 | |||
314 | return 0; | 378 | return 0; |
315 | 379 | ||
316 | free_r_end_wq: | 380 | free_r_end_wq: |
@@ -333,6 +397,8 @@ free_page_bio_pool: | |||
333 | mempool_destroy(pblk->page_bio_pool); | 397 | mempool_destroy(pblk->page_bio_pool); |
334 | free_global_caches: | 398 | free_global_caches: |
335 | pblk_free_global_caches(pblk); | 399 | pblk_free_global_caches(pblk); |
400 | fail_free_pad_dist: | ||
401 | kfree(pblk->pad_dist); | ||
336 | return -ENOMEM; | 402 | return -ENOMEM; |
337 | } | 403 | } |
338 | 404 | ||
@@ -354,14 +420,8 @@ static void pblk_core_free(struct pblk *pblk) | |||
354 | mempool_destroy(pblk->e_rq_pool); | 420 | mempool_destroy(pblk->e_rq_pool); |
355 | mempool_destroy(pblk->w_rq_pool); | 421 | mempool_destroy(pblk->w_rq_pool); |
356 | 422 | ||
357 | pblk_rwb_free(pblk); | ||
358 | |||
359 | pblk_free_global_caches(pblk); | 423 | pblk_free_global_caches(pblk); |
360 | } | 424 | kfree(pblk->pad_dist); |
361 | |||
362 | static void pblk_luns_free(struct pblk *pblk) | ||
363 | { | ||
364 | kfree(pblk->luns); | ||
365 | } | 425 | } |
366 | 426 | ||
367 | static void pblk_line_mg_free(struct pblk *pblk) | 427 | static void pblk_line_mg_free(struct pblk *pblk) |
@@ -378,8 +438,6 @@ static void pblk_line_mg_free(struct pblk *pblk) | |||
378 | pblk_mfree(l_mg->eline_meta[i]->buf, l_mg->emeta_alloc_type); | 438 | pblk_mfree(l_mg->eline_meta[i]->buf, l_mg->emeta_alloc_type); |
379 | kfree(l_mg->eline_meta[i]); | 439 | kfree(l_mg->eline_meta[i]); |
380 | } | 440 | } |
381 | |||
382 | kfree(pblk->lines); | ||
383 | } | 441 | } |
384 | 442 | ||
385 | static void pblk_line_meta_free(struct pblk_line *line) | 443 | static void pblk_line_meta_free(struct pblk_line *line) |
@@ -402,6 +460,11 @@ static void pblk_lines_free(struct pblk *pblk) | |||
402 | pblk_line_meta_free(line); | 460 | pblk_line_meta_free(line); |
403 | } | 461 | } |
404 | spin_unlock(&l_mg->free_lock); | 462 | spin_unlock(&l_mg->free_lock); |
463 | |||
464 | pblk_line_mg_free(pblk); | ||
465 | |||
466 | kfree(pblk->luns); | ||
467 | kfree(pblk->lines); | ||
405 | } | 468 | } |
406 | 469 | ||
407 | static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun, | 470 | static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun, |
@@ -476,7 +539,7 @@ static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line, | |||
476 | return bb_cnt; | 539 | return bb_cnt; |
477 | } | 540 | } |
478 | 541 | ||
479 | static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns) | 542 | static int pblk_luns_init(struct pblk *pblk) |
480 | { | 543 | { |
481 | struct nvm_tgt_dev *dev = pblk->dev; | 544 | struct nvm_tgt_dev *dev = pblk->dev; |
482 | struct nvm_geo *geo = &dev->geo; | 545 | struct nvm_geo *geo = &dev->geo; |
@@ -501,7 +564,7 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns) | |||
501 | int lunid = lun_raw + ch * geo->nr_luns; | 564 | int lunid = lun_raw + ch * geo->nr_luns; |
502 | 565 | ||
503 | rlun = &pblk->luns[i]; | 566 | rlun = &pblk->luns[i]; |
504 | rlun->bppa = luns[lunid]; | 567 | rlun->bppa = dev->luns[lunid]; |
505 | 568 | ||
506 | sema_init(&rlun->wr_sem, 1); | 569 | sema_init(&rlun->wr_sem, 1); |
507 | } | 570 | } |
@@ -509,38 +572,6 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns) | |||
509 | return 0; | 572 | return 0; |
510 | } | 573 | } |
511 | 574 | ||
512 | static int pblk_lines_configure(struct pblk *pblk, int flags) | ||
513 | { | ||
514 | struct pblk_line *line = NULL; | ||
515 | int ret = 0; | ||
516 | |||
517 | if (!(flags & NVM_TARGET_FACTORY)) { | ||
518 | line = pblk_recov_l2p(pblk); | ||
519 | if (IS_ERR(line)) { | ||
520 | pr_err("pblk: could not recover l2p table\n"); | ||
521 | ret = -EFAULT; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | #ifdef CONFIG_NVM_DEBUG | ||
526 | pr_info("pblk init: L2P CRC: %x\n", pblk_l2p_crc(pblk)); | ||
527 | #endif | ||
528 | |||
529 | /* Free full lines directly as GC has not been started yet */ | ||
530 | pblk_gc_free_full_lines(pblk); | ||
531 | |||
532 | if (!line) { | ||
533 | /* Configure next line for user data */ | ||
534 | line = pblk_line_get_first_data(pblk); | ||
535 | if (!line) { | ||
536 | pr_err("pblk: line list corrupted\n"); | ||
537 | ret = -EFAULT; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | return ret; | ||
542 | } | ||
543 | |||
544 | /* See comment over struct line_emeta definition */ | 575 | /* See comment over struct line_emeta definition */ |
545 | static unsigned int calc_emeta_len(struct pblk *pblk) | 576 | static unsigned int calc_emeta_len(struct pblk *pblk) |
546 | { | 577 | { |
@@ -606,11 +637,70 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks) | |||
606 | atomic_set(&pblk->rl.free_user_blocks, nr_free_blks); | 637 | atomic_set(&pblk->rl.free_user_blocks, nr_free_blks); |
607 | } | 638 | } |
608 | 639 | ||
609 | static int pblk_lines_alloc_metadata(struct pblk *pblk) | 640 | static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line, |
641 | void *chunk_log, long *nr_bad_blks) | ||
642 | { | ||
643 | struct pblk_line_meta *lm = &pblk->lm; | ||
644 | |||
645 | line->blk_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL); | ||
646 | if (!line->blk_bitmap) | ||
647 | return -ENOMEM; | ||
648 | |||
649 | line->erase_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL); | ||
650 | if (!line->erase_bitmap) { | ||
651 | kfree(line->blk_bitmap); | ||
652 | return -ENOMEM; | ||
653 | } | ||
654 | |||
655 | *nr_bad_blks = pblk_bb_line(pblk, line, chunk_log, lm->blk_per_line); | ||
656 | |||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static int pblk_line_mg_init(struct pblk *pblk) | ||
610 | { | 661 | { |
662 | struct nvm_tgt_dev *dev = pblk->dev; | ||
663 | struct nvm_geo *geo = &dev->geo; | ||
611 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; | 664 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; |
612 | struct pblk_line_meta *lm = &pblk->lm; | 665 | struct pblk_line_meta *lm = &pblk->lm; |
613 | int i; | 666 | int i, bb_distance; |
667 | |||
668 | l_mg->nr_lines = geo->nr_chks; | ||
669 | l_mg->log_line = l_mg->data_line = NULL; | ||
670 | l_mg->l_seq_nr = l_mg->d_seq_nr = 0; | ||
671 | l_mg->nr_free_lines = 0; | ||
672 | bitmap_zero(&l_mg->meta_bitmap, PBLK_DATA_LINES); | ||
673 | |||
674 | INIT_LIST_HEAD(&l_mg->free_list); | ||
675 | INIT_LIST_HEAD(&l_mg->corrupt_list); | ||
676 | INIT_LIST_HEAD(&l_mg->bad_list); | ||
677 | INIT_LIST_HEAD(&l_mg->gc_full_list); | ||
678 | INIT_LIST_HEAD(&l_mg->gc_high_list); | ||
679 | INIT_LIST_HEAD(&l_mg->gc_mid_list); | ||
680 | INIT_LIST_HEAD(&l_mg->gc_low_list); | ||
681 | INIT_LIST_HEAD(&l_mg->gc_empty_list); | ||
682 | |||
683 | INIT_LIST_HEAD(&l_mg->emeta_list); | ||
684 | |||
685 | l_mg->gc_lists[0] = &l_mg->gc_high_list; | ||
686 | l_mg->gc_lists[1] = &l_mg->gc_mid_list; | ||
687 | l_mg->gc_lists[2] = &l_mg->gc_low_list; | ||
688 | |||
689 | spin_lock_init(&l_mg->free_lock); | ||
690 | spin_lock_init(&l_mg->close_lock); | ||
691 | spin_lock_init(&l_mg->gc_lock); | ||
692 | |||
693 | l_mg->vsc_list = kcalloc(l_mg->nr_lines, sizeof(__le32), GFP_KERNEL); | ||
694 | if (!l_mg->vsc_list) | ||
695 | goto fail; | ||
696 | |||
697 | l_mg->bb_template = kzalloc(lm->sec_bitmap_len, GFP_KERNEL); | ||
698 | if (!l_mg->bb_template) | ||
699 | goto fail_free_vsc_list; | ||
700 | |||
701 | l_mg->bb_aux = kzalloc(lm->sec_bitmap_len, GFP_KERNEL); | ||
702 | if (!l_mg->bb_aux) | ||
703 | goto fail_free_bb_template; | ||
614 | 704 | ||
615 | /* smeta is always small enough to fit on a kmalloc memory allocation, | 705 | /* smeta is always small enough to fit on a kmalloc memory allocation, |
616 | * emeta depends on the number of LUNs allocated to the pblk instance | 706 | * emeta depends on the number of LUNs allocated to the pblk instance |
@@ -656,13 +746,13 @@ static int pblk_lines_alloc_metadata(struct pblk *pblk) | |||
656 | } | 746 | } |
657 | } | 747 | } |
658 | 748 | ||
659 | l_mg->vsc_list = kcalloc(l_mg->nr_lines, sizeof(__le32), GFP_KERNEL); | ||
660 | if (!l_mg->vsc_list) | ||
661 | goto fail_free_emeta; | ||
662 | |||
663 | for (i = 0; i < l_mg->nr_lines; i++) | 749 | for (i = 0; i < l_mg->nr_lines; i++) |
664 | l_mg->vsc_list[i] = cpu_to_le32(EMPTY_ENTRY); | 750 | l_mg->vsc_list[i] = cpu_to_le32(EMPTY_ENTRY); |
665 | 751 | ||
752 | bb_distance = (geo->all_luns) * geo->ws_opt; | ||
753 | for (i = 0; i < lm->sec_per_line; i += bb_distance) | ||
754 | bitmap_set(l_mg->bb_template, i, geo->ws_opt); | ||
755 | |||
666 | return 0; | 756 | return 0; |
667 | 757 | ||
668 | fail_free_emeta: | 758 | fail_free_emeta: |
@@ -673,69 +763,25 @@ fail_free_emeta: | |||
673 | kfree(l_mg->eline_meta[i]->buf); | 763 | kfree(l_mg->eline_meta[i]->buf); |
674 | kfree(l_mg->eline_meta[i]); | 764 | kfree(l_mg->eline_meta[i]); |
675 | } | 765 | } |
676 | |||
677 | fail_free_smeta: | 766 | fail_free_smeta: |
678 | for (i = 0; i < PBLK_DATA_LINES; i++) | 767 | for (i = 0; i < PBLK_DATA_LINES; i++) |
679 | kfree(l_mg->sline_meta[i]); | 768 | kfree(l_mg->sline_meta[i]); |
680 | 769 | kfree(l_mg->bb_aux); | |
770 | fail_free_bb_template: | ||
771 | kfree(l_mg->bb_template); | ||
772 | fail_free_vsc_list: | ||
773 | kfree(l_mg->vsc_list); | ||
774 | fail: | ||
681 | return -ENOMEM; | 775 | return -ENOMEM; |
682 | } | 776 | } |
683 | 777 | ||
684 | static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line, | 778 | static int pblk_line_meta_init(struct pblk *pblk) |
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 | |||
704 | static int pblk_lines_init(struct pblk *pblk) | ||
705 | { | 779 | { |
706 | struct nvm_tgt_dev *dev = pblk->dev; | 780 | struct nvm_tgt_dev *dev = pblk->dev; |
707 | struct nvm_geo *geo = &dev->geo; | 781 | struct nvm_geo *geo = &dev->geo; |
708 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; | ||
709 | struct pblk_line_meta *lm = &pblk->lm; | 782 | struct pblk_line_meta *lm = &pblk->lm; |
710 | struct pblk_line *line; | ||
711 | void *chunk_log; | ||
712 | unsigned int smeta_len, emeta_len; | 783 | unsigned int smeta_len, emeta_len; |
713 | long nr_bad_blks = 0, nr_free_blks = 0; | 784 | int i; |
714 | int bb_distance, max_write_ppas, mod; | ||
715 | int i, ret; | ||
716 | |||
717 | pblk->min_write_pgs = geo->sec_per_pl * (geo->sec_size / PAGE_SIZE); | ||
718 | max_write_ppas = pblk->min_write_pgs * geo->all_luns; | ||
719 | pblk->max_write_pgs = min_t(int, max_write_ppas, NVM_MAX_VLBA); | ||
720 | pblk_set_sec_per_write(pblk, pblk->min_write_pgs); | ||
721 | |||
722 | if (pblk->max_write_pgs > PBLK_MAX_REQ_ADDRS) { | ||
723 | pr_err("pblk: vector list too big(%u > %u)\n", | ||
724 | pblk->max_write_pgs, PBLK_MAX_REQ_ADDRS); | ||
725 | return -EINVAL; | ||
726 | } | ||
727 | |||
728 | div_u64_rem(geo->sec_per_chk, pblk->min_write_pgs, &mod); | ||
729 | if (mod) { | ||
730 | pr_err("pblk: bad configuration of sectors/pages\n"); | ||
731 | return -EINVAL; | ||
732 | } | ||
733 | |||
734 | l_mg->nr_lines = geo->nr_chks; | ||
735 | l_mg->log_line = l_mg->data_line = NULL; | ||
736 | l_mg->l_seq_nr = l_mg->d_seq_nr = 0; | ||
737 | l_mg->nr_free_lines = 0; | ||
738 | bitmap_zero(&l_mg->meta_bitmap, PBLK_DATA_LINES); | ||
739 | 785 | ||
740 | lm->sec_per_line = geo->sec_per_chk * geo->all_luns; | 786 | lm->sec_per_line = geo->sec_per_chk * geo->all_luns; |
741 | lm->blk_per_line = geo->all_luns; | 787 | lm->blk_per_line = geo->all_luns; |
@@ -787,58 +833,43 @@ add_emeta_page: | |||
787 | return -EINVAL; | 833 | return -EINVAL; |
788 | } | 834 | } |
789 | 835 | ||
790 | ret = pblk_lines_alloc_metadata(pblk); | 836 | return 0; |
837 | } | ||
838 | |||
839 | static int pblk_lines_init(struct pblk *pblk) | ||
840 | { | ||
841 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; | ||
842 | struct pblk_line_meta *lm = &pblk->lm; | ||
843 | struct pblk_line *line; | ||
844 | void *chunk_log; | ||
845 | long nr_bad_blks = 0, nr_free_blks = 0; | ||
846 | int i, ret; | ||
847 | |||
848 | ret = pblk_line_meta_init(pblk); | ||
791 | if (ret) | 849 | if (ret) |
792 | return ret; | 850 | return ret; |
793 | 851 | ||
794 | l_mg->bb_template = kzalloc(lm->sec_bitmap_len, GFP_KERNEL); | 852 | ret = pblk_line_mg_init(pblk); |
795 | if (!l_mg->bb_template) { | 853 | if (ret) |
796 | ret = -ENOMEM; | 854 | return ret; |
855 | |||
856 | ret = pblk_luns_init(pblk); | ||
857 | if (ret) | ||
797 | goto fail_free_meta; | 858 | goto fail_free_meta; |
798 | } | ||
799 | 859 | ||
800 | l_mg->bb_aux = kzalloc(lm->sec_bitmap_len, GFP_KERNEL); | 860 | chunk_log = pblk_bb_get_log(pblk); |
801 | if (!l_mg->bb_aux) { | 861 | if (IS_ERR(chunk_log)) { |
802 | ret = -ENOMEM; | 862 | pr_err("pblk: could not get bad block log (%lu)\n", |
803 | goto fail_free_bb_template; | 863 | PTR_ERR(chunk_log)); |
864 | ret = PTR_ERR(chunk_log); | ||
865 | goto fail_free_luns; | ||
804 | } | 866 | } |
805 | 867 | ||
806 | bb_distance = (geo->all_luns) * geo->sec_per_pl; | ||
807 | for (i = 0; i < lm->sec_per_line; i += bb_distance) | ||
808 | bitmap_set(l_mg->bb_template, i, geo->sec_per_pl); | ||
809 | |||
810 | INIT_LIST_HEAD(&l_mg->free_list); | ||
811 | INIT_LIST_HEAD(&l_mg->corrupt_list); | ||
812 | INIT_LIST_HEAD(&l_mg->bad_list); | ||
813 | INIT_LIST_HEAD(&l_mg->gc_full_list); | ||
814 | INIT_LIST_HEAD(&l_mg->gc_high_list); | ||
815 | INIT_LIST_HEAD(&l_mg->gc_mid_list); | ||
816 | INIT_LIST_HEAD(&l_mg->gc_low_list); | ||
817 | INIT_LIST_HEAD(&l_mg->gc_empty_list); | ||
818 | |||
819 | INIT_LIST_HEAD(&l_mg->emeta_list); | ||
820 | |||
821 | l_mg->gc_lists[0] = &l_mg->gc_high_list; | ||
822 | l_mg->gc_lists[1] = &l_mg->gc_mid_list; | ||
823 | l_mg->gc_lists[2] = &l_mg->gc_low_list; | ||
824 | |||
825 | spin_lock_init(&l_mg->free_lock); | ||
826 | spin_lock_init(&l_mg->close_lock); | ||
827 | spin_lock_init(&l_mg->gc_lock); | ||
828 | |||
829 | pblk->lines = kcalloc(l_mg->nr_lines, sizeof(struct pblk_line), | 868 | pblk->lines = kcalloc(l_mg->nr_lines, sizeof(struct pblk_line), |
830 | GFP_KERNEL); | 869 | GFP_KERNEL); |
831 | if (!pblk->lines) { | 870 | if (!pblk->lines) { |
832 | ret = -ENOMEM; | 871 | ret = -ENOMEM; |
833 | goto fail_free_bb_aux; | 872 | goto fail_free_chunk_log; |
834 | } | ||
835 | |||
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 | } | 873 | } |
843 | 874 | ||
844 | for (i = 0; i < l_mg->nr_lines; i++) { | 875 | for (i = 0; i < l_mg->nr_lines; i++) { |
@@ -856,7 +887,7 @@ add_emeta_page: | |||
856 | 887 | ||
857 | ret = pblk_setup_line_meta(pblk, line, chunk_log, &nr_bad_blks); | 888 | ret = pblk_setup_line_meta(pblk, line, chunk_log, &nr_bad_blks); |
858 | if (ret) | 889 | if (ret) |
859 | goto fail_free_chunk_log; | 890 | goto fail_free_lines; |
860 | 891 | ||
861 | chk_in_line = lm->blk_per_line - nr_bad_blks; | 892 | chk_in_line = lm->blk_per_line - nr_bad_blks; |
862 | if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line || | 893 | if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line || |
@@ -878,14 +909,14 @@ add_emeta_page: | |||
878 | kfree(chunk_log); | 909 | kfree(chunk_log); |
879 | return 0; | 910 | return 0; |
880 | 911 | ||
881 | fail_free_chunk_log: | 912 | fail_free_lines: |
882 | kfree(chunk_log); | ||
883 | while (--i >= 0) | 913 | while (--i >= 0) |
884 | pblk_line_meta_free(&pblk->lines[i]); | 914 | pblk_line_meta_free(&pblk->lines[i]); |
885 | fail_free_bb_aux: | 915 | kfree(pblk->lines); |
886 | kfree(l_mg->bb_aux); | 916 | fail_free_chunk_log: |
887 | fail_free_bb_template: | 917 | kfree(chunk_log); |
888 | kfree(l_mg->bb_template); | 918 | fail_free_luns: |
919 | kfree(pblk->luns); | ||
889 | fail_free_meta: | 920 | fail_free_meta: |
890 | pblk_line_mg_free(pblk); | 921 | pblk_line_mg_free(pblk); |
891 | 922 | ||
@@ -928,12 +959,10 @@ static void pblk_writer_stop(struct pblk *pblk) | |||
928 | 959 | ||
929 | static void pblk_free(struct pblk *pblk) | 960 | static void pblk_free(struct pblk *pblk) |
930 | { | 961 | { |
931 | pblk_luns_free(pblk); | ||
932 | pblk_lines_free(pblk); | 962 | pblk_lines_free(pblk); |
933 | kfree(pblk->pad_dist); | ||
934 | pblk_line_mg_free(pblk); | ||
935 | pblk_core_free(pblk); | ||
936 | pblk_l2p_free(pblk); | 963 | pblk_l2p_free(pblk); |
964 | pblk_rwb_free(pblk); | ||
965 | pblk_core_free(pblk); | ||
937 | 966 | ||
938 | kfree(pblk); | 967 | kfree(pblk); |
939 | } | 968 | } |
@@ -998,19 +1027,6 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk, | |||
998 | spin_lock_init(&pblk->trans_lock); | 1027 | spin_lock_init(&pblk->trans_lock); |
999 | spin_lock_init(&pblk->lock); | 1028 | spin_lock_init(&pblk->lock); |
1000 | 1029 | ||
1001 | if (flags & NVM_TARGET_FACTORY) | ||
1002 | pblk_setup_uuid(pblk); | ||
1003 | |||
1004 | atomic64_set(&pblk->user_wa, 0); | ||
1005 | atomic64_set(&pblk->pad_wa, 0); | ||
1006 | atomic64_set(&pblk->gc_wa, 0); | ||
1007 | pblk->user_rst_wa = 0; | ||
1008 | pblk->pad_rst_wa = 0; | ||
1009 | pblk->gc_rst_wa = 0; | ||
1010 | |||
1011 | atomic64_set(&pblk->nr_flush, 0); | ||
1012 | pblk->nr_flush_rst = 0; | ||
1013 | |||
1014 | #ifdef CONFIG_NVM_DEBUG | 1030 | #ifdef CONFIG_NVM_DEBUG |
1015 | atomic_long_set(&pblk->inflight_writes, 0); | 1031 | atomic_long_set(&pblk->inflight_writes, 0); |
1016 | atomic_long_set(&pblk->padded_writes, 0); | 1032 | atomic_long_set(&pblk->padded_writes, 0); |
@@ -1034,48 +1050,35 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk, | |||
1034 | atomic_long_set(&pblk->write_failed, 0); | 1050 | atomic_long_set(&pblk->write_failed, 0); |
1035 | atomic_long_set(&pblk->erase_failed, 0); | 1051 | atomic_long_set(&pblk->erase_failed, 0); |
1036 | 1052 | ||
1037 | ret = pblk_luns_init(pblk, dev->luns); | 1053 | ret = pblk_core_init(pblk); |
1038 | if (ret) { | 1054 | if (ret) { |
1039 | pr_err("pblk: could not initialize luns\n"); | 1055 | pr_err("pblk: could not initialize core\n"); |
1040 | goto fail; | 1056 | goto fail; |
1041 | } | 1057 | } |
1042 | 1058 | ||
1043 | ret = pblk_lines_init(pblk); | 1059 | ret = pblk_lines_init(pblk); |
1044 | if (ret) { | 1060 | if (ret) { |
1045 | pr_err("pblk: could not initialize lines\n"); | 1061 | pr_err("pblk: could not initialize lines\n"); |
1046 | goto fail_free_luns; | 1062 | goto fail_free_core; |
1047 | } | ||
1048 | |||
1049 | pblk->pad_dist = kzalloc((pblk->min_write_pgs - 1) * sizeof(atomic64_t), | ||
1050 | GFP_KERNEL); | ||
1051 | if (!pblk->pad_dist) { | ||
1052 | ret = -ENOMEM; | ||
1053 | goto fail_free_line_meta; | ||
1054 | } | 1063 | } |
1055 | 1064 | ||
1056 | ret = pblk_core_init(pblk); | 1065 | ret = pblk_rwb_init(pblk); |
1057 | if (ret) { | 1066 | if (ret) { |
1058 | pr_err("pblk: could not initialize core\n"); | 1067 | pr_err("pblk: could not initialize write buffer\n"); |
1059 | goto fail_free_pad_dist; | 1068 | goto fail_free_lines; |
1060 | } | 1069 | } |
1061 | 1070 | ||
1062 | ret = pblk_l2p_init(pblk); | 1071 | ret = pblk_l2p_init(pblk, flags & NVM_TARGET_FACTORY); |
1063 | if (ret) { | 1072 | if (ret) { |
1064 | pr_err("pblk: could not initialize maps\n"); | 1073 | pr_err("pblk: could not initialize maps\n"); |
1065 | goto fail_free_core; | 1074 | goto fail_free_rwb; |
1066 | } | ||
1067 | |||
1068 | ret = pblk_lines_configure(pblk, flags); | ||
1069 | if (ret) { | ||
1070 | pr_err("pblk: could not configure lines\n"); | ||
1071 | goto fail_free_l2p; | ||
1072 | } | 1075 | } |
1073 | 1076 | ||
1074 | ret = pblk_writer_init(pblk); | 1077 | ret = pblk_writer_init(pblk); |
1075 | if (ret) { | 1078 | if (ret) { |
1076 | if (ret != -EINTR) | 1079 | if (ret != -EINTR) |
1077 | pr_err("pblk: could not initialize write thread\n"); | 1080 | pr_err("pblk: could not initialize write thread\n"); |
1078 | goto fail_free_lines; | 1081 | goto fail_free_l2p; |
1079 | } | 1082 | } |
1080 | 1083 | ||
1081 | ret = pblk_gc_init(pblk); | 1084 | ret = pblk_gc_init(pblk); |
@@ -1110,18 +1113,14 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk, | |||
1110 | 1113 | ||
1111 | fail_stop_writer: | 1114 | fail_stop_writer: |
1112 | pblk_writer_stop(pblk); | 1115 | pblk_writer_stop(pblk); |
1113 | fail_free_lines: | ||
1114 | pblk_lines_free(pblk); | ||
1115 | fail_free_l2p: | 1116 | fail_free_l2p: |
1116 | pblk_l2p_free(pblk); | 1117 | pblk_l2p_free(pblk); |
1118 | fail_free_rwb: | ||
1119 | pblk_rwb_free(pblk); | ||
1120 | fail_free_lines: | ||
1121 | pblk_lines_free(pblk); | ||
1117 | fail_free_core: | 1122 | fail_free_core: |
1118 | pblk_core_free(pblk); | 1123 | pblk_core_free(pblk); |
1119 | fail_free_pad_dist: | ||
1120 | kfree(pblk->pad_dist); | ||
1121 | fail_free_line_meta: | ||
1122 | pblk_line_mg_free(pblk); | ||
1123 | fail_free_luns: | ||
1124 | pblk_luns_free(pblk); | ||
1125 | fail: | 1124 | fail: |
1126 | kfree(pblk); | 1125 | kfree(pblk); |
1127 | return ERR_PTR(ret); | 1126 | return ERR_PTR(ret); |