aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier González <javier@javigon.com>2018-06-01 09:04:24 -0400
committerJens Axboe <axboe@kernel.dk>2018-06-01 09:43:53 -0400
commita7c9e9109ca1142f33b882615cc5fa048e07f3ea (patch)
treed82d1ed53aa6053714b27c2fcd491fc9c32d0c2f
parent6f9c9607d445a05267eb4830e5375535f5a547a2 (diff)
lightnvm: pass flag on graceful teardown to targets
If the namespace is unregistered before the LightNVM target is removed (e.g., on hot unplug) it is too late for the target to store any metadata on the device - any attempt to write to the device will fail. In this case, pass on a "gracefull teardown" flag to the target to let it know when this happens. In the case of pblk, we pad the open line (close all open chunks) to improve data retention. In the event of an ungraceful shutdown, avoid this part and just clean up. 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/core.c10
-rw-r--r--drivers/lightnvm/pblk-core.c13
-rw-r--r--drivers/lightnvm/pblk-gc.c10
-rw-r--r--drivers/lightnvm/pblk-init.c14
-rw-r--r--drivers/lightnvm/pblk.h4
-rw-r--r--include/linux/lightnvm.h2
6 files changed, 35 insertions, 18 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 63171cdce270..60aa7bc5a630 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -431,7 +431,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
431 return 0; 431 return 0;
432err_sysfs: 432err_sysfs:
433 if (tt->exit) 433 if (tt->exit)
434 tt->exit(targetdata); 434 tt->exit(targetdata, true);
435err_init: 435err_init:
436 blk_cleanup_queue(tqueue); 436 blk_cleanup_queue(tqueue);
437 tdisk->queue = NULL; 437 tdisk->queue = NULL;
@@ -446,7 +446,7 @@ err_reserve:
446 return ret; 446 return ret;
447} 447}
448 448
449static void __nvm_remove_target(struct nvm_target *t) 449static void __nvm_remove_target(struct nvm_target *t, bool graceful)
450{ 450{
451 struct nvm_tgt_type *tt = t->type; 451 struct nvm_tgt_type *tt = t->type;
452 struct gendisk *tdisk = t->disk; 452 struct gendisk *tdisk = t->disk;
@@ -459,7 +459,7 @@ static void __nvm_remove_target(struct nvm_target *t)
459 tt->sysfs_exit(tdisk); 459 tt->sysfs_exit(tdisk);
460 460
461 if (tt->exit) 461 if (tt->exit)
462 tt->exit(tdisk->private_data); 462 tt->exit(tdisk->private_data, graceful);
463 463
464 nvm_remove_tgt_dev(t->dev, 1); 464 nvm_remove_tgt_dev(t->dev, 1);
465 put_disk(tdisk); 465 put_disk(tdisk);
@@ -489,7 +489,7 @@ static int nvm_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove)
489 mutex_unlock(&dev->mlock); 489 mutex_unlock(&dev->mlock);
490 return 1; 490 return 1;
491 } 491 }
492 __nvm_remove_target(t); 492 __nvm_remove_target(t, true);
493 mutex_unlock(&dev->mlock); 493 mutex_unlock(&dev->mlock);
494 494
495 return 0; 495 return 0;
@@ -963,7 +963,7 @@ void nvm_unregister(struct nvm_dev *dev)
963 list_for_each_entry_safe(t, tmp, &dev->targets, list) { 963 list_for_each_entry_safe(t, tmp, &dev->targets, list) {
964 if (t->dev->parent != dev) 964 if (t->dev->parent != dev)
965 continue; 965 continue;
966 __nvm_remove_target(t); 966 __nvm_remove_target(t, false);
967 } 967 }
968 mutex_unlock(&dev->mlock); 968 mutex_unlock(&dev->mlock);
969 969
diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 26f3c14ad799..6e6a65b278b9 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -1461,7 +1461,7 @@ static void pblk_line_close_meta_sync(struct pblk *pblk)
1461 flush_workqueue(pblk->close_wq); 1461 flush_workqueue(pblk->close_wq);
1462} 1462}
1463 1463
1464void pblk_pipeline_stop(struct pblk *pblk) 1464void __pblk_pipeline_flush(struct pblk *pblk)
1465{ 1465{
1466 struct pblk_line_mgmt *l_mg = &pblk->l_mg; 1466 struct pblk_line_mgmt *l_mg = &pblk->l_mg;
1467 int ret; 1467 int ret;
@@ -1486,6 +1486,11 @@ void pblk_pipeline_stop(struct pblk *pblk)
1486 1486
1487 flush_workqueue(pblk->bb_wq); 1487 flush_workqueue(pblk->bb_wq);
1488 pblk_line_close_meta_sync(pblk); 1488 pblk_line_close_meta_sync(pblk);
1489}
1490
1491void __pblk_pipeline_stop(struct pblk *pblk)
1492{
1493 struct pblk_line_mgmt *l_mg = &pblk->l_mg;
1489 1494
1490 spin_lock(&l_mg->free_lock); 1495 spin_lock(&l_mg->free_lock);
1491 pblk->state = PBLK_STATE_STOPPED; 1496 pblk->state = PBLK_STATE_STOPPED;
@@ -1494,6 +1499,12 @@ void pblk_pipeline_stop(struct pblk *pblk)
1494 spin_unlock(&l_mg->free_lock); 1499 spin_unlock(&l_mg->free_lock);
1495} 1500}
1496 1501
1502void pblk_pipeline_stop(struct pblk *pblk)
1503{
1504 __pblk_pipeline_flush(pblk);
1505 __pblk_pipeline_stop(pblk);
1506}
1507
1497struct pblk_line *pblk_line_replace_data(struct pblk *pblk) 1508struct pblk_line *pblk_line_replace_data(struct pblk *pblk)
1498{ 1509{
1499 struct pblk_line_mgmt *l_mg = &pblk->l_mg; 1510 struct pblk_line_mgmt *l_mg = &pblk->l_mg;
diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c
index 6851a5c67189..b0cc277bf972 100644
--- a/drivers/lightnvm/pblk-gc.c
+++ b/drivers/lightnvm/pblk-gc.c
@@ -649,7 +649,7 @@ fail_free_main_kthread:
649 return ret; 649 return ret;
650} 650}
651 651
652void pblk_gc_exit(struct pblk *pblk) 652void pblk_gc_exit(struct pblk *pblk, bool graceful)
653{ 653{
654 struct pblk_gc *gc = &pblk->gc; 654 struct pblk_gc *gc = &pblk->gc;
655 655
@@ -663,10 +663,12 @@ void pblk_gc_exit(struct pblk *pblk)
663 if (gc->gc_reader_ts) 663 if (gc->gc_reader_ts)
664 kthread_stop(gc->gc_reader_ts); 664 kthread_stop(gc->gc_reader_ts);
665 665
666 flush_workqueue(gc->gc_reader_wq); 666 if (graceful) {
667 destroy_workqueue(gc->gc_reader_wq); 667 flush_workqueue(gc->gc_reader_wq);
668 flush_workqueue(gc->gc_line_reader_wq);
669 }
668 670
669 flush_workqueue(gc->gc_line_reader_wq); 671 destroy_workqueue(gc->gc_reader_wq);
670 destroy_workqueue(gc->gc_line_reader_wq); 672 destroy_workqueue(gc->gc_line_reader_wq);
671 673
672 if (gc->gc_writer_ts) 674 if (gc->gc_writer_ts)
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 81c103b341bd..f47e95c0e5da 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -1118,23 +1118,25 @@ static void pblk_free(struct pblk *pblk)
1118 kfree(pblk); 1118 kfree(pblk);
1119} 1119}
1120 1120
1121static void pblk_tear_down(struct pblk *pblk) 1121static void pblk_tear_down(struct pblk *pblk, bool graceful)
1122{ 1122{
1123 pblk_pipeline_stop(pblk); 1123 if (graceful)
1124 __pblk_pipeline_flush(pblk);
1125 __pblk_pipeline_stop(pblk);
1124 pblk_writer_stop(pblk); 1126 pblk_writer_stop(pblk);
1125 pblk_rb_sync_l2p(&pblk->rwb); 1127 pblk_rb_sync_l2p(&pblk->rwb);
1126 pblk_rl_free(&pblk->rl); 1128 pblk_rl_free(&pblk->rl);
1127 1129
1128 pr_debug("pblk: consistent tear down\n"); 1130 pr_debug("pblk: consistent tear down (graceful:%d)\n", graceful);
1129} 1131}
1130 1132
1131static void pblk_exit(void *private) 1133static void pblk_exit(void *private, bool graceful)
1132{ 1134{
1133 struct pblk *pblk = private; 1135 struct pblk *pblk = private;
1134 1136
1135 down_write(&pblk_lock); 1137 down_write(&pblk_lock);
1136 pblk_gc_exit(pblk); 1138 pblk_gc_exit(pblk, graceful);
1137 pblk_tear_down(pblk); 1139 pblk_tear_down(pblk, graceful);
1138 1140
1139#ifdef CONFIG_NVM_DEBUG 1141#ifdef CONFIG_NVM_DEBUG
1140 pr_info("pblk exit: L2P CRC: %x\n", pblk_l2p_crc(pblk)); 1142 pr_info("pblk exit: L2P CRC: %x\n", pblk_l2p_crc(pblk));
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index 97c0dd5f4857..2399db1b479a 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -771,6 +771,8 @@ void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line);
771void pblk_line_close(struct pblk *pblk, struct pblk_line *line); 771void pblk_line_close(struct pblk *pblk, struct pblk_line *line);
772void pblk_line_close_ws(struct work_struct *work); 772void pblk_line_close_ws(struct work_struct *work);
773void pblk_pipeline_stop(struct pblk *pblk); 773void pblk_pipeline_stop(struct pblk *pblk);
774void __pblk_pipeline_stop(struct pblk *pblk);
775void __pblk_pipeline_flush(struct pblk *pblk);
774void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv, 776void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv,
775 void (*work)(struct work_struct *), gfp_t gfp_mask, 777 void (*work)(struct work_struct *), gfp_t gfp_mask,
776 struct workqueue_struct *wq); 778 struct workqueue_struct *wq);
@@ -864,7 +866,7 @@ int pblk_recov_setup_rq(struct pblk *pblk, struct pblk_c_ctx *c_ctx,
864#define PBLK_GC_RSV_LINE 1 /* Reserved lines for GC */ 866#define PBLK_GC_RSV_LINE 1 /* Reserved lines for GC */
865 867
866int pblk_gc_init(struct pblk *pblk); 868int pblk_gc_init(struct pblk *pblk);
867void pblk_gc_exit(struct pblk *pblk); 869void pblk_gc_exit(struct pblk *pblk, bool graceful);
868void pblk_gc_should_start(struct pblk *pblk); 870void pblk_gc_should_start(struct pblk *pblk);
869void pblk_gc_should_stop(struct pblk *pblk); 871void pblk_gc_should_stop(struct pblk *pblk);
870void pblk_gc_should_kick(struct pblk *pblk); 872void pblk_gc_should_kick(struct pblk *pblk);
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 6e0859b9d4d2..e9e0d1c7eaf5 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -489,7 +489,7 @@ typedef blk_qc_t (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *);
489typedef sector_t (nvm_tgt_capacity_fn)(void *); 489typedef sector_t (nvm_tgt_capacity_fn)(void *);
490typedef void *(nvm_tgt_init_fn)(struct nvm_tgt_dev *, struct gendisk *, 490typedef void *(nvm_tgt_init_fn)(struct nvm_tgt_dev *, struct gendisk *,
491 int flags); 491 int flags);
492typedef void (nvm_tgt_exit_fn)(void *); 492typedef void (nvm_tgt_exit_fn)(void *, bool);
493typedef int (nvm_tgt_sysfs_init_fn)(struct gendisk *); 493typedef int (nvm_tgt_sysfs_init_fn)(struct gendisk *);
494typedef void (nvm_tgt_sysfs_exit_fn)(struct gendisk *); 494typedef void (nvm_tgt_sysfs_exit_fn)(struct gendisk *);
495 495