aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier González <javier@javigon.com>2018-06-01 09:04:15 -0400
committerJens Axboe <axboe@kernel.dk>2018-06-01 09:43:53 -0400
commit2deeefc02dfff6b554020eb62aecf98814641372 (patch)
treedfbad7a5382c329d42d6da0cb85aeac9534973d5
parent84e92c131a0a2c7b28d1aa98c69350bc3577f34c (diff)
lightnvm: pblk: fail gracefully on line alloc. failure
In the event of a line failing to allocate, fail gracefully and stop the pipeline to avoid more write failing in the same place. 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.c5
-rw-r--r--drivers/lightnvm/pblk-map.c33
2 files changed, 29 insertions, 9 deletions
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 9a984abd3dfe..44f9ec8d4c2a 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -1047,6 +1047,11 @@ static int pblk_lines_init(struct pblk *pblk)
1047 nr_free_chks += pblk_setup_line_meta(pblk, line, chunk_meta, i); 1047 nr_free_chks += pblk_setup_line_meta(pblk, line, chunk_meta, i);
1048 } 1048 }
1049 1049
1050 if (!nr_free_chks) {
1051 pr_err("pblk: too many bad blocks prevent for sane instance\n");
1052 return -EINTR;
1053 }
1054
1050 pblk_set_provision(pblk, nr_free_chks); 1055 pblk_set_provision(pblk, nr_free_chks);
1051 1056
1052 kfree(chunk_meta); 1057 kfree(chunk_meta);
diff --git a/drivers/lightnvm/pblk-map.c b/drivers/lightnvm/pblk-map.c
index 20dbaa89c9df..953ca31dda68 100644
--- a/drivers/lightnvm/pblk-map.c
+++ b/drivers/lightnvm/pblk-map.c
@@ -18,11 +18,11 @@
18 18
19#include "pblk.h" 19#include "pblk.h"
20 20
21static void pblk_map_page_data(struct pblk *pblk, unsigned int sentry, 21static int pblk_map_page_data(struct pblk *pblk, unsigned int sentry,
22 struct ppa_addr *ppa_list, 22 struct ppa_addr *ppa_list,
23 unsigned long *lun_bitmap, 23 unsigned long *lun_bitmap,
24 struct pblk_sec_meta *meta_list, 24 struct pblk_sec_meta *meta_list,
25 unsigned int valid_secs) 25 unsigned int valid_secs)
26{ 26{
27 struct pblk_line *line = pblk_line_get_data(pblk); 27 struct pblk_line *line = pblk_line_get_data(pblk);
28 struct pblk_emeta *emeta; 28 struct pblk_emeta *emeta;
@@ -35,8 +35,14 @@ static void pblk_map_page_data(struct pblk *pblk, unsigned int sentry,
35 if (pblk_line_is_full(line)) { 35 if (pblk_line_is_full(line)) {
36 struct pblk_line *prev_line = line; 36 struct pblk_line *prev_line = line;
37 37
38 /* If we cannot allocate a new line, make sure to store metadata
39 * on current line and then fail
40 */
38 line = pblk_line_replace_data(pblk); 41 line = pblk_line_replace_data(pblk);
39 pblk_line_close_meta(pblk, prev_line); 42 pblk_line_close_meta(pblk, prev_line);
43
44 if (!line)
45 return -EINTR;
40 } 46 }
41 47
42 emeta = line->emeta; 48 emeta = line->emeta;
@@ -74,6 +80,7 @@ static void pblk_map_page_data(struct pblk *pblk, unsigned int sentry,
74 } 80 }
75 81
76 pblk_down_rq(pblk, ppa_list, nr_secs, lun_bitmap); 82 pblk_down_rq(pblk, ppa_list, nr_secs, lun_bitmap);
83 return 0;
77} 84}
78 85
79void pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry, 86void pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry,
@@ -87,8 +94,12 @@ void pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry,
87 94
88 for (i = off; i < rqd->nr_ppas; i += min) { 95 for (i = off; i < rqd->nr_ppas; i += min) {
89 map_secs = (i + min > valid_secs) ? (valid_secs % min) : min; 96 map_secs = (i + min > valid_secs) ? (valid_secs % min) : min;
90 pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i], 97 if (pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i],
91 lun_bitmap, &meta_list[i], map_secs); 98 lun_bitmap, &meta_list[i], map_secs)) {
99 bio_put(rqd->bio);
100 pblk_free_rqd(pblk, rqd, PBLK_WRITE);
101 pblk_pipeline_stop(pblk);
102 }
92 } 103 }
93} 104}
94 105
@@ -108,8 +119,12 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
108 119
109 for (i = 0; i < rqd->nr_ppas; i += min) { 120 for (i = 0; i < rqd->nr_ppas; i += min) {
110 map_secs = (i + min > valid_secs) ? (valid_secs % min) : min; 121 map_secs = (i + min > valid_secs) ? (valid_secs % min) : min;
111 pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i], 122 if (pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i],
112 lun_bitmap, &meta_list[i], map_secs); 123 lun_bitmap, &meta_list[i], map_secs)) {
124 bio_put(rqd->bio);
125 pblk_free_rqd(pblk, rqd, PBLK_WRITE);
126 pblk_pipeline_stop(pblk);
127 }
113 128
114 erase_lun = pblk_ppa_to_pos(geo, rqd->ppa_list[i]); 129 erase_lun = pblk_ppa_to_pos(geo, rqd->ppa_list[i]);
115 130