[PATCH RFC 3/5] NVMe: Asynchronous device scan support

Santosh Y santoshsy at gmail.com
Fri Mar 28 10:02:54 EDT 2014


On Mon, Dec 30, 2013 at 7:20 PM, Matthew Wilcox <willy at linux.intel.com> wrote:
> On Mon, Dec 30, 2013 at 03:57:18PM +0530, Santosh Y wrote:
>> This patch provides asynchronous device enumeration
>> capability. The 'probe' need not wait until the namespace scanning is
>> complete.
>
> I'm very interested in having something like this, except I don't think
> it's complete.  You don't seem to handle the cases where the device
> is shut down in the middle of an async scan.  Also, the only piece you
> seem to make async is the calls to add_disk(), which are surely not the
> timeconsuming parts of the scan.  I would think the time consuming parts
> are sending the IDENTIFY commands, which you don't make async.
>

Would you prefer changes in the following patch. Please let me know
your comments.

diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index b59a93a..2f65f89 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -17,6 +17,7 @@
  */

 #include <linux/nvme.h>
+#include <linux/async.h>
 #include <linux/bio.h>
 #include <linux/bitops.h>
 #include <linux/blkdev.h>
@@ -1993,6 +1994,49 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
     return result;
 }

+static void nvme_async_add(void *data, async_cookie_t cookie)
+{
+    struct nvme_dev *dev = (struct nvme_dev *) data;
+    struct pci_dev *pdev = dev->pci_dev;
+    struct nvme_ns *ns;
+    struct nvme_id_ns *id_ns;
+    void *mem;
+    dma_addr_t dma_addr;
+    unsigned i;
+    int res;
+
+    mem = dma_alloc_coherent(&pdev->dev, 8192, &dma_addr, GFP_KERNEL);
+    if (!mem)
+        return;
+
+    id_ns = mem;
+    for (i = 1; i <= dev->nn; i++) {
+        res = nvme_identify(dev, i, 0, dma_addr);
+
+        if (res)
+            continue;
+
+        if (id_ns->ncap == 0)
+            continue;
+
+        res = nvme_get_features(dev, NVME_FEAT_LBA_RANGE, i,
+                    dma_addr + 4096, NULL);
+        if (res)
+            memset(mem + 4096, 0, 4096);
+        ns = nvme_alloc_ns(dev, i, mem, mem + 4096);
+        if (ns)
+            list_add_tail(&ns->list, &dev->namespaces);
+    }
+
+    mutex_lock(&dev->async_mutex);
+    list_for_each_entry(ns, &dev->namespaces, list)
+    add_disk(ns->disk);
+    mutex_unlock(&dev->async_mutex);
+
+    dev->initialized = 1;
+    dma_free_coherent(&pdev->dev, 8192, mem, dma_addr);
+}
+
 /*
  * Return: error value if an error occurred setting up the queues or calling
  * Identify Device.  0 if these succeeded, even if adding some of the
@@ -2003,15 +2047,12 @@ static int nvme_dev_add(struct nvme_dev *dev)
 {
     struct pci_dev *pdev = dev->pci_dev;
     int res;
-    unsigned nn, i;
-    struct nvme_ns *ns;
     struct nvme_id_ctrl *ctrl;
-    struct nvme_id_ns *id_ns;
     void *mem;
     dma_addr_t dma_addr;
     int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12;

-    mem = dma_alloc_coherent(&pdev->dev, 8192, &dma_addr, GFP_KERNEL);
+    mem = dma_alloc_coherent(&pdev->dev, 4096, &dma_addr, GFP_KERNEL);
     if (!mem)
         return -ENOMEM;

@@ -2022,7 +2063,7 @@ static int nvme_dev_add(struct nvme_dev *dev)
     }

     ctrl = mem;
-    nn = le32_to_cpup(&ctrl->nn);
+    dev->nn = le32_to_cpup(&ctrl->nn);
     dev->oncs = le16_to_cpup(&ctrl->oncs);
     dev->abort_limit = ctrl->acl + 1;
     memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn));
@@ -2034,30 +2075,11 @@ static int nvme_dev_add(struct nvme_dev *dev)
             (pdev->device == 0x0953) && ctrl->vs[3])
         dev->stripe_size = 1 << (ctrl->vs[3] + shift);

-    id_ns = mem;
-    for (i = 1; i <= nn; i++) {
-        res = nvme_identify(dev, i, 0, dma_addr);
-        if (res)
-            continue;
-
-        if (id_ns->ncap == 0)
-            continue;
-
-        res = nvme_get_features(dev, NVME_FEAT_LBA_RANGE, i,
-                            dma_addr + 4096, NULL);
-        if (res)
-            memset(mem + 4096, 0, 4096);
-
-        ns = nvme_alloc_ns(dev, i, mem, mem + 4096);
-        if (ns)
-            list_add_tail(&ns->list, &dev->namespaces);
-    }
-    list_for_each_entry(ns, &dev->namespaces, list)
-        add_disk(ns->disk);
+    async_schedule(nvme_async_add, dev);
     res = 0;

  out:
-    dma_free_coherent(&dev->pci_dev->dev, 8192, mem, dma_addr);
+    dma_free_coherent(&pdev->dev, 4096, mem, dma_addr);
     return res;
 }

@@ -2501,6 +2523,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->async_mutex);
     dev->pci_dev = pdev;
     pci_set_drvdata(pdev, dev);
     result = nvme_set_instance(dev);
@@ -2532,7 +2555,6 @@ static int nvme_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
     if (result)
         goto remove;

-    dev->initialized = 1;
     kref_init(&dev->kref);
     return 0;

@@ -2560,6 +2582,7 @@ static void nvme_remove(struct pci_dev *pdev)
     list_del_init(&dev->node);
     spin_unlock(&dev_list_lock);

+    mutex_lock(&dev->async_mutex);
     pci_set_drvdata(pdev, NULL);
     flush_work(&dev->reset_work);
     misc_deregister(&dev->miscdev);
@@ -2569,6 +2592,7 @@ static void nvme_remove(struct pci_dev *pdev)
     nvme_release_instance(dev);
     nvme_release_prp_pools(dev);
     kref_put(&dev->kref, nvme_free_dev);
+    mutex_unlock(&dev->async_mutex);
 }

 /* These functions are yet to be implemented */
@@ -2583,7 +2607,9 @@ static int nvme_suspend(struct device *dev)
     struct pci_dev *pdev = to_pci_dev(dev);
     struct nvme_dev *ndev = pci_get_drvdata(pdev);

+    mutex_lock(&ndev->async_mutex);
     nvme_dev_shutdown(ndev);
+    mutex_unlock(&ndev->async_mutex);
     return 0;
 }

diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 69ae03f..4ada390 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -97,6 +97,8 @@ struct nvme_dev {
     u16 oncs;
     u16 abort_limit;
     u8 initialized;
+    unsigned nn;
+    struct mutex async_mutex;
 };

 /*
-- 
1.8.3.2


-- 
~Santosh



More information about the Linux-nvme mailing list