aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm/core.c
diff options
context:
space:
mode:
authorMatias Bjørling <m@bjorling.me>2016-07-07 03:54:16 -0400
committerJens Axboe <axboe@fb.com>2016-07-07 10:51:52 -0400
commitb76eb20bb0c6f4f9c2e1ad493f73c52817b8aaff (patch)
treeb066ae87ea129c6b01bcab50e24efc8acb3e62b0 /drivers/lightnvm/core.c
parent5e60edb7dcedd6bdcf946ba765f51e8d363d65a8 (diff)
lightnvm: move target mgmt into media mgr
To enable persistent block management to easily control creation and removal of targets, we move target management into the media manager. The LightNVM core continues to maintain which target types are registered, while the media manager now keeps track of its initialized targets. Two new callbacks for the media manager are introduced. create_tgt and remove_tgt. Note that remove_tgt returns 0 on successfully removing a target, and returns 1 if the target was not found. Signed-off-by: Matias Bjørling <m@bjorling.me> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/lightnvm/core.c')
-rw-r--r--drivers/lightnvm/core.c198
1 files changed, 39 insertions, 159 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 0da196f6891b..8afb04cc4d5a 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -18,8 +18,6 @@
18 * 18 *
19 */ 19 */
20 20
21#include <linux/blkdev.h>
22#include <linux/blk-mq.h>
23#include <linux/list.h> 21#include <linux/list.h>
24#include <linux/types.h> 22#include <linux/types.h>
25#include <linux/sem.h> 23#include <linux/sem.h>
@@ -28,42 +26,37 @@
28#include <linux/miscdevice.h> 26#include <linux/miscdevice.h>
29#include <linux/lightnvm.h> 27#include <linux/lightnvm.h>
30#include <linux/sched/sysctl.h> 28#include <linux/sched/sysctl.h>
31#include <uapi/linux/lightnvm.h>
32 29
33static LIST_HEAD(nvm_tgt_types); 30static LIST_HEAD(nvm_tgt_types);
34static LIST_HEAD(nvm_mgrs); 31static LIST_HEAD(nvm_mgrs);
35static LIST_HEAD(nvm_devices); 32static LIST_HEAD(nvm_devices);
36static LIST_HEAD(nvm_targets);
37static DECLARE_RWSEM(nvm_lock); 33static DECLARE_RWSEM(nvm_lock);
38 34
39static struct nvm_target *nvm_find_target(const char *name) 35struct nvm_tgt_type *nvm_find_target_type(const char *name, int lock)
40{ 36{
41 struct nvm_target *tgt; 37 struct nvm_tgt_type *tmp, *tt = NULL;
42 38
43 list_for_each_entry(tgt, &nvm_targets, list) 39 if (lock)
44 if (!strcmp(name, tgt->disk->disk_name)) 40 down_write(&nvm_lock);
45 return tgt;
46 41
47 return NULL; 42 list_for_each_entry(tmp, &nvm_tgt_types, list)
48} 43 if (!strcmp(name, tmp->name)) {
49 44 tt = tmp;
50static struct nvm_tgt_type *nvm_find_target_type(const char *name) 45 break;
51{ 46 }
52 struct nvm_tgt_type *tt;
53
54 list_for_each_entry(tt, &nvm_tgt_types, list)
55 if (!strcmp(name, tt->name))
56 return tt;
57 47
58 return NULL; 48 if (lock)
49 up_write(&nvm_lock);
50 return tt;
59} 51}
52EXPORT_SYMBOL(nvm_find_target_type);
60 53
61int nvm_register_tgt_type(struct nvm_tgt_type *tt) 54int nvm_register_tgt_type(struct nvm_tgt_type *tt)
62{ 55{
63 int ret = 0; 56 int ret = 0;
64 57
65 down_write(&nvm_lock); 58 down_write(&nvm_lock);
66 if (nvm_find_target_type(tt->name)) 59 if (nvm_find_target_type(tt->name, 0))
67 ret = -EEXIST; 60 ret = -EEXIST;
68 else 61 else
69 list_add(&tt->list, &nvm_tgt_types); 62 list_add(&tt->list, &nvm_tgt_types);
@@ -605,42 +598,11 @@ err_fmtype:
605 return ret; 598 return ret;
606} 599}
607 600
608static void nvm_remove_target(struct nvm_target *t)
609{
610 struct nvm_tgt_type *tt = t->type;
611 struct gendisk *tdisk = t->disk;
612 struct request_queue *q = tdisk->queue;
613
614 lockdep_assert_held(&nvm_lock);
615
616 del_gendisk(tdisk);
617 blk_cleanup_queue(q);
618
619 if (tt->exit)
620 tt->exit(tdisk->private_data);
621
622 put_disk(tdisk);
623
624 list_del(&t->list);
625 kfree(t);
626}
627
628static void nvm_free_mgr(struct nvm_dev *dev) 601static void nvm_free_mgr(struct nvm_dev *dev)
629{ 602{
630 struct nvm_target *tgt, *tmp;
631
632 if (!dev->mt) 603 if (!dev->mt)
633 return; 604 return;
634 605
635 down_write(&nvm_lock);
636 list_for_each_entry_safe(tgt, tmp, &nvm_targets, list) {
637 if (tgt->dev != dev)
638 continue;
639
640 nvm_remove_target(tgt);
641 }
642 up_write(&nvm_lock);
643
644 dev->mt->unregister_mgr(dev); 606 dev->mt->unregister_mgr(dev);
645 dev->mt = NULL; 607 dev->mt = NULL;
646} 608}
@@ -787,91 +749,6 @@ void nvm_unregister(char *disk_name)
787} 749}
788EXPORT_SYMBOL(nvm_unregister); 750EXPORT_SYMBOL(nvm_unregister);
789 751
790static const struct block_device_operations nvm_fops = {
791 .owner = THIS_MODULE,
792};
793
794static int nvm_create_target(struct nvm_dev *dev,
795 struct nvm_ioctl_create *create)
796{
797 struct nvm_ioctl_create_simple *s = &create->conf.s;
798 struct request_queue *tqueue;
799 struct gendisk *tdisk;
800 struct nvm_tgt_type *tt;
801 struct nvm_target *t;
802 void *targetdata;
803
804 if (!dev->mt) {
805 pr_info("nvm: device has no media manager registered.\n");
806 return -ENODEV;
807 }
808
809 down_write(&nvm_lock);
810 tt = nvm_find_target_type(create->tgttype);
811 if (!tt) {
812 pr_err("nvm: target type %s not found\n", create->tgttype);
813 up_write(&nvm_lock);
814 return -EINVAL;
815 }
816
817 t = nvm_find_target(create->tgtname);
818 if (t) {
819 pr_err("nvm: target name already exists.\n");
820 up_write(&nvm_lock);
821 return -EINVAL;
822 }
823 up_write(&nvm_lock);
824
825 t = kmalloc(sizeof(struct nvm_target), GFP_KERNEL);
826 if (!t)
827 return -ENOMEM;
828
829 tqueue = blk_alloc_queue_node(GFP_KERNEL, dev->q->node);
830 if (!tqueue)
831 goto err_t;
832 blk_queue_make_request(tqueue, tt->make_rq);
833
834 tdisk = alloc_disk(0);
835 if (!tdisk)
836 goto err_queue;
837
838 sprintf(tdisk->disk_name, "%s", create->tgtname);
839 tdisk->flags = GENHD_FL_EXT_DEVT;
840 tdisk->major = 0;
841 tdisk->first_minor = 0;
842 tdisk->fops = &nvm_fops;
843 tdisk->queue = tqueue;
844
845 targetdata = tt->init(dev, tdisk, s->lun_begin, s->lun_end);
846 if (IS_ERR(targetdata))
847 goto err_init;
848
849 tdisk->private_data = targetdata;
850 tqueue->queuedata = targetdata;
851
852 blk_queue_max_hw_sectors(tqueue, 8 * dev->ops->max_phys_sect);
853
854 set_capacity(tdisk, tt->capacity(targetdata));
855 add_disk(tdisk);
856
857 t->type = tt;
858 t->disk = tdisk;
859 t->dev = dev;
860
861 down_write(&nvm_lock);
862 list_add_tail(&t->list, &nvm_targets);
863 up_write(&nvm_lock);
864
865 return 0;
866err_init:
867 put_disk(tdisk);
868err_queue:
869 blk_cleanup_queue(tqueue);
870err_t:
871 kfree(t);
872 return -ENOMEM;
873}
874
875static int __nvm_configure_create(struct nvm_ioctl_create *create) 752static int __nvm_configure_create(struct nvm_ioctl_create *create)
876{ 753{
877 struct nvm_dev *dev; 754 struct nvm_dev *dev;
@@ -880,11 +757,17 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
880 down_write(&nvm_lock); 757 down_write(&nvm_lock);
881 dev = nvm_find_nvm_dev(create->dev); 758 dev = nvm_find_nvm_dev(create->dev);
882 up_write(&nvm_lock); 759 up_write(&nvm_lock);
760
883 if (!dev) { 761 if (!dev) {
884 pr_err("nvm: device not found\n"); 762 pr_err("nvm: device not found\n");
885 return -EINVAL; 763 return -EINVAL;
886 } 764 }
887 765
766 if (!dev->mt) {
767 pr_info("nvm: device has no media manager registered.\n");
768 return -ENODEV;
769 }
770
888 if (create->conf.type != NVM_CONFIG_TYPE_SIMPLE) { 771 if (create->conf.type != NVM_CONFIG_TYPE_SIMPLE) {
889 pr_err("nvm: config type not valid\n"); 772 pr_err("nvm: config type not valid\n");
890 return -EINVAL; 773 return -EINVAL;
@@ -897,25 +780,7 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
897 return -EINVAL; 780 return -EINVAL;
898 } 781 }
899 782
900 return nvm_create_target(dev, create); 783 return dev->mt->create_tgt(dev, create);
901}
902
903static int __nvm_configure_remove(struct nvm_ioctl_remove *remove)
904{
905 struct nvm_target *t;
906
907 down_write(&nvm_lock);
908 t = nvm_find_target(remove->tgtname);
909 if (!t) {
910 pr_err("nvm: target \"%s\" doesn't exist.\n", remove->tgtname);
911 up_write(&nvm_lock);
912 return -EINVAL;
913 }
914
915 nvm_remove_target(t);
916 up_write(&nvm_lock);
917
918 return 0;
919} 784}
920 785
921#ifdef CONFIG_NVM_DEBUG 786#ifdef CONFIG_NVM_DEBUG
@@ -950,8 +815,9 @@ static int nvm_configure_show(const char *val)
950static int nvm_configure_remove(const char *val) 815static int nvm_configure_remove(const char *val)
951{ 816{
952 struct nvm_ioctl_remove remove; 817 struct nvm_ioctl_remove remove;
818 struct nvm_dev *dev;
953 char opcode; 819 char opcode;
954 int ret; 820 int ret = 0;
955 821
956 ret = sscanf(val, "%c %256s", &opcode, remove.tgtname); 822 ret = sscanf(val, "%c %256s", &opcode, remove.tgtname);
957 if (ret != 2) { 823 if (ret != 2) {
@@ -961,7 +827,13 @@ static int nvm_configure_remove(const char *val)
961 827
962 remove.flags = 0; 828 remove.flags = 0;
963 829
964 return __nvm_configure_remove(&remove); 830 list_for_each_entry(dev, &nvm_devices, devices) {
831 ret = dev->mt->remove_tgt(dev, &remove);
832 if (!ret)
833 break;
834 }
835
836 return ret;
965} 837}
966 838
967static int nvm_configure_create(const char *val) 839static int nvm_configure_create(const char *val)
@@ -1158,6 +1030,8 @@ static long nvm_ioctl_dev_create(struct file *file, void __user *arg)
1158static long nvm_ioctl_dev_remove(struct file *file, void __user *arg) 1030static long nvm_ioctl_dev_remove(struct file *file, void __user *arg)
1159{ 1031{
1160 struct nvm_ioctl_remove remove; 1032 struct nvm_ioctl_remove remove;
1033 struct nvm_dev *dev;
1034 int ret = 0;
1161 1035
1162 if (!capable(CAP_SYS_ADMIN)) 1036 if (!capable(CAP_SYS_ADMIN))
1163 return -EPERM; 1037 return -EPERM;
@@ -1172,7 +1046,13 @@ static long nvm_ioctl_dev_remove(struct file *file, void __user *arg)
1172 return -EINVAL; 1046 return -EINVAL;
1173 } 1047 }
1174 1048
1175 return __nvm_configure_remove(&remove); 1049 list_for_each_entry(dev, &nvm_devices, devices) {
1050 ret = dev->mt->remove_tgt(dev, &remove);
1051 if (!ret)
1052 break;
1053 }
1054
1055 return ret;
1176} 1056}
1177 1057
1178static void nvm_setup_nvm_sb_info(struct nvm_sb_info *info) 1058static void nvm_setup_nvm_sb_info(struct nvm_sb_info *info)