summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew.r.wilcox@intel.com>2011-05-06 08:45:47 -0400
committerMatthew Wilcox <matthew.r.wilcox@intel.com>2011-11-04 15:53:03 -0400
commit5aff9382ddc8aac6eb0c70ffbb351652d71da69a (patch)
treec8fcc4d065e48b55f8f04d0c7eae858fff2fd1a1
parentfd63e9ceeeae58cfe877c2d49d41c1bf7532303c (diff)
NVMe: Use an IDA to allocate minor numbers
The current approach of using the namespace ID as the minor number doesn't work when there are multiple adapters in the machine. Rather than statically partitioning the number of namespaces between adapters, dynamically allocate minor numbers to namespaces as they are detected. Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
-rw-r--r--drivers/block/nvme.c38
1 files changed, 34 insertions, 4 deletions
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index b285a7e0624d..79012c53ae9c 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -24,6 +24,7 @@
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/genhd.h>
+#include <linux/idr.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -1240,7 +1241,34 @@ static int nvme_kthread(void *data)
return 0;
}
-static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, int index,
+static DEFINE_IDA(nvme_index_ida);
+
+static int nvme_get_ns_idx(void)
+{
+ int index, error;
+
+ do {
+ if (!ida_pre_get(&nvme_index_ida, GFP_KERNEL))
+ return -1;
+
+ spin_lock(&dev_list_lock);
+ error = ida_get_new(&nvme_index_ida, &index);
+ spin_unlock(&dev_list_lock);
+ } while (error == -EAGAIN);
+
+ if (error)
+ index = -1;
+ return index;
+}
+
+static void nvme_put_ns_idx(int index)
+{
+ spin_lock(&dev_list_lock);
+ ida_remove(&nvme_index_ida, index);
+ spin_unlock(&dev_list_lock);
+}
+
+static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, int nsid,
struct nvme_id_ns *id, struct nvme_lba_range_type *rt)
{
struct nvme_ns *ns;
@@ -1265,19 +1293,19 @@ static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, int index,
disk = alloc_disk(NVME_MINORS);
if (!disk)
goto out_free_queue;
- ns->ns_id = index;
+ ns->ns_id = nsid;
ns->disk = disk;
lbaf = id->flbas & 0xf;
ns->lba_shift = id->lbaf[lbaf].ds;
disk->major = nvme_major;
disk->minors = NVME_MINORS;
- disk->first_minor = NVME_MINORS * index;
+ disk->first_minor = NVME_MINORS * nvme_get_ns_idx();
disk->fops = &nvme_fops;
disk->private_data = ns;
disk->queue = ns->queue;
disk->driverfs_dev = &dev->pci_dev->dev;
- sprintf(disk->disk_name, "nvme%dn%d", dev->instance, index);
+ sprintf(disk->disk_name, "nvme%dn%d", dev->instance, nsid);
set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
return ns;
@@ -1291,7 +1319,9 @@ static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, int index,
static void nvme_ns_free(struct nvme_ns *ns)
{
+ int index = ns->disk->first_minor / NVME_MINORS;
put_disk(ns->disk);
+ nvme_put_ns_idx(index);
blk_cleanup_queue(ns->queue);
kfree(ns);
}