aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatias Bjørling <m@bjorling.me>2016-09-16 08:25:07 -0400
committerJens Axboe <axboe@fb.com>2016-09-21 09:56:18 -0400
commitb0b4e09c1ae71c4ec33df0616b830ae050006e9b (patch)
tree67a148740845d77af662b36ec17d88f991c84d72
parentb21d5b301794ae332eaa6e177d71fe8b77d3664c (diff)
lightnvm: control life of nvm_dev in driver
LightNVM compatible device drivers does not have a method to expose LightNVM specific sysfs entries. To enable LightNVM sysfs entries to be exposed, lightnvm device drivers require a struct device to attach it to. To allow both the actual device driver and lightnvm sysfs entries to coexist, the device driver tracks the lifetime of the nvm_dev structure. This patch refactors NVMe and null_blk to handle the lifetime of struct nvm_dev, which eliminates the need for struct gendisk when a lightnvm compatible device is provided. Signed-off-by: Matias Bjørling <m@bjorling.me> Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--drivers/block/null_blk.c22
-rw-r--r--drivers/lightnvm/core.c35
-rw-r--r--drivers/nvme/host/core.c36
-rw-r--r--drivers/nvme/host/lightnvm.c31
-rw-r--r--drivers/nvme/host/nvme.h12
-rw-r--r--include/linux/lightnvm.h15
6 files changed, 83 insertions, 68 deletions
diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c
index 895867a8a783..91e1de898daf 100644
--- a/drivers/block/null_blk.c
+++ b/drivers/block/null_blk.c
@@ -34,6 +34,7 @@ struct nullb {
34 unsigned int index; 34 unsigned int index;
35 struct request_queue *q; 35 struct request_queue *q;
36 struct gendisk *disk; 36 struct gendisk *disk;
37 struct nvm_dev *ndev;
37 struct blk_mq_tag_set tag_set; 38 struct blk_mq_tag_set tag_set;
38 struct hrtimer timer; 39 struct hrtimer timer;
39 unsigned int queue_depth; 40 unsigned int queue_depth;
@@ -550,12 +551,29 @@ static struct nvm_dev_ops null_lnvm_dev_ops = {
550 551
551static int null_nvm_register(struct nullb *nullb) 552static int null_nvm_register(struct nullb *nullb)
552{ 553{
553 return nvm_register(nullb->q, nullb->disk_name, &null_lnvm_dev_ops); 554 struct nvm_dev *dev;
555 int rv;
556
557 dev = nvm_alloc_dev(0);
558 if (!dev)
559 return -ENOMEM;
560
561 dev->q = nullb->q;
562 memcpy(dev->name, nullb->disk_name, DISK_NAME_LEN);
563 dev->ops = &null_lnvm_dev_ops;
564
565 rv = nvm_register(dev);
566 if (rv) {
567 kfree(dev);
568 return rv;
569 }
570 nullb->ndev = dev;
571 return 0;
554} 572}
555 573
556static void null_nvm_unregister(struct nullb *nullb) 574static void null_nvm_unregister(struct nullb *nullb)
557{ 575{
558 nvm_unregister(nullb->disk_name); 576 nvm_unregister(nullb->ndev);
559} 577}
560#else 578#else
561static int null_nvm_register(struct nullb *nullb) 579static int null_nvm_register(struct nullb *nullb)
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 25c5df920326..a99b59d1eb36 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -660,22 +660,15 @@ static void nvm_exit(struct nvm_dev *dev)
660 pr_info("nvm: successfully unloaded\n"); 660 pr_info("nvm: successfully unloaded\n");
661} 661}
662 662
663int nvm_register(struct request_queue *q, char *disk_name, 663struct nvm_dev *nvm_alloc_dev(int node)
664 struct nvm_dev_ops *ops)
665{ 664{
666 struct nvm_dev *dev; 665 return kzalloc_node(sizeof(struct nvm_dev), GFP_KERNEL, node);
667 int ret; 666}
668 667EXPORT_SYMBOL(nvm_alloc_dev);
669 if (!ops->identity)
670 return -EINVAL;
671
672 dev = kzalloc(sizeof(struct nvm_dev), GFP_KERNEL);
673 if (!dev)
674 return -ENOMEM;
675 668
676 dev->q = q; 669int nvm_register(struct nvm_dev *dev)
677 dev->ops = ops; 670{
678 strncpy(dev->name, disk_name, DISK_NAME_LEN); 671 int ret;
679 672
680 ret = nvm_init(dev); 673 ret = nvm_init(dev);
681 if (ret) 674 if (ret)
@@ -714,29 +707,17 @@ int nvm_register(struct request_queue *q, char *disk_name,
714 return 0; 707 return 0;
715err_init: 708err_init:
716 kfree(dev->lun_map); 709 kfree(dev->lun_map);
717 kfree(dev);
718 return ret; 710 return ret;
719} 711}
720EXPORT_SYMBOL(nvm_register); 712EXPORT_SYMBOL(nvm_register);
721 713
722void nvm_unregister(char *disk_name) 714void nvm_unregister(struct nvm_dev *dev)
723{ 715{
724 struct nvm_dev *dev;
725
726 down_write(&nvm_lock); 716 down_write(&nvm_lock);
727 dev = nvm_find_nvm_dev(disk_name);
728 if (!dev) {
729 pr_err("nvm: could not find device %s to unregister\n",
730 disk_name);
731 up_write(&nvm_lock);
732 return;
733 }
734
735 list_del(&dev->devices); 717 list_del(&dev->devices);
736 up_write(&nvm_lock); 718 up_write(&nvm_lock);
737 719
738 nvm_exit(dev); 720 nvm_exit(dev);
739 kfree(dev);
740} 721}
741EXPORT_SYMBOL(nvm_unregister); 722EXPORT_SYMBOL(nvm_unregister);
742 723
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 2c3da3315a02..3c707d83b1da 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -156,12 +156,14 @@ static void nvme_free_ns(struct kref *kref)
156{ 156{
157 struct nvme_ns *ns = container_of(kref, struct nvme_ns, kref); 157 struct nvme_ns *ns = container_of(kref, struct nvme_ns, kref);
158 158
159 if (ns->type == NVME_NS_LIGHTNVM) 159 if (ns->ndev)
160 nvme_nvm_unregister(ns->queue, ns->disk->disk_name); 160 nvme_nvm_unregister(ns);
161 161
162 spin_lock(&dev_list_lock); 162 if (ns->disk) {
163 ns->disk->private_data = NULL; 163 spin_lock(&dev_list_lock);
164 spin_unlock(&dev_list_lock); 164 ns->disk->private_data = NULL;
165 spin_unlock(&dev_list_lock);
166 }
165 167
166 put_disk(ns->disk); 168 put_disk(ns->disk);
167 ida_simple_remove(&ns->ctrl->ns_ida, ns->instance); 169 ida_simple_remove(&ns->ctrl->ns_ida, ns->instance);
@@ -891,8 +893,7 @@ static void nvme_config_discard(struct nvme_ns *ns)
891static int nvme_revalidate_ns(struct nvme_ns *ns, struct nvme_id_ns **id) 893static int nvme_revalidate_ns(struct nvme_ns *ns, struct nvme_id_ns **id)
892{ 894{
893 if (nvme_identify_ns(ns->ctrl, ns->ns_id, id)) { 895 if (nvme_identify_ns(ns->ctrl, ns->ns_id, id)) {
894 dev_warn(disk_to_dev(ns->disk), "%s: Identify failure\n", 896 dev_warn(ns->ctrl->dev, "%s: Identify failure\n", __func__);
895 __func__);
896 return -ENODEV; 897 return -ENODEV;
897 } 898 }
898 899
@@ -1683,18 +1684,11 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
1683 goto out_free_queue; 1684 goto out_free_queue;
1684 1685
1685 if (nvme_nvm_ns_supported(ns, id)) { 1686 if (nvme_nvm_ns_supported(ns, id)) {
1686 if (nvme_nvm_register(ns->queue, disk_name)) { 1687 if (nvme_nvm_register(ns, disk_name, node)) {
1687 dev_warn(ctrl->dev, 1688 dev_warn(ctrl->dev, "%s: LightNVM init failure\n",
1688 "%s: LightNVM init failure\n", __func__); 1689 __func__);
1689 goto out_free_id; 1690 goto out_free_id;
1690 } 1691 }
1691
1692 disk = alloc_disk_node(0, node);
1693 if (!disk)
1694 goto out_free_id;
1695 memcpy(disk->disk_name, disk_name, DISK_NAME_LEN);
1696 ns->disk = disk;
1697 ns->type = NVME_NS_LIGHTNVM;
1698 } else { 1692 } else {
1699 disk = alloc_disk_node(0, node); 1693 disk = alloc_disk_node(0, node);
1700 if (!disk) 1694 if (!disk)
@@ -1718,7 +1712,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
1718 1712
1719 kfree(id); 1713 kfree(id);
1720 1714
1721 if (ns->type == NVME_NS_LIGHTNVM) 1715 if (ns->ndev)
1722 return; 1716 return;
1723 1717
1724 device_add_disk(ctrl->device, ns->disk); 1718 device_add_disk(ctrl->device, ns->disk);
@@ -1742,7 +1736,7 @@ static void nvme_ns_remove(struct nvme_ns *ns)
1742 if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags)) 1736 if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags))
1743 return; 1737 return;
1744 1738
1745 if (ns->disk->flags & GENHD_FL_UP) { 1739 if (ns->disk && ns->disk->flags & GENHD_FL_UP) {
1746 if (blk_get_integrity(ns->disk)) 1740 if (blk_get_integrity(ns->disk))
1747 blk_integrity_unregister(ns->disk); 1741 blk_integrity_unregister(ns->disk);
1748 sysfs_remove_group(&disk_to_dev(ns->disk)->kobj, 1742 sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
@@ -1765,7 +1759,7 @@ static void nvme_validate_ns(struct nvme_ctrl *ctrl, unsigned nsid)
1765 1759
1766 ns = nvme_find_get_ns(ctrl, nsid); 1760 ns = nvme_find_get_ns(ctrl, nsid);
1767 if (ns) { 1761 if (ns) {
1768 if (revalidate_disk(ns->disk)) 1762 if (ns->disk && revalidate_disk(ns->disk))
1769 nvme_ns_remove(ns); 1763 nvme_ns_remove(ns);
1770 nvme_put_ns(ns); 1764 nvme_put_ns(ns);
1771 } else 1765 } else
@@ -2070,7 +2064,7 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl)
2070 * Revalidating a dead namespace sets capacity to 0. This will 2064 * Revalidating a dead namespace sets capacity to 0. This will
2071 * end buffered writers dirtying pages that can't be synced. 2065 * end buffered writers dirtying pages that can't be synced.
2072 */ 2066 */
2073 if (!test_and_set_bit(NVME_NS_DEAD, &ns->flags)) 2067 if (ns->disk && !test_and_set_bit(NVME_NS_DEAD, &ns->flags))
2074 revalidate_disk(ns->disk); 2068 revalidate_disk(ns->disk);
2075 2069
2076 blk_set_queue_dying(ns->queue); 2070 blk_set_queue_dying(ns->queue);
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 7268a7a1a19a..798fcd9f5d1f 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -474,9 +474,8 @@ static inline void nvme_nvm_rqtocmd(struct request *rq, struct nvm_rq *rqd,
474 c->ph_rw.length = cpu_to_le16(rqd->nr_ppas - 1); 474 c->ph_rw.length = cpu_to_le16(rqd->nr_ppas - 1);
475 475
476 if (rqd->opcode == NVM_OP_HBWRITE || rqd->opcode == NVM_OP_HBREAD) 476 if (rqd->opcode == NVM_OP_HBWRITE || rqd->opcode == NVM_OP_HBREAD)
477 /* momentarily hardcode the shift configuration. lba_shift from 477 c->hb_rw.slba = cpu_to_le64(nvme_block_nr(ns,
478 * nvm_dev will be available in a follow-up patch */ 478 rqd->bio->bi_iter.bi_sector));
479 c->hb_rw.slba = cpu_to_le64(rqd->bio->bi_iter.bi_sector >> 3);
480} 479}
481 480
482static void nvme_nvm_end_io(struct request *rq, int error) 481static void nvme_nvm_end_io(struct request *rq, int error)
@@ -593,14 +592,32 @@ static struct nvm_dev_ops nvme_nvm_dev_ops = {
593 .max_phys_sect = 64, 592 .max_phys_sect = 64,
594}; 593};
595 594
596int nvme_nvm_register(struct request_queue *q, char *disk_name) 595int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node)
597{ 596{
598 return nvm_register(q, disk_name, &nvme_nvm_dev_ops); 597 struct request_queue *q = ns->queue;
598 struct nvm_dev *dev;
599 int ret;
600
601 dev = nvm_alloc_dev(node);
602 if (!dev)
603 return -ENOMEM;
604
605 dev->q = q;
606 memcpy(dev->name, disk_name, DISK_NAME_LEN);
607 dev->ops = &nvme_nvm_dev_ops;
608 ns->ndev = dev;
609
610 ret = nvm_register(dev);
611
612 ns->lba_shift = ilog2(dev->sec_size) - 9;
613
614 return ret;
599} 615}
600 616
601void nvme_nvm_unregister(struct request_queue *q, char *disk_name) 617void nvme_nvm_unregister(struct nvme_ns *ns)
602{ 618{
603 nvm_unregister(disk_name); 619 nvm_unregister(ns->ndev);
620 kfree(ns->ndev);
604} 621}
605 622
606/* move to shared place when used in multiple places. */ 623/* move to shared place when used in multiple places. */
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index ab18b78102bf..e0535c14e538 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -18,6 +18,7 @@
18#include <linux/pci.h> 18#include <linux/pci.h>
19#include <linux/kref.h> 19#include <linux/kref.h>
20#include <linux/blk-mq.h> 20#include <linux/blk-mq.h>
21#include <linux/lightnvm.h>
21 22
22enum { 23enum {
23 /* 24 /*
@@ -154,6 +155,7 @@ struct nvme_ns {
154 struct nvme_ctrl *ctrl; 155 struct nvme_ctrl *ctrl;
155 struct request_queue *queue; 156 struct request_queue *queue;
156 struct gendisk *disk; 157 struct gendisk *disk;
158 struct nvm_dev *ndev;
157 struct kref kref; 159 struct kref kref;
158 int instance; 160 int instance;
159 161
@@ -165,7 +167,6 @@ struct nvme_ns {
165 u16 ms; 167 u16 ms;
166 bool ext; 168 bool ext;
167 u8 pi_type; 169 u8 pi_type;
168 int type;
169 unsigned long flags; 170 unsigned long flags;
170 171
171#define NVME_NS_REMOVING 0 172#define NVME_NS_REMOVING 0
@@ -307,15 +308,16 @@ int nvme_sg_get_version_num(int __user *ip);
307 308
308#ifdef CONFIG_NVM 309#ifdef CONFIG_NVM
309int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id); 310int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id);
310int nvme_nvm_register(struct request_queue *q, char *disk_name); 311int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node);
311void nvme_nvm_unregister(struct request_queue *q, char *disk_name); 312void nvme_nvm_unregister(struct nvme_ns *ns);
312#else 313#else
313static inline int nvme_nvm_register(struct request_queue *q, char *disk_name) 314static inline int nvme_nvm_register(struct nvme_ns *ns, char *disk_name,
315 int node)
314{ 316{
315 return 0; 317 return 0;
316} 318}
317 319
318static inline void nvme_nvm_unregister(struct request_queue *q, char *disk_name) {}; 320static inline void nvme_nvm_unregister(struct nvme_ns *ns) {};
319 321
320static inline int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id) 322static inline int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id)
321{ 323{
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index ba78b8306674..5afc2634f332 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -524,9 +524,9 @@ extern struct nvm_block *nvm_get_blk(struct nvm_dev *, struct nvm_lun *,
524 unsigned long); 524 unsigned long);
525extern void nvm_put_blk(struct nvm_dev *, struct nvm_block *); 525extern void nvm_put_blk(struct nvm_dev *, struct nvm_block *);
526 526
527extern int nvm_register(struct request_queue *, char *, 527extern struct nvm_dev *nvm_alloc_dev(int);
528 struct nvm_dev_ops *); 528extern int nvm_register(struct nvm_dev *);
529extern void nvm_unregister(char *); 529extern void nvm_unregister(struct nvm_dev *);
530 530
531void nvm_mark_blk(struct nvm_dev *dev, struct ppa_addr ppa, int type); 531void nvm_mark_blk(struct nvm_dev *dev, struct ppa_addr ppa, int type);
532 532
@@ -575,11 +575,14 @@ extern int nvm_dev_factory(struct nvm_dev *, int flags);
575#else /* CONFIG_NVM */ 575#else /* CONFIG_NVM */
576struct nvm_dev_ops; 576struct nvm_dev_ops;
577 577
578static inline int nvm_register(struct request_queue *q, char *disk_name, 578static inline struct nvm_dev *nvm_alloc_dev(int node)
579 struct nvm_dev_ops *ops) 579{
580 return ERR_PTR(-EINVAL);
581}
582static inline int nvm_register(struct nvm_dev *dev)
580{ 583{
581 return -EINVAL; 584 return -EINVAL;
582} 585}
583static inline void nvm_unregister(char *disk_name) {} 586static inline void nvm_unregister(struct nvm_dev *dev) {}
584#endif /* CONFIG_NVM */ 587#endif /* CONFIG_NVM */
585#endif /* LIGHTNVM.H */ 588#endif /* LIGHTNVM.H */