aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier González <jg@lightnvm.io>2017-06-30 11:56:40 -0400
committerJens Axboe <axboe@kernel.dk>2017-06-30 13:08:18 -0400
commitee8d5c1ad54e48ec44b6ae9cf91144fcab6ebf83 (patch)
treecd5e6be51067d2eb47fa42c031a723644593d94f
parentde54e703a4229e4688eb77b32b1c27861384e22a (diff)
lightnvm: pblk: remove target using async. I/Os
When removing a pblk instance, pad the current line using asynchronous I/O. This reduces the removal time from ~1 minute in the worst case to a couple of seconds. Signed-off-by: Javier González <javier@cnexlabs.com> Signed-off-by: Matias Bjørling <matias@cnexlabs.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--drivers/lightnvm/pblk-core.c5
-rw-r--r--drivers/lightnvm/pblk-init.c9
-rw-r--r--drivers/lightnvm/pblk-rb.c8
-rw-r--r--drivers/lightnvm/pblk-recovery.c163
-rw-r--r--drivers/lightnvm/pblk-write.c2
-rw-r--r--drivers/lightnvm/pblk.h8
6 files changed, 122 insertions, 73 deletions
diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 74b8d9db05e1..e6f42cddc8ec 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -273,9 +273,10 @@ static void pblk_flush_writer(struct pblk *pblk)
273{ 273{
274 pblk_rb_flush(&pblk->rwb); 274 pblk_rb_flush(&pblk->rwb);
275 do { 275 do {
276 if (!pblk_rb_read_count(&pblk->rwb)) 276 if (!pblk_rb_sync_count(&pblk->rwb))
277 break; 277 break;
278 278
279 pblk_write_kick(pblk);
279 schedule(); 280 schedule();
280 } while (1); 281 } while (1);
281} 282}
@@ -1350,6 +1351,7 @@ void pblk_pipeline_stop(struct pblk *pblk)
1350 return; 1351 return;
1351 } 1352 }
1352 1353
1354 flush_workqueue(pblk->bb_wq);
1353 pblk_line_close_meta_sync(pblk); 1355 pblk_line_close_meta_sync(pblk);
1354 1356
1355 spin_lock(&l_mg->free_lock); 1357 spin_lock(&l_mg->free_lock);
@@ -1547,6 +1549,7 @@ void pblk_line_close_meta_sync(struct pblk *pblk)
1547 } 1549 }
1548 1550
1549 pblk_wait_for_meta(pblk); 1551 pblk_wait_for_meta(pblk);
1552 flush_workqueue(pblk->close_wq);
1550} 1553}
1551 1554
1552static void pblk_line_should_sync_meta(struct pblk *pblk) 1555static void pblk_line_should_sync_meta(struct pblk *pblk)
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index b3fc310aa51c..025d8fe52154 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -841,6 +841,15 @@ static int pblk_writer_init(struct pblk *pblk)
841 841
842static void pblk_writer_stop(struct pblk *pblk) 842static void pblk_writer_stop(struct pblk *pblk)
843{ 843{
844 /* The pipeline must be stopped and the write buffer emptied before the
845 * write thread is stopped
846 */
847 WARN(pblk_rb_read_count(&pblk->rwb),
848 "Stopping not fully persisted write buffer\n");
849
850 WARN(pblk_rb_sync_count(&pblk->rwb),
851 "Stopping not fully synced write buffer\n");
852
844 if (pblk->writer_ts) 853 if (pblk->writer_ts)
845 kthread_stop(pblk->writer_ts); 854 kthread_stop(pblk->writer_ts);
846 del_timer(&pblk->wtimer); 855 del_timer(&pblk->wtimer);
diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c
index 2dda874af890..7300be98e831 100644
--- a/drivers/lightnvm/pblk-rb.c
+++ b/drivers/lightnvm/pblk-rb.c
@@ -180,6 +180,14 @@ unsigned int pblk_rb_read_count(struct pblk_rb *rb)
180 return pblk_rb_ring_count(mem, subm, rb->nr_entries); 180 return pblk_rb_ring_count(mem, subm, rb->nr_entries);
181} 181}
182 182
183unsigned int pblk_rb_sync_count(struct pblk_rb *rb)
184{
185 unsigned int mem = READ_ONCE(rb->mem);
186 unsigned int sync = READ_ONCE(rb->sync);
187
188 return pblk_rb_ring_count(mem, sync, rb->nr_entries);
189}
190
183unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int nr_entries) 191unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int nr_entries)
184{ 192{
185 unsigned int subm; 193 unsigned int subm;
diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c
index 6d58659fa3da..0e48d3e4e143 100644
--- a/drivers/lightnvm/pblk-recovery.c
+++ b/drivers/lightnvm/pblk-recovery.c
@@ -327,47 +327,94 @@ next_read_rq:
327 return 0; 327 return 0;
328} 328}
329 329
330static void pblk_recov_complete(struct kref *ref)
331{
332 struct pblk_pad_rq *pad_rq = container_of(ref, struct pblk_pad_rq, ref);
333
334 complete(&pad_rq->wait);
335}
336
337static void pblk_end_io_recov(struct nvm_rq *rqd)
338{
339 struct pblk_pad_rq *pad_rq = rqd->private;
340 struct pblk *pblk = pad_rq->pblk;
341 struct nvm_tgt_dev *dev = pblk->dev;
342
343 kref_put(&pad_rq->ref, pblk_recov_complete);
344 nvm_dev_dma_free(dev->parent, rqd->meta_list, rqd->dma_meta_list);
345 pblk_free_rqd(pblk, rqd, WRITE);
346}
347
330static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line, 348static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line,
331 struct pblk_recov_alloc p, int left_ppas) 349 int left_ppas)
332{ 350{
333 struct nvm_tgt_dev *dev = pblk->dev; 351 struct nvm_tgt_dev *dev = pblk->dev;
334 struct nvm_geo *geo = &dev->geo; 352 struct nvm_geo *geo = &dev->geo;
335 struct ppa_addr *ppa_list; 353 struct ppa_addr *ppa_list;
336 struct pblk_sec_meta *meta_list; 354 struct pblk_sec_meta *meta_list;
355 struct pblk_pad_rq *pad_rq;
337 struct nvm_rq *rqd; 356 struct nvm_rq *rqd;
338 struct bio *bio; 357 struct bio *bio;
339 void *data; 358 void *data;
340 dma_addr_t dma_ppa_list, dma_meta_list; 359 dma_addr_t dma_ppa_list, dma_meta_list;
341 __le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf); 360 __le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf);
342 u64 w_ptr = line->cur_sec; 361 u64 w_ptr = line->cur_sec;
343 int left_line_ppas = line->left_msecs; 362 int left_line_ppas, rq_ppas, rq_len;
344 int rq_ppas, rq_len;
345 int i, j; 363 int i, j;
346 int ret = 0; 364 int ret = 0;
347 DECLARE_COMPLETION_ONSTACK(wait);
348 365
349 ppa_list = p.ppa_list; 366 spin_lock(&line->lock);
350 meta_list = p.meta_list; 367 left_line_ppas = line->left_msecs;
351 rqd = p.rqd; 368 spin_unlock(&line->lock);
352 data = p.data; 369
353 dma_ppa_list = p.dma_ppa_list; 370 pad_rq = kmalloc(sizeof(struct pblk_pad_rq), GFP_KERNEL);
354 dma_meta_list = p.dma_meta_list; 371 if (!pad_rq)
372 return -ENOMEM;
373
374 data = vzalloc(pblk->max_write_pgs * geo->sec_size);
375 if (!data) {
376 ret = -ENOMEM;
377 goto free_rq;
378 }
379
380 pad_rq->pblk = pblk;
381 init_completion(&pad_rq->wait);
382 kref_init(&pad_rq->ref);
355 383
356next_pad_rq: 384next_pad_rq:
357 rq_ppas = pblk_calc_secs(pblk, left_ppas, 0); 385 rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
358 if (!rq_ppas) 386 if (rq_ppas < pblk->min_write_pgs) {
359 rq_ppas = pblk->min_write_pgs; 387 pr_err("pblk: corrupted pad line %d\n", line->id);
388 goto free_rq;
389 }
390
360 rq_len = rq_ppas * geo->sec_size; 391 rq_len = rq_ppas * geo->sec_size;
361 392
393 meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, &dma_meta_list);
394 if (!meta_list) {
395 ret = -ENOMEM;
396 goto free_data;
397 }
398
399 ppa_list = (void *)(meta_list) + pblk_dma_meta_size;
400 dma_ppa_list = dma_meta_list + pblk_dma_meta_size;
401
402 rqd = pblk_alloc_rqd(pblk, WRITE);
403 if (IS_ERR(rqd)) {
404 ret = PTR_ERR(rqd);
405 goto fail_free_meta;
406 }
407 memset(rqd, 0, pblk_w_rq_size);
408
362 bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL); 409 bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
363 if (IS_ERR(bio)) 410 if (IS_ERR(bio)) {
364 return PTR_ERR(bio); 411 ret = PTR_ERR(bio);
412 goto fail_free_rqd;
413 }
365 414
366 bio->bi_iter.bi_sector = 0; /* internal bio */ 415 bio->bi_iter.bi_sector = 0; /* internal bio */
367 bio_set_op_attrs(bio, REQ_OP_WRITE, 0); 416 bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
368 417
369 memset(rqd, 0, pblk_g_rq_size);
370
371 rqd->bio = bio; 418 rqd->bio = bio;
372 rqd->opcode = NVM_OP_PWRITE; 419 rqd->opcode = NVM_OP_PWRITE;
373 rqd->flags = pblk_set_progr_mode(pblk, WRITE); 420 rqd->flags = pblk_set_progr_mode(pblk, WRITE);
@@ -376,8 +423,8 @@ next_pad_rq:
376 rqd->ppa_list = ppa_list; 423 rqd->ppa_list = ppa_list;
377 rqd->dma_ppa_list = dma_ppa_list; 424 rqd->dma_ppa_list = dma_ppa_list;
378 rqd->dma_meta_list = dma_meta_list; 425 rqd->dma_meta_list = dma_meta_list;
379 rqd->end_io = pblk_end_io_sync; 426 rqd->end_io = pblk_end_io_recov;
380 rqd->private = &wait; 427 rqd->private = pad_rq;
381 428
382 for (i = 0; i < rqd->nr_ppas; ) { 429 for (i = 0; i < rqd->nr_ppas; ) {
383 struct ppa_addr ppa; 430 struct ppa_addr ppa;
@@ -405,25 +452,41 @@ next_pad_rq:
405 } 452 }
406 } 453 }
407 454
455 kref_get(&pad_rq->ref);
456
408 ret = pblk_submit_io(pblk, rqd); 457 ret = pblk_submit_io(pblk, rqd);
409 if (ret) { 458 if (ret) {
410 pr_err("pblk: I/O submission failed: %d\n", ret); 459 pr_err("pblk: I/O submission failed: %d\n", ret);
411 return ret; 460 goto free_data;
412 } 461 }
413 462
414 if (!wait_for_completion_io_timeout(&wait,
415 msecs_to_jiffies(PBLK_COMMAND_TIMEOUT_MS))) {
416 pr_err("pblk: L2P recovery write timed out\n");
417 }
418 atomic_dec(&pblk->inflight_io); 463 atomic_dec(&pblk->inflight_io);
419 reinit_completion(&wait);
420 464
421 left_line_ppas -= rq_ppas; 465 left_line_ppas -= rq_ppas;
422 left_ppas -= rq_ppas; 466 left_ppas -= rq_ppas;
423 if (left_ppas > 0 && left_line_ppas) 467 if (left_ppas && left_line_ppas)
424 goto next_pad_rq; 468 goto next_pad_rq;
425 469
426 return 0; 470 kref_put(&pad_rq->ref, pblk_recov_complete);
471
472 if (!wait_for_completion_io_timeout(&pad_rq->wait,
473 msecs_to_jiffies(PBLK_COMMAND_TIMEOUT_MS))) {
474 pr_err("pblk: pad write timed out\n");
475 ret = -ETIME;
476 }
477
478free_rq:
479 kfree(pad_rq);
480free_data:
481 vfree(data);
482 return ret;
483
484fail_free_rqd:
485 pblk_free_rqd(pblk, rqd, WRITE);
486fail_free_meta:
487 nvm_dev_dma_free(dev->parent, meta_list, dma_meta_list);
488 kfree(pad_rq);
489 return ret;
427} 490}
428 491
429/* When this function is called, it means that not all upper pages have been 492/* When this function is called, it means that not all upper pages have been
@@ -555,7 +618,7 @@ next_rq:
555 if (pad_secs > line->left_msecs) 618 if (pad_secs > line->left_msecs)
556 pad_secs = line->left_msecs; 619 pad_secs = line->left_msecs;
557 620
558 ret = pblk_recov_pad_oob(pblk, line, p, pad_secs); 621 ret = pblk_recov_pad_oob(pblk, line, pad_secs);
559 if (ret) 622 if (ret)
560 pr_err("pblk: OOB padding failed (err:%d)\n", ret); 623 pr_err("pblk: OOB padding failed (err:%d)\n", ret);
561 624
@@ -961,64 +1024,22 @@ out:
961 */ 1024 */
962int pblk_recov_pad(struct pblk *pblk) 1025int pblk_recov_pad(struct pblk *pblk)
963{ 1026{
964 struct nvm_tgt_dev *dev = pblk->dev;
965 struct nvm_geo *geo = &dev->geo;
966 struct pblk_line *line; 1027 struct pblk_line *line;
967 struct pblk_line_mgmt *l_mg = &pblk->l_mg; 1028 struct pblk_line_mgmt *l_mg = &pblk->l_mg;
968 struct nvm_rq *rqd;
969 struct pblk_recov_alloc p;
970 struct ppa_addr *ppa_list;
971 struct pblk_sec_meta *meta_list;
972 void *data;
973 int left_msecs; 1029 int left_msecs;
974 int ret = 0; 1030 int ret = 0;
975 dma_addr_t dma_ppa_list, dma_meta_list;
976 1031
977 spin_lock(&l_mg->free_lock); 1032 spin_lock(&l_mg->free_lock);
978 line = l_mg->data_line; 1033 line = l_mg->data_line;
979 left_msecs = line->left_msecs; 1034 left_msecs = line->left_msecs;
980 spin_unlock(&l_mg->free_lock); 1035 spin_unlock(&l_mg->free_lock);
981 1036
982 rqd = pblk_alloc_rqd(pblk, READ); 1037 ret = pblk_recov_pad_oob(pblk, line, left_msecs);
983 if (IS_ERR(rqd))
984 return PTR_ERR(rqd);
985
986 meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, &dma_meta_list);
987 if (!meta_list) {
988 ret = -ENOMEM;
989 goto free_rqd;
990 }
991
992 ppa_list = (void *)(meta_list) + pblk_dma_meta_size;
993 dma_ppa_list = dma_meta_list + pblk_dma_meta_size;
994
995 data = kcalloc(pblk->max_write_pgs, geo->sec_size, GFP_KERNEL);
996 if (!data) {
997 ret = -ENOMEM;
998 goto free_meta_list;
999 }
1000
1001 p.ppa_list = ppa_list;
1002 p.meta_list = meta_list;
1003 p.rqd = rqd;
1004 p.data = data;
1005 p.dma_ppa_list = dma_ppa_list;
1006 p.dma_meta_list = dma_meta_list;
1007
1008 ret = pblk_recov_pad_oob(pblk, line, p, left_msecs);
1009 if (ret) { 1038 if (ret) {
1010 pr_err("pblk: Tear down padding failed (%d)\n", ret); 1039 pr_err("pblk: Tear down padding failed (%d)\n", ret);
1011 goto free_data; 1040 return ret;
1012 } 1041 }
1013 1042
1014 pblk_line_close_meta(pblk, line); 1043 pblk_line_close_meta(pblk, line);
1015
1016free_data:
1017 kfree(data);
1018free_meta_list:
1019 nvm_dev_dma_free(dev->parent, meta_list, dma_meta_list);
1020free_rqd:
1021 pblk_free_rqd(pblk, rqd, READ);
1022
1023 return ret; 1044 return ret;
1024} 1045}
diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c
index 8151bf4bb945..d62a8f4faaf4 100644
--- a/drivers/lightnvm/pblk-write.c
+++ b/drivers/lightnvm/pblk-write.c
@@ -190,7 +190,7 @@ static void pblk_end_io_write_meta(struct nvm_rq *rqd)
190 190
191 if (rqd->error) { 191 if (rqd->error) {
192 pblk_log_write_err(pblk, rqd); 192 pblk_log_write_err(pblk, rqd);
193 pr_err("pblk: metadata I/O failed\n"); 193 pr_err("pblk: metadata I/O failed. Line %d\n", line->id);
194 } 194 }
195#ifdef CONFIG_NVM_DEBUG 195#ifdef CONFIG_NVM_DEBUG
196 else 196 else
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index cdad2c9edbdf..bf5b73fb345f 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -111,6 +111,13 @@ struct pblk_g_ctx {
111 void *private; 111 void *private;
112}; 112};
113 113
114/* Pad context */
115struct pblk_pad_rq {
116 struct pblk *pblk;
117 struct completion wait;
118 struct kref ref;
119};
120
114/* Recovery context */ 121/* Recovery context */
115struct pblk_rec_ctx { 122struct pblk_rec_ctx {
116 struct pblk *pblk; 123 struct pblk *pblk;
@@ -674,6 +681,7 @@ void pblk_rb_sync_end(struct pblk_rb *rb, unsigned long *flags);
674unsigned int pblk_rb_sync_point_count(struct pblk_rb *rb); 681unsigned int pblk_rb_sync_point_count(struct pblk_rb *rb);
675 682
676unsigned int pblk_rb_read_count(struct pblk_rb *rb); 683unsigned int pblk_rb_read_count(struct pblk_rb *rb);
684unsigned int pblk_rb_sync_count(struct pblk_rb *rb);
677unsigned int pblk_rb_wrap_pos(struct pblk_rb *rb, unsigned int pos); 685unsigned int pblk_rb_wrap_pos(struct pblk_rb *rb, unsigned int pos);
678 686
679int pblk_rb_tear_down_check(struct pblk_rb *rb); 687int pblk_rb_tear_down_check(struct pblk_rb *rb);