[PATCH] NVMe: Add a character device for each nvme device

Keith Busch keith.busch at intel.com
Fri Jul 27 12:44:18 EDT 2012


Registers a character device for the nvme module and creates character
files as /dev/nvmeN for each nvme device probed, where N is the device
instance. The character devices support nvme admin ioctl commands so
that nvme devices without namespaces can be managed.

Signed-off-by: Keith Busch <keith.busch at intel.com>
---
 drivers/block/nvme.c |   55 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 54 insertions(+), 1 deletions(-)

diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 7bcd882..8a16ac8 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -20,6 +20,7 @@
 #include <linux/bio.h>
 #include <linux/bitops.h>
 #include <linux/blkdev.h>
+#include <linux/cdev.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -45,6 +46,7 @@
 #define SQ_SIZE(depth)		(depth * sizeof(struct nvme_command))
 #define CQ_SIZE(depth)		(depth * sizeof(struct nvme_completion))
 #define NVME_MINORS 64
+#define NVME_MAX_DEVS 1024
 #define NVME_IO_TIMEOUT	(5 * HZ)
 #define ADMIN_TIMEOUT	(60 * HZ)
 
@@ -54,9 +56,13 @@ module_param(nvme_major, int, 0);
 static int use_threaded_interrupts;
 module_param(use_threaded_interrupts, int, 0);
 
+static int nvme_char_major;
+module_param(nvme_char_major, int, 0);
+
 static DEFINE_SPINLOCK(dev_list_lock);
 static LIST_HEAD(dev_list);
 static struct task_struct *nvme_thread;
+static struct class *nvme_char_cl;
 
 /*
  * Represents an NVM Express device.  Each nvme_dev is a PCI function.
@@ -1222,6 +1228,35 @@ static const struct block_device_operations nvme_fops = {
 	.compat_ioctl	= nvme_ioctl,
 };
 
+static long nvme_char_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+	struct nvme_dev *dev;
+	int instance = iminor(f->f_dentry->d_inode);
+
+	spin_lock(&dev_list_lock);
+	list_for_each_entry(dev, &dev_list, node) {
+		if (dev->instance == instance)
+			break;
+	}
+	spin_unlock(&dev_list_lock);
+
+	if (&dev->node == &dev_list)
+		return -ENOTTY;
+	
+	switch (cmd) {
+	case NVME_IOCTL_ADMIN_CMD:
+		return nvme_user_admin_cmd(dev, (void __user *)arg);
+	default:
+		return -ENOTTY;
+	}
+}
+
+static const struct file_operations nvme_char_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= nvme_char_ioctl,
+	.compat_ioctl	= nvme_char_ioctl,
+};
+
 static void nvme_timeout_ios(struct nvme_queue *nvmeq)
 {
 	int depth = nvmeq->q_depth - 1;
@@ -1632,6 +1667,8 @@ static int __devinit nvme_probe(struct pci_dev *pdev,
 	if (result)
 		goto delete;
 
+	device_create(nvme_char_cl, NULL, MKDEV(nvme_char_major, dev->instance),
+						NULL, "nvme%d", dev->instance);
 	return 0;
 
  delete:
@@ -1660,6 +1697,7 @@ static void __devexit nvme_remove(struct pci_dev *pdev)
 {
 	struct nvme_dev *dev = pci_get_drvdata(pdev);
 	nvme_dev_remove(dev);
+	device_destroy(nvme_char_cl, MKDEV(nvme_char_major, dev->instance));
 	pci_disable_msix(pdev);
 	iounmap(dev->bar);
 	nvme_release_instance(dev);
@@ -1721,11 +1759,24 @@ static int __init nvme_init(void)
 	else if (result > 0)
 	    nvme_major = result;
 
+	result = __register_chrdev(nvme_char_major, 0, NVME_MAX_DEVS, "nvme",
+							&nvme_char_fops);
+	if (result < 0)
+		goto unregister_blkdev;
+	else if (result > 0)
+		nvme_char_major = result;
+	nvme_char_cl = class_create(THIS_MODULE, "nvme");
+	if (!nvme_char_cl)
+		goto unregister_chrdev;
 	result = pci_register_driver(&nvme_driver);
 	if (result)
-		goto unregister_blkdev;
+		goto destroy_class;
 	return 0;
 
+ destroy_class:
+	class_destroy(nvme_char_cl);
+ unregister_chrdev:
+	__unregister_chrdev(nvme_char_major, 0, NVME_MAX_DEVS, "nvme");
  unregister_blkdev:
 	unregister_blkdev(nvme_major, "nvme");
  kill_kthread:
@@ -1736,6 +1787,8 @@ static int __init nvme_init(void)
 static void __exit nvme_exit(void)
 {
 	pci_unregister_driver(&nvme_driver);
+	class_destroy(nvme_char_cl);
+	__unregister_chrdev(nvme_char_major, 0, NVME_MAX_DEVS, "nvme");
 	unregister_blkdev(nvme_major, "nvme");
 	kthread_stop(nvme_thread);
 }
-- 
1.7.0.4




More information about the Linux-nvme mailing list