diff options
author | Matias Bjørling <m@bjorling.me> | 2016-05-06 20:03:17 +0200 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-05-06 12:51:10 -0600 |
commit | 976bdfcae32ea10c2c8c2ecaeb0d85873f634dad (patch) | |
tree | 479ceab3d7330f9acd8d64353ed2c238311171c1 | |
parent | 45bbd0529e5d50aa91a4bb5fffffc5e24df3ef7e (diff) |
lightnvm: remove mgt targets on mgt removal
Targets associated with a device manager are not freed on device
removal. They have to be manually removed before shutdown. Make sure
any outstanding targets are freed upon shutdown.
Signed-off-by: Matias Bjørling <m@bjorling.me>
Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r-- | drivers/lightnvm/core.c | 69 | ||||
-rw-r--r-- | include/linux/lightnvm.h | 1 |
2 files changed, 44 insertions, 26 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 1873a3bc913d..d3af77102e47 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -596,13 +596,52 @@ err_fmtype: return ret; } +static void nvm_remove_target(struct nvm_target *t) +{ + struct nvm_tgt_type *tt = t->type; + struct gendisk *tdisk = t->disk; + struct request_queue *q = tdisk->queue; + + lockdep_assert_held(&nvm_lock); + + del_gendisk(tdisk); + blk_cleanup_queue(q); + + if (tt->exit) + tt->exit(tdisk->private_data); + + put_disk(tdisk); + + list_del(&t->list); + kfree(t); +} + +static void nvm_free_mgr(struct nvm_dev *dev) +{ + struct nvm_target *tgt, *tmp; + + if (!dev->mt) + return; + + down_write(&nvm_lock); + list_for_each_entry_safe(tgt, tmp, &nvm_targets, list) { + if (tgt->dev != dev) + continue; + + nvm_remove_target(tgt); + } + up_write(&nvm_lock); + + dev->mt->unregister_mgr(dev); + dev->mt = NULL; +} + static void nvm_free(struct nvm_dev *dev) { if (!dev) return; - if (dev->mt) - dev->mt->unregister_mgr(dev); + nvm_free_mgr(dev); kfree(dev->lptbl); kfree(dev->lun_map); @@ -808,6 +847,7 @@ static int nvm_create_target(struct nvm_dev *dev, t->type = tt; t->disk = tdisk; + t->dev = dev; down_write(&nvm_lock); list_add_tail(&t->list, &nvm_targets); @@ -823,26 +863,6 @@ err_t: return -ENOMEM; } -static void nvm_remove_target(struct nvm_target *t) -{ - struct nvm_tgt_type *tt = t->type; - struct gendisk *tdisk = t->disk; - struct request_queue *q = tdisk->queue; - - lockdep_assert_held(&nvm_lock); - - del_gendisk(tdisk); - blk_cleanup_queue(q); - - if (tt->exit) - tt->exit(tdisk->private_data); - - put_disk(tdisk); - - list_del(&t->list); - kfree(t); -} - static int __nvm_configure_create(struct nvm_ioctl_create *create) { struct nvm_dev *dev; @@ -1231,10 +1251,7 @@ static long nvm_ioctl_dev_factory(struct file *file, void __user *arg) return -EINVAL; } - if (dev->mt) { - dev->mt->unregister_mgr(dev); - dev->mt = NULL; - } + nvm_free_mgr(dev); if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) return nvm_dev_factory(dev, fact.flags); diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 0e8e01956325..cde31ffe2d62 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -200,6 +200,7 @@ struct nvm_id { struct nvm_target { struct list_head list; + struct nvm_dev *dev; struct nvm_tgt_type *type; struct gendisk *disk; }; |