NVMe: Short-cut removal on surprise hot-unplug
authorKeith Busch <keith.busch@intel.com>
Thu, 12 May 2016 14:37:14 +0000 (08:37 -0600)
committerJens Axboe <axboe@fb.com>
Tue, 17 May 2016 23:14:21 +0000 (17:14 -0600)
This patch adds a new state that when set has the core automatically
kill request queues prior to removing namespaces.

If PCI device is not present at the time the nvme driver's remove is
called, we can kill all IO queues immediately instead of waiting for
the watchdog thread to do that at its polling interval. This improves
scenarios where multiple hot plug events occur at the same time since
it doesn't block the pci enumeration for as long.

Signed-off-by: Keith Busch <keith.busch@intel.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@fb.com>
drivers/nvme/host/core.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c

index acc05adaa0d4566ac82dd1c18a5e47aa223957ea..beed3940786b12eb293acf3693b8a80e243ae248 100644 (file)
@@ -95,6 +95,15 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                        break;
                }
                break;
+       case NVME_CTRL_DEAD:
+               switch (old_state) {
+               case NVME_CTRL_DELETING:
+                       changed = true;
+                       /* FALLTHRU */
+               default:
+                       break;
+               }
+               break;
        default:
                break;
        }
@@ -1595,6 +1604,15 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
 {
        struct nvme_ns *ns, *next;
 
+       /*
+        * The dead states indicates the controller was not gracefully
+        * disconnected. In that case, we won't be able to flush any data while
+        * removing the namespaces' disks; fail all the queues now to avoid
+        * potentially having to clean up the failed sync later.
+        */
+       if (ctrl->state == NVME_CTRL_DEAD)
+               nvme_kill_queues(ctrl);
+
        mutex_lock(&ctrl->namespaces_mutex);
        list_for_each_entry_safe(ns, next, &ctrl->namespaces, list)
                nvme_ns_remove(ns);
index 114b928738946b9c6c00a00b13651914ffa27d6d..1daa0482de0e70616c4c97c34ad1e572c2ece649 100644 (file)
@@ -72,6 +72,7 @@ enum nvme_ctrl_state {
        NVME_CTRL_LIVE,
        NVME_CTRL_RESETTING,
        NVME_CTRL_DELETING,
+       NVME_CTRL_DEAD,
 };
 
 struct nvme_ctrl {
index 4feaed591e836aca8cef1bf17c5275028a9fbf7d..3bdcf0e34fd6d736444b4d95b36b7f14c34763e0 100644 (file)
@@ -2017,6 +2017,10 @@ static void nvme_remove(struct pci_dev *pdev)
        nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING);
 
        pci_set_drvdata(pdev, NULL);
+
+       if (!pci_device_is_present(pdev))
+               nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DEAD);
+
        flush_work(&dev->reset_work);
        nvme_uninit_ctrl(&dev->ctrl);
        nvme_dev_disable(dev, true);