summaryrefslogtreecommitdiffstats
path: root/drivers/block/nvme-core.c
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2015-01-08 02:55:49 +0100
committerJens Axboe <axboe@fb.com>2015-01-08 17:00:32 +0100
commitea191d2f36b0f577ce5377c3e72aedc34282969d (patch)
tree27ff7ee0f1971cea41c38a7c3d265a3f4a106263 /drivers/block/nvme-core.c
parentNVMe: Start all requests (diff)
downloadlinux-ea191d2f36b0f577ce5377c3e72aedc34282969d.tar.xz
linux-ea191d2f36b0f577ce5377c3e72aedc34282969d.zip
NVMe: Reference count admin queue usage
Since there is no gendisk associated with the admin queue, the driver needs to hold a reference to it until all open references to the controller are closed. This also combines queue cleanup with freeing the tag set since these should not be separate. Signed-off-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block/nvme-core.c')
-rw-r--r--drivers/block/nvme-core.c28
1 files changed, 14 insertions, 14 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index 286fa4cfc937..beb8d48f8560 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -1369,6 +1369,14 @@ static struct blk_mq_ops nvme_mq_ops = {
.timeout = nvme_timeout,
};
+static void nvme_dev_remove_admin(struct nvme_dev *dev)
+{
+ if (dev->admin_q && !blk_queue_dying(dev->admin_q)) {
+ blk_cleanup_queue(dev->admin_q);
+ blk_mq_free_tag_set(&dev->admin_tagset);
+ }
+}
+
static int nvme_alloc_admin_tags(struct nvme_dev *dev)
{
if (!dev->admin_q) {
@@ -1388,17 +1396,15 @@ static int nvme_alloc_admin_tags(struct nvme_dev *dev)
blk_mq_free_tag_set(&dev->admin_tagset);
return -ENOMEM;
}
+ if (!blk_get_queue(dev->admin_q)) {
+ nvme_dev_remove_admin(dev);
+ return -ENODEV;
+ }
}
return 0;
}
-static void nvme_free_admin_tags(struct nvme_dev *dev)
-{
- if (dev->admin_q)
- blk_mq_free_tag_set(&dev->admin_tagset);
-}
-
static int nvme_configure_admin_queue(struct nvme_dev *dev)
{
int result;
@@ -1465,7 +1471,7 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
return result;
free_tags:
- nvme_free_admin_tags(dev);
+ nvme_dev_remove_admin(dev);
free_nvmeq:
nvme_free_queues(dev, 0);
return result;
@@ -2415,12 +2421,6 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
nvme_dev_unmap(dev);
}
-static void nvme_dev_remove_admin(struct nvme_dev *dev)
-{
- if (dev->admin_q && !blk_queue_dying(dev->admin_q))
- blk_cleanup_queue(dev->admin_q);
-}
-
static void nvme_dev_remove(struct nvme_dev *dev)
{
struct nvme_ns *ns;
@@ -2510,6 +2510,7 @@ static void nvme_free_dev(struct kref *kref)
nvme_free_namespaces(dev);
nvme_release_instance(dev);
blk_mq_free_tag_set(&dev->tagset);
+ blk_put_queue(dev->admin_q);
kfree(dev->queues);
kfree(dev->entry);
kfree(dev);
@@ -2795,7 +2796,6 @@ static void nvme_remove(struct pci_dev *pdev)
nvme_dev_shutdown(dev);
nvme_dev_remove_admin(dev);
nvme_free_queues(dev, 0);
- nvme_free_admin_tags(dev);
nvme_release_prp_pools(dev);
kref_put(&dev->kref, nvme_free_dev);
}