diff options
author | Javier González <javier@javigon.com> | 2018-06-01 09:04:15 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-06-01 09:43:53 -0400 |
commit | 2deeefc02dfff6b554020eb62aecf98814641372 (patch) | |
tree | dfbad7a5382c329d42d6da0cb85aeac9534973d5 | |
parent | 84e92c131a0a2c7b28d1aa98c69350bc3577f34c (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.c | 5 | ||||
-rw-r--r-- | drivers/lightnvm/pblk-map.c | 33 |
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 | ||
21 | static void pblk_map_page_data(struct pblk *pblk, unsigned int sentry, | 21 | static 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 | ||
79 | void pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry, | 86 | void 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 | ||