summaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm
diff options
context:
space:
mode:
authorJavier González <javier@javigon.com>2018-06-01 09:04:16 -0400
committerJens Axboe <axboe@kernel.dk>2018-06-01 09:43:53 -0400
commit1d8b33e05cea69a1b0b7f2f2a7c102b6583a984f (patch)
treee591e7a0e7ace394454241a3e42675dc34dff0c7 /drivers/lightnvm
parent2deeefc02dfff6b554020eb62aecf98814641372 (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.c38
-rw-r--r--drivers/lightnvm/pblk-init.c11
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)
1174static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line) 1174static 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
1230fail_free_invalid_bitmap:
1231 spin_unlock(&line->lock);
1232 kfree(line->invalid_bitmap);
1233 line->invalid_bitmap = NULL;
1234fail_free_map_bitmap:
1235 kfree(line->map_bitmap);
1236 line->map_bitmap = NULL;
1237
1238 return ret;
1225} 1239}
1226 1240
1227int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line) 1241int 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
158static void pblk_rwb_free(struct pblk *pblk) 161static void pblk_rwb_free(struct pblk *pblk)