]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
nvme: synchronize access to ctrl->namespaces
authorAshok Vairavan <ashok.vairavan@oracle.com>
Mon, 10 Oct 2016 19:15:14 +0000 (12:15 -0700)
committerChuck Anderson <chuck.anderson@oracle.com>
Sun, 16 Oct 2016 03:39:02 +0000 (20:39 -0700)
Currently traversal and modification of ctrl->namespaces happens completely
unsynchronized, which can be fixed by the addition of a simple mutex.

Note: nvme_dev_ioctl will be handled in the next patch.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Sagi Grimberg <sagig@mellanox.com>
Acked-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
(cherry picked from commit 69d3b8ac15a5eb938e6a01909f6cc8ae4b5d3a17)

Orabug: 24583236
Signed-off-by: Ashok Vairavan <ashok.vairavan@oracle.com>
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c

index c1f41bf3c0f27b6876edf4923f3783e6b992ba98..8d503dc6269e4519c4b00cabd1a8896d2691b074 100644 (file)
@@ -45,6 +45,7 @@ struct nvme_dev {
        struct msix_entry *entry;
        struct nvme_bar __iomem *bar;
        struct list_head namespaces;
+       struct mutex namespaces_mutex;
        struct kref kref;
        struct device *device;
        struct work_struct reset_work;
index 81606e1de21dca5fc3cbdde92ab7d9912eb9c055..86105ce693c41a1862e20e701adadb434d5d663d 100644 (file)
@@ -2117,6 +2117,8 @@ static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)
        struct gendisk *disk;
        int node = dev_to_node(dev->dev);
 
+       lockdep_assert_held(&dev->namespaces_mutex);
+
        ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node);
        if (!ns)
                return;
@@ -2387,6 +2389,9 @@ static struct nvme_ns *nvme_find_ns(struct nvme_dev *dev, unsigned nsid)
 {
        struct nvme_ns *ns;
 
+       lockdep_assert_held(&dev->namespaces_mutex);
+
+
        list_for_each_entry(ns, &dev->namespaces, list) {
                if (ns->ns_id == nsid)
                        return ns;
@@ -2406,6 +2411,8 @@ static void nvme_ns_remove(struct nvme_ns *ns)
 {
        bool kill = nvme_io_incapable(ns->dev) && !blk_queue_dying(ns->queue);
 
+       lockdep_assert_held(&ns->dev->namespaces_mutex);
+
        if (kill) {
                blk_set_queue_dying(ns->queue);
                /*
@@ -2483,6 +2490,8 @@ static void __nvme_scan_namespaces(struct nvme_dev *dev, unsigned nn)
        struct nvme_ns *ns, *next;
        unsigned i;
 
+       lockdep_assert_held(&dev->namespaces_mutex);
+
        for (i = 1; i <= nn; i++)
                nvme_validate_ns(dev, i);
 
@@ -2500,12 +2509,15 @@ void nvme_scan_namespaces(struct nvme_dev *dev)
        if (nvme_identify_ctrl(dev, &id))
                return;
 
+       mutex_lock(&dev->namespaces_mutex);
+
        nn = le32_to_cpu(id->nn);
        if (!nvme_scan_ns_list(dev, nn))
                goto done;
        __nvme_scan_namespaces(dev, le32_to_cpup(&id->nn));
 done:
        list_sort(NULL, &dev->namespaces, ns_cmp);
+       mutex_unlock(&dev->namespaces_mutex);
        kfree(id);
 }
 
@@ -2839,6 +2851,7 @@ static void nvme_freeze_queues(struct nvme_dev *dev)
 {
        struct nvme_ns *ns;
 
+       mutex_lock(&dev->namespaces_mutex);
        list_for_each_entry(ns, &dev->namespaces, list) {
                blk_mq_freeze_queue_start(ns->queue);
 
@@ -2849,18 +2862,21 @@ static void nvme_freeze_queues(struct nvme_dev *dev)
                blk_mq_cancel_requeue_work(ns->queue);
                blk_mq_stop_hw_queues(ns->queue);
        }
+       mutex_unlock(&dev->namespaces_mutex);
 }
 
 static void nvme_unfreeze_queues(struct nvme_dev *dev)
 {
        struct nvme_ns *ns;
 
+       mutex_lock(&dev->namespaces_mutex);
        list_for_each_entry(ns, &dev->namespaces, list) {
                queue_flag_clear_unlocked(QUEUE_FLAG_STOPPED, ns->queue);
                blk_mq_unfreeze_queue(ns->queue);
                blk_mq_start_stopped_hw_queues(ns->queue, true);
                blk_mq_kick_requeue_list(ns->queue);
        }
+       mutex_unlock(&dev->namespaces_mutex);
 }
 
 static void nvme_dev_shutdown(struct nvme_dev *dev)
@@ -2903,8 +2919,10 @@ static void nvme_dev_remove(struct nvme_dev *dev)
                 */
                nvme_dev_shutdown(dev);
        }
+       mutex_lock(&dev->namespaces_mutex);
        list_for_each_entry_safe(ns, next, &dev->namespaces, list)
                nvme_ns_remove(ns);
+       mutex_unlock(&dev->namespaces_mutex);
 }
 
 static int nvme_setup_prp_pools(struct nvme_dev *dev)
@@ -3239,6 +3257,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto free;
 
        INIT_LIST_HEAD(&dev->namespaces);
+       mutex_init(&dev->namespaces_mutex);
        INIT_WORK(&dev->reset_work, nvme_reset_work);
        dev->dev = get_device(&pdev->dev);
        pci_set_drvdata(pdev, dev);