summaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm
diff options
context:
space:
mode:
authorJavier González <javier@cnexlabs.com>2017-10-13 08:46:23 -0400
committerJens Axboe <axboe@kernel.dk>2017-10-13 10:34:57 -0400
commit7bd4d370db6090004a06deb526f0f01fa99a3f9f (patch)
tree01cbfeca78132835d73f56f1a42c5aeb0731b287 /drivers/lightnvm
parenta4809fee4e774fdf3296cc69c22ce6e6acef36b2 (diff)
lightnvm: pblk: guarantee line integrity on reads
When a line is recycled during garbage collection, reads can still be issued to the line. If the line is freed in the middle of this process, data corruption might occur. This patch guarantees that lines are not freed in the middle of reads that target them (lines). Specifically, we use the existing line reference to decide when a line is eligible for being freed after the recycle process. Signed-off-by: Javier González <javier@cnexlabs.com> Signed-off-by: Matias Bjørling <m@bjorling.me> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/lightnvm')
-rw-r--r--drivers/lightnvm/pblk-core.c56
-rw-r--r--drivers/lightnvm/pblk-init.c14
-rw-r--r--drivers/lightnvm/pblk-read.c71
-rw-r--r--drivers/lightnvm/pblk.h2
4 files changed, 118 insertions, 25 deletions
diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 08d166ac4f3c..0a41fb998d55 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -1460,10 +1460,8 @@ void pblk_line_free(struct pblk *pblk, struct pblk_line *line)
1460 line->emeta = NULL; 1460 line->emeta = NULL;
1461} 1461}
1462 1462
1463void pblk_line_put(struct kref *ref) 1463static void __pblk_line_put(struct pblk *pblk, struct pblk_line *line)
1464{ 1464{
1465 struct pblk_line *line = container_of(ref, struct pblk_line, ref);
1466 struct pblk *pblk = line->pblk;
1467 struct pblk_line_mgmt *l_mg = &pblk->l_mg; 1465 struct pblk_line_mgmt *l_mg = &pblk->l_mg;
1468 1466
1469 spin_lock(&line->lock); 1467 spin_lock(&line->lock);
@@ -1481,6 +1479,43 @@ void pblk_line_put(struct kref *ref)
1481 pblk_rl_free_lines_inc(&pblk->rl, line); 1479 pblk_rl_free_lines_inc(&pblk->rl, line);
1482} 1480}
1483 1481
1482static void pblk_line_put_ws(struct work_struct *work)
1483{
1484 struct pblk_line_ws *line_put_ws = container_of(work,
1485 struct pblk_line_ws, ws);
1486 struct pblk *pblk = line_put_ws->pblk;
1487 struct pblk_line *line = line_put_ws->line;
1488
1489 __pblk_line_put(pblk, line);
1490 mempool_free(line_put_ws, pblk->gen_ws_pool);
1491}
1492
1493void pblk_line_put(struct kref *ref)
1494{
1495 struct pblk_line *line = container_of(ref, struct pblk_line, ref);
1496 struct pblk *pblk = line->pblk;
1497
1498 __pblk_line_put(pblk, line);
1499}
1500
1501void pblk_line_put_wq(struct kref *ref)
1502{
1503 struct pblk_line *line = container_of(ref, struct pblk_line, ref);
1504 struct pblk *pblk = line->pblk;
1505 struct pblk_line_ws *line_put_ws;
1506
1507 line_put_ws = mempool_alloc(pblk->gen_ws_pool, GFP_ATOMIC);
1508 if (!line_put_ws)
1509 return;
1510
1511 line_put_ws->pblk = pblk;
1512 line_put_ws->line = line;
1513 line_put_ws->priv = NULL;
1514
1515 INIT_WORK(&line_put_ws->ws, pblk_line_put_ws);
1516 queue_work(pblk->r_end_wq, &line_put_ws->ws);
1517}
1518
1484int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr ppa) 1519int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr ppa)
1485{ 1520{
1486 struct nvm_rq *rqd; 1521 struct nvm_rq *rqd;
@@ -1878,8 +1913,19 @@ void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
1878 int i; 1913 int i;
1879 1914
1880 spin_lock(&pblk->trans_lock); 1915 spin_lock(&pblk->trans_lock);
1881 for (i = 0; i < nr_secs; i++) 1916 for (i = 0; i < nr_secs; i++) {
1882 ppas[i] = pblk_trans_map_get(pblk, blba + i); 1917 struct ppa_addr ppa;
1918
1919 ppa = ppas[i] = pblk_trans_map_get(pblk, blba + i);
1920
1921 /* If the L2P entry maps to a line, the reference is valid */
1922 if (!pblk_ppa_empty(ppa) && !pblk_addr_in_cache(ppa)) {
1923 int line_id = pblk_dev_ppa_to_line(ppa);
1924 struct pblk_line *line = &pblk->lines[line_id];
1925
1926 kref_get(&line->ref);
1927 }
1928 }
1883 spin_unlock(&pblk->trans_lock); 1929 spin_unlock(&pblk->trans_lock);
1884} 1930}
1885 1931
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 4d719782f65b..34527646c01b 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -271,15 +271,22 @@ static int pblk_core_init(struct pblk *pblk)
271 if (!pblk->bb_wq) 271 if (!pblk->bb_wq)
272 goto free_close_wq; 272 goto free_close_wq;
273 273
274 if (pblk_set_ppaf(pblk)) 274 pblk->r_end_wq = alloc_workqueue("pblk-read-end-wq",
275 WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
276 if (!pblk->r_end_wq)
275 goto free_bb_wq; 277 goto free_bb_wq;
276 278
279 if (pblk_set_ppaf(pblk))
280 goto free_r_end_wq;
281
277 if (pblk_rwb_init(pblk)) 282 if (pblk_rwb_init(pblk))
278 goto free_bb_wq; 283 goto free_r_end_wq;
279 284
280 INIT_LIST_HEAD(&pblk->compl_list); 285 INIT_LIST_HEAD(&pblk->compl_list);
281 return 0; 286 return 0;
282 287
288free_r_end_wq:
289 destroy_workqueue(pblk->r_end_wq);
283free_bb_wq: 290free_bb_wq:
284 destroy_workqueue(pblk->bb_wq); 291 destroy_workqueue(pblk->bb_wq);
285free_close_wq: 292free_close_wq:
@@ -304,6 +311,9 @@ static void pblk_core_free(struct pblk *pblk)
304 if (pblk->close_wq) 311 if (pblk->close_wq)
305 destroy_workqueue(pblk->close_wq); 312 destroy_workqueue(pblk->close_wq);
306 313
314 if (pblk->r_end_wq)
315 destroy_workqueue(pblk->r_end_wq);
316
307 if (pblk->bb_wq) 317 if (pblk->bb_wq)
308 destroy_workqueue(pblk->bb_wq); 318 destroy_workqueue(pblk->bb_wq);
309 319
diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c
index a465d9980df4..402f8eff6a2e 100644
--- a/drivers/lightnvm/pblk-read.c
+++ b/drivers/lightnvm/pblk-read.c
@@ -130,9 +130,34 @@ static void pblk_read_check(struct pblk *pblk, struct nvm_rq *rqd,
130 } 130 }
131} 131}
132 132
133static void pblk_end_io_read(struct nvm_rq *rqd) 133static void pblk_read_put_rqd_kref(struct pblk *pblk, struct nvm_rq *rqd)
134{
135 struct ppa_addr *ppa_list;
136 int i;
137
138 ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr;
139
140 for (i = 0; i < rqd->nr_ppas; i++) {
141 struct ppa_addr ppa = ppa_list[i];
142 struct pblk_line *line;
143
144 line = &pblk->lines[pblk_dev_ppa_to_line(ppa)];
145 kref_put(&line->ref, pblk_line_put_wq);
146 }
147}
148
149static void pblk_end_user_read(struct bio *bio)
150{
151#ifdef CONFIG_NVM_DEBUG
152 WARN_ONCE(bio->bi_status, "pblk: corrupted read bio\n");
153#endif
154 bio_endio(bio);
155 bio_put(bio);
156}
157
158static void __pblk_end_io_read(struct pblk *pblk, struct nvm_rq *rqd,
159 bool put_line)
134{ 160{
135 struct pblk *pblk = rqd->private;
136 struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd); 161 struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
137 struct bio *bio = rqd->bio; 162 struct bio *bio = rqd->bio;
138 163
@@ -146,15 +171,11 @@ static void pblk_end_io_read(struct nvm_rq *rqd)
146 pblk_read_check(pblk, rqd, r_ctx->lba); 171 pblk_read_check(pblk, rqd, r_ctx->lba);
147 172
148 bio_put(bio); 173 bio_put(bio);
149 if (r_ctx->private) { 174 if (r_ctx->private)
150 struct bio *orig_bio = r_ctx->private; 175 pblk_end_user_read((struct bio *)r_ctx->private);
151 176
152#ifdef CONFIG_NVM_DEBUG 177 if (put_line)
153 WARN_ONCE(orig_bio->bi_status, "pblk: corrupted read bio\n"); 178 pblk_read_put_rqd_kref(pblk, rqd);
154#endif
155 bio_endio(orig_bio);
156 bio_put(orig_bio);
157 }
158 179
159#ifdef CONFIG_NVM_DEBUG 180#ifdef CONFIG_NVM_DEBUG
160 atomic_long_add(rqd->nr_ppas, &pblk->sync_reads); 181 atomic_long_add(rqd->nr_ppas, &pblk->sync_reads);
@@ -165,6 +186,13 @@ static void pblk_end_io_read(struct nvm_rq *rqd)
165 atomic_dec(&pblk->inflight_io); 186 atomic_dec(&pblk->inflight_io);
166} 187}
167 188
189static void pblk_end_io_read(struct nvm_rq *rqd)
190{
191 struct pblk *pblk = rqd->private;
192
193 __pblk_end_io_read(pblk, rqd, true);
194}
195
168static int pblk_fill_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd, 196static int pblk_fill_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd,
169 unsigned int bio_init_idx, 197 unsigned int bio_init_idx,
170 unsigned long *read_bitmap) 198 unsigned long *read_bitmap)
@@ -233,8 +261,12 @@ static int pblk_fill_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd,
233 } 261 }
234 262
235 if (unlikely(nr_secs > 1 && nr_holes == 1)) { 263 if (unlikely(nr_secs > 1 && nr_holes == 1)) {
264 struct ppa_addr ppa;
265
266 ppa = rqd->ppa_addr;
236 rqd->ppa_list = ppa_ptr; 267 rqd->ppa_list = ppa_ptr;
237 rqd->dma_ppa_list = dma_ppa_list; 268 rqd->dma_ppa_list = dma_ppa_list;
269 rqd->ppa_list[0] = ppa;
238 } 270 }
239 271
240 for (i = 0; i < nr_secs; i++) { 272 for (i = 0; i < nr_secs; i++) {
@@ -246,6 +278,11 @@ static int pblk_fill_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd,
246 i = 0; 278 i = 0;
247 hole = find_first_zero_bit(read_bitmap, nr_secs); 279 hole = find_first_zero_bit(read_bitmap, nr_secs);
248 do { 280 do {
281 int line_id = pblk_dev_ppa_to_line(rqd->ppa_list[i]);
282 struct pblk_line *line = &pblk->lines[line_id];
283
284 kref_put(&line->ref, pblk_line_put);
285
249 meta_list[hole].lba = lba_list_media[i]; 286 meta_list[hole].lba = lba_list_media[i];
250 287
251 src_bv = new_bio->bi_io_vec[i++]; 288 src_bv = new_bio->bi_io_vec[i++];
@@ -269,19 +306,17 @@ static int pblk_fill_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd,
269 bio_put(new_bio); 306 bio_put(new_bio);
270 307
271 /* Complete the original bio and associated request */ 308 /* Complete the original bio and associated request */
309 bio_endio(bio);
272 rqd->bio = bio; 310 rqd->bio = bio;
273 rqd->nr_ppas = nr_secs; 311 rqd->nr_ppas = nr_secs;
274 rqd->private = pblk;
275 312
276 bio_endio(bio); 313 __pblk_end_io_read(pblk, rqd, false);
277 pblk_end_io_read(rqd);
278 return NVM_IO_OK; 314 return NVM_IO_OK;
279 315
280err: 316err:
281 /* Free allocated pages in new bio */ 317 /* Free allocated pages in new bio */
282 pblk_bio_free_pages(pblk, bio, 0, new_bio->bi_vcnt); 318 pblk_bio_free_pages(pblk, bio, 0, new_bio->bi_vcnt);
283 rqd->private = pblk; 319 __pblk_end_io_read(pblk, rqd, false);
284 pblk_end_io_read(rqd);
285 return NVM_IO_ERR; 320 return NVM_IO_ERR;
286} 321}
287 322
@@ -314,11 +349,11 @@ retry:
314 goto retry; 349 goto retry;
315 } 350 }
316 351
352 WARN_ON(test_and_set_bit(0, read_bitmap));
317 meta_list[0].lba = cpu_to_le64(lba); 353 meta_list[0].lba = cpu_to_le64(lba);
318 354
319 WARN_ON(test_and_set_bit(0, read_bitmap));
320#ifdef CONFIG_NVM_DEBUG 355#ifdef CONFIG_NVM_DEBUG
321 atomic_long_inc(&pblk->cache_reads); 356 atomic_long_inc(&pblk->cache_reads);
322#endif 357#endif
323 } else { 358 } else {
324 rqd->ppa_addr = ppa; 359 rqd->ppa_addr = ppa;
@@ -383,7 +418,7 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio)
383 if (bitmap_full(&read_bitmap, nr_secs)) { 418 if (bitmap_full(&read_bitmap, nr_secs)) {
384 bio_endio(bio); 419 bio_endio(bio);
385 atomic_inc(&pblk->inflight_io); 420 atomic_inc(&pblk->inflight_io);
386 pblk_end_io_read(rqd); 421 __pblk_end_io_read(pblk, rqd, false);
387 return NVM_IO_OK; 422 return NVM_IO_OK;
388 } 423 }
389 424
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index 4a51e6d4d036..e4704373398b 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -636,6 +636,7 @@ struct pblk {
636 636
637 struct workqueue_struct *close_wq; 637 struct workqueue_struct *close_wq;
638 struct workqueue_struct *bb_wq; 638 struct workqueue_struct *bb_wq;
639 struct workqueue_struct *r_end_wq;
639 640
640 struct timer_list wtimer; 641 struct timer_list wtimer;
641 642
@@ -741,6 +742,7 @@ int pblk_line_read_emeta(struct pblk *pblk, struct pblk_line *line,
741 void *emeta_buf); 742 void *emeta_buf);
742int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr erase_ppa); 743int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr erase_ppa);
743void pblk_line_put(struct kref *ref); 744void pblk_line_put(struct kref *ref);
745void pblk_line_put_wq(struct kref *ref);
744struct list_head *pblk_line_gc_list(struct pblk *pblk, struct pblk_line *line); 746struct list_head *pblk_line_gc_list(struct pblk *pblk, struct pblk_line *line);
745u64 pblk_lookup_page(struct pblk *pblk, struct pblk_line *line); 747u64 pblk_lookup_page(struct pblk *pblk, struct pblk_line *line);
746void pblk_dealloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs); 748void pblk_dealloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs);