Commit a7c9e910 authored by Javier González's avatar Javier González Committed by Jens Axboe

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: default avatarJavier González <javier@cnexlabs.com>
Signed-off-by: default avatarMatias Bjørling <mb@lightnvm.io>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 6f9c9607
...@@ -431,7 +431,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create) ...@@ -431,7 +431,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
return 0; return 0;
err_sysfs: err_sysfs:
if (tt->exit) if (tt->exit)
tt->exit(targetdata); tt->exit(targetdata, true);
err_init: err_init:
blk_cleanup_queue(tqueue); blk_cleanup_queue(tqueue);
tdisk->queue = NULL; tdisk->queue = NULL;
...@@ -446,7 +446,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create) ...@@ -446,7 +446,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
return ret; return ret;
} }
static void __nvm_remove_target(struct nvm_target *t) static void __nvm_remove_target(struct nvm_target *t, bool graceful)
{ {
struct nvm_tgt_type *tt = t->type; struct nvm_tgt_type *tt = t->type;
struct gendisk *tdisk = t->disk; struct gendisk *tdisk = t->disk;
...@@ -459,7 +459,7 @@ static void __nvm_remove_target(struct nvm_target *t) ...@@ -459,7 +459,7 @@ static void __nvm_remove_target(struct nvm_target *t)
tt->sysfs_exit(tdisk); tt->sysfs_exit(tdisk);
if (tt->exit) if (tt->exit)
tt->exit(tdisk->private_data); tt->exit(tdisk->private_data, graceful);
nvm_remove_tgt_dev(t->dev, 1); nvm_remove_tgt_dev(t->dev, 1);
put_disk(tdisk); put_disk(tdisk);
...@@ -489,7 +489,7 @@ static int nvm_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove) ...@@ -489,7 +489,7 @@ static int nvm_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove)
mutex_unlock(&dev->mlock); mutex_unlock(&dev->mlock);
return 1; return 1;
} }
__nvm_remove_target(t); __nvm_remove_target(t, true);
mutex_unlock(&dev->mlock); mutex_unlock(&dev->mlock);
return 0; return 0;
...@@ -963,7 +963,7 @@ void nvm_unregister(struct nvm_dev *dev) ...@@ -963,7 +963,7 @@ void nvm_unregister(struct nvm_dev *dev)
list_for_each_entry_safe(t, tmp, &dev->targets, list) { list_for_each_entry_safe(t, tmp, &dev->targets, list) {
if (t->dev->parent != dev) if (t->dev->parent != dev)
continue; continue;
__nvm_remove_target(t); __nvm_remove_target(t, false);
} }
mutex_unlock(&dev->mlock); mutex_unlock(&dev->mlock);
......
...@@ -1461,7 +1461,7 @@ static void pblk_line_close_meta_sync(struct pblk *pblk) ...@@ -1461,7 +1461,7 @@ static void pblk_line_close_meta_sync(struct pblk *pblk)
flush_workqueue(pblk->close_wq); flush_workqueue(pblk->close_wq);
} }
void pblk_pipeline_stop(struct pblk *pblk) void __pblk_pipeline_flush(struct pblk *pblk)
{ {
struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_mgmt *l_mg = &pblk->l_mg;
int ret; int ret;
...@@ -1486,6 +1486,11 @@ void pblk_pipeline_stop(struct pblk *pblk) ...@@ -1486,6 +1486,11 @@ void pblk_pipeline_stop(struct pblk *pblk)
flush_workqueue(pblk->bb_wq); flush_workqueue(pblk->bb_wq);
pblk_line_close_meta_sync(pblk); pblk_line_close_meta_sync(pblk);
}
void __pblk_pipeline_stop(struct pblk *pblk)
{
struct pblk_line_mgmt *l_mg = &pblk->l_mg;
spin_lock(&l_mg->free_lock); spin_lock(&l_mg->free_lock);
pblk->state = PBLK_STATE_STOPPED; pblk->state = PBLK_STATE_STOPPED;
...@@ -1494,6 +1499,12 @@ void pblk_pipeline_stop(struct pblk *pblk) ...@@ -1494,6 +1499,12 @@ void pblk_pipeline_stop(struct pblk *pblk)
spin_unlock(&l_mg->free_lock); spin_unlock(&l_mg->free_lock);
} }
void pblk_pipeline_stop(struct pblk *pblk)
{
__pblk_pipeline_flush(pblk);
__pblk_pipeline_stop(pblk);
}
struct pblk_line *pblk_line_replace_data(struct pblk *pblk) struct pblk_line *pblk_line_replace_data(struct pblk *pblk)
{ {
struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_mgmt *l_mg = &pblk->l_mg;
......
...@@ -649,7 +649,7 @@ int pblk_gc_init(struct pblk *pblk) ...@@ -649,7 +649,7 @@ int pblk_gc_init(struct pblk *pblk)
return ret; return ret;
} }
void pblk_gc_exit(struct pblk *pblk) void pblk_gc_exit(struct pblk *pblk, bool graceful)
{ {
struct pblk_gc *gc = &pblk->gc; struct pblk_gc *gc = &pblk->gc;
...@@ -663,10 +663,12 @@ void pblk_gc_exit(struct pblk *pblk) ...@@ -663,10 +663,12 @@ void pblk_gc_exit(struct pblk *pblk)
if (gc->gc_reader_ts) if (gc->gc_reader_ts)
kthread_stop(gc->gc_reader_ts); kthread_stop(gc->gc_reader_ts);
if (graceful) {
flush_workqueue(gc->gc_reader_wq); flush_workqueue(gc->gc_reader_wq);
destroy_workqueue(gc->gc_reader_wq);
flush_workqueue(gc->gc_line_reader_wq); flush_workqueue(gc->gc_line_reader_wq);
}
destroy_workqueue(gc->gc_reader_wq);
destroy_workqueue(gc->gc_line_reader_wq); destroy_workqueue(gc->gc_line_reader_wq);
if (gc->gc_writer_ts) if (gc->gc_writer_ts)
......
...@@ -1118,23 +1118,25 @@ static void pblk_free(struct pblk *pblk) ...@@ -1118,23 +1118,25 @@ static void pblk_free(struct pblk *pblk)
kfree(pblk); kfree(pblk);
} }
static void pblk_tear_down(struct pblk *pblk) static void pblk_tear_down(struct pblk *pblk, bool graceful)
{ {
pblk_pipeline_stop(pblk); if (graceful)
__pblk_pipeline_flush(pblk);
__pblk_pipeline_stop(pblk);
pblk_writer_stop(pblk); pblk_writer_stop(pblk);
pblk_rb_sync_l2p(&pblk->rwb); pblk_rb_sync_l2p(&pblk->rwb);
pblk_rl_free(&pblk->rl); pblk_rl_free(&pblk->rl);
pr_debug("pblk: consistent tear down\n"); pr_debug("pblk: consistent tear down (graceful:%d)\n", graceful);
} }
static void pblk_exit(void *private) static void pblk_exit(void *private, bool graceful)
{ {
struct pblk *pblk = private; struct pblk *pblk = private;
down_write(&pblk_lock); down_write(&pblk_lock);
pblk_gc_exit(pblk); pblk_gc_exit(pblk, graceful);
pblk_tear_down(pblk); pblk_tear_down(pblk, graceful);
#ifdef CONFIG_NVM_DEBUG #ifdef CONFIG_NVM_DEBUG
pr_info("pblk exit: L2P CRC: %x\n", pblk_l2p_crc(pblk)); pr_info("pblk exit: L2P CRC: %x\n", pblk_l2p_crc(pblk));
......
...@@ -771,6 +771,8 @@ void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line); ...@@ -771,6 +771,8 @@ void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line);
void pblk_line_close(struct pblk *pblk, struct pblk_line *line); void pblk_line_close(struct pblk *pblk, struct pblk_line *line);
void pblk_line_close_ws(struct work_struct *work); void pblk_line_close_ws(struct work_struct *work);
void pblk_pipeline_stop(struct pblk *pblk); void pblk_pipeline_stop(struct pblk *pblk);
void __pblk_pipeline_stop(struct pblk *pblk);
void __pblk_pipeline_flush(struct pblk *pblk);
void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv, void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv,
void (*work)(struct work_struct *), gfp_t gfp_mask, void (*work)(struct work_struct *), gfp_t gfp_mask,
struct workqueue_struct *wq); struct workqueue_struct *wq);
...@@ -864,7 +866,7 @@ int pblk_recov_setup_rq(struct pblk *pblk, struct pblk_c_ctx *c_ctx, ...@@ -864,7 +866,7 @@ int pblk_recov_setup_rq(struct pblk *pblk, struct pblk_c_ctx *c_ctx,
#define PBLK_GC_RSV_LINE 1 /* Reserved lines for GC */ #define PBLK_GC_RSV_LINE 1 /* Reserved lines for GC */
int pblk_gc_init(struct pblk *pblk); int pblk_gc_init(struct pblk *pblk);
void pblk_gc_exit(struct pblk *pblk); void pblk_gc_exit(struct pblk *pblk, bool graceful);
void pblk_gc_should_start(struct pblk *pblk); void pblk_gc_should_start(struct pblk *pblk);
void pblk_gc_should_stop(struct pblk *pblk); void pblk_gc_should_stop(struct pblk *pblk);
void pblk_gc_should_kick(struct pblk *pblk); void pblk_gc_should_kick(struct pblk *pblk);
......
...@@ -489,7 +489,7 @@ typedef blk_qc_t (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *); ...@@ -489,7 +489,7 @@ typedef blk_qc_t (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *);
typedef sector_t (nvm_tgt_capacity_fn)(void *); typedef sector_t (nvm_tgt_capacity_fn)(void *);
typedef void *(nvm_tgt_init_fn)(struct nvm_tgt_dev *, struct gendisk *, typedef void *(nvm_tgt_init_fn)(struct nvm_tgt_dev *, struct gendisk *,
int flags); int flags);
typedef void (nvm_tgt_exit_fn)(void *); typedef void (nvm_tgt_exit_fn)(void *, bool);
typedef int (nvm_tgt_sysfs_init_fn)(struct gendisk *); typedef int (nvm_tgt_sysfs_init_fn)(struct gendisk *);
typedef void (nvm_tgt_sysfs_exit_fn)(struct gendisk *); typedef void (nvm_tgt_sysfs_exit_fn)(struct gendisk *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment