diff options
-rw-r--r-- | drivers/block/nvme.c | 38 |
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); } |