diff options
author | Javier González <javier@javigon.com> | 2018-06-01 09:04:16 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-06-01 09:43:53 -0400 |
commit | 1d8b33e05cea69a1b0b7f2f2a7c102b6583a984f (patch) | |
tree | e591e7a0e7ace394454241a3e42675dc34dff0c7 /drivers/lightnvm | |
parent | 2deeefc02dfff6b554020eb62aecf98814641372 (diff) |
lightnvm: pblk: recheck for bad lines at runtime
Bad blocks can grow at runtime. Check that the number of valid blocks in
a line are within the sanity threshold before allocating the line for
new writes.
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')
-rw-r--r-- | drivers/lightnvm/pblk-core.c | 38 | ||||
-rw-r--r-- | drivers/lightnvm/pblk-init.c | 11 |
2 files changed, 35 insertions, 14 deletions
diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c index 934341b10493..f34ce522348e 100644 --- a/drivers/lightnvm/pblk-core.c +++ b/drivers/lightnvm/pblk-core.c | |||
@@ -1174,7 +1174,8 @@ static int pblk_prepare_new_line(struct pblk *pblk, struct pblk_line *line) | |||
1174 | static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line) | 1174 | static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line) |
1175 | { | 1175 | { |
1176 | struct pblk_line_meta *lm = &pblk->lm; | 1176 | struct pblk_line_meta *lm = &pblk->lm; |
1177 | int blk_to_erase; | 1177 | int blk_in_line = atomic_read(&line->blk_in_line); |
1178 | int blk_to_erase, ret; | ||
1178 | 1179 | ||
1179 | line->map_bitmap = kzalloc(lm->sec_bitmap_len, GFP_ATOMIC); | 1180 | line->map_bitmap = kzalloc(lm->sec_bitmap_len, GFP_ATOMIC); |
1180 | if (!line->map_bitmap) | 1181 | if (!line->map_bitmap) |
@@ -1183,8 +1184,8 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line) | |||
1183 | /* will be initialized using bb info from map_bitmap */ | 1184 | /* will be initialized using bb info from map_bitmap */ |
1184 | line->invalid_bitmap = kmalloc(lm->sec_bitmap_len, GFP_ATOMIC); | 1185 | line->invalid_bitmap = kmalloc(lm->sec_bitmap_len, GFP_ATOMIC); |
1185 | if (!line->invalid_bitmap) { | 1186 | if (!line->invalid_bitmap) { |
1186 | kfree(line->map_bitmap); | 1187 | ret = -ENOMEM; |
1187 | return -ENOMEM; | 1188 | goto fail_free_map_bitmap; |
1188 | } | 1189 | } |
1189 | 1190 | ||
1190 | /* Bad blocks do not need to be erased */ | 1191 | /* Bad blocks do not need to be erased */ |
@@ -1199,16 +1200,19 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line) | |||
1199 | blk_to_erase = pblk_prepare_new_line(pblk, line); | 1200 | blk_to_erase = pblk_prepare_new_line(pblk, line); |
1200 | line->state = PBLK_LINESTATE_FREE; | 1201 | line->state = PBLK_LINESTATE_FREE; |
1201 | } else { | 1202 | } else { |
1202 | blk_to_erase = atomic_read(&line->blk_in_line); | 1203 | blk_to_erase = blk_in_line; |
1204 | } | ||
1205 | |||
1206 | if (blk_in_line < lm->min_blk_line) { | ||
1207 | ret = -EAGAIN; | ||
1208 | goto fail_free_invalid_bitmap; | ||
1203 | } | 1209 | } |
1204 | 1210 | ||
1205 | if (line->state != PBLK_LINESTATE_FREE) { | 1211 | if (line->state != PBLK_LINESTATE_FREE) { |
1206 | kfree(line->map_bitmap); | ||
1207 | kfree(line->invalid_bitmap); | ||
1208 | spin_unlock(&line->lock); | ||
1209 | WARN(1, "pblk: corrupted line %d, state %d\n", | 1212 | WARN(1, "pblk: corrupted line %d, state %d\n", |
1210 | line->id, line->state); | 1213 | line->id, line->state); |
1211 | return -EAGAIN; | 1214 | ret = -EINTR; |
1215 | goto fail_free_invalid_bitmap; | ||
1212 | } | 1216 | } |
1213 | 1217 | ||
1214 | line->state = PBLK_LINESTATE_OPEN; | 1218 | line->state = PBLK_LINESTATE_OPEN; |
@@ -1222,6 +1226,16 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line) | |||
1222 | kref_init(&line->ref); | 1226 | kref_init(&line->ref); |
1223 | 1227 | ||
1224 | return 0; | 1228 | return 0; |
1229 | |||
1230 | fail_free_invalid_bitmap: | ||
1231 | spin_unlock(&line->lock); | ||
1232 | kfree(line->invalid_bitmap); | ||
1233 | line->invalid_bitmap = NULL; | ||
1234 | fail_free_map_bitmap: | ||
1235 | kfree(line->map_bitmap); | ||
1236 | line->map_bitmap = NULL; | ||
1237 | |||
1238 | return ret; | ||
1225 | } | 1239 | } |
1226 | 1240 | ||
1227 | int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line) | 1241 | int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line) |
@@ -1292,10 +1306,14 @@ retry: | |||
1292 | 1306 | ||
1293 | ret = pblk_line_prepare(pblk, line); | 1307 | ret = pblk_line_prepare(pblk, line); |
1294 | if (ret) { | 1308 | if (ret) { |
1295 | if (ret == -EAGAIN) { | 1309 | switch (ret) { |
1310 | case -EAGAIN: | ||
1311 | list_add(&line->list, &l_mg->bad_list); | ||
1312 | goto retry; | ||
1313 | case -EINTR: | ||
1296 | list_add(&line->list, &l_mg->corrupt_list); | 1314 | list_add(&line->list, &l_mg->corrupt_list); |
1297 | goto retry; | 1315 | goto retry; |
1298 | } else { | 1316 | default: |
1299 | pr_err("pblk: failed to prepare line %d\n", line->id); | 1317 | pr_err("pblk: failed to prepare line %d\n", line->id); |
1300 | list_add(&line->list, &l_mg->free_list); | 1318 | list_add(&line->list, &l_mg->free_list); |
1301 | l_mg->nr_free_lines++; | 1319 | l_mg->nr_free_lines++; |
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c index 44f9ec8d4c2a..fe501e6d45fc 100644 --- a/drivers/lightnvm/pblk-init.c +++ b/drivers/lightnvm/pblk-init.c | |||
@@ -127,10 +127,8 @@ static int pblk_l2p_recover(struct pblk *pblk, bool factory_init) | |||
127 | if (!line) { | 127 | if (!line) { |
128 | /* Configure next line for user data */ | 128 | /* Configure next line for user data */ |
129 | line = pblk_line_get_first_data(pblk); | 129 | line = pblk_line_get_first_data(pblk); |
130 | if (!line) { | 130 | if (!line) |
131 | pr_err("pblk: line list corrupted\n"); | ||
132 | return -EFAULT; | 131 | return -EFAULT; |
133 | } | ||
134 | } | 132 | } |
135 | 133 | ||
136 | return 0; | 134 | return 0; |
@@ -141,6 +139,7 @@ static int pblk_l2p_init(struct pblk *pblk, bool factory_init) | |||
141 | sector_t i; | 139 | sector_t i; |
142 | struct ppa_addr ppa; | 140 | struct ppa_addr ppa; |
143 | size_t map_size; | 141 | size_t map_size; |
142 | int ret = 0; | ||
144 | 143 | ||
145 | map_size = pblk_trans_map_size(pblk); | 144 | map_size = pblk_trans_map_size(pblk); |
146 | pblk->trans_map = vmalloc(map_size); | 145 | pblk->trans_map = vmalloc(map_size); |
@@ -152,7 +151,11 @@ static int pblk_l2p_init(struct pblk *pblk, bool factory_init) | |||
152 | for (i = 0; i < pblk->rl.nr_secs; i++) | 151 | for (i = 0; i < pblk->rl.nr_secs; i++) |
153 | pblk_trans_map_set(pblk, i, ppa); | 152 | pblk_trans_map_set(pblk, i, ppa); |
154 | 153 | ||
155 | return pblk_l2p_recover(pblk, factory_init); | 154 | ret = pblk_l2p_recover(pblk, factory_init); |
155 | if (ret) | ||
156 | vfree(pblk->trans_map); | ||
157 | |||
158 | return ret; | ||
156 | } | 159 | } |
157 | 160 | ||
158 | static void pblk_rwb_free(struct pblk *pblk) | 161 | static void pblk_rwb_free(struct pblk *pblk) |