aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2016-04-08 18:11:02 -0400
committerJens Axboe <axboe@fb.com>2016-04-11 12:00:04 -0400
commit9bf2b972afeaffd173fe2ce211ebc555ea7e8a87 (patch)
tree3ad6e0a0d24a9afff0b3c6cc426e606d8fa75cf6
parentc877ef8ae7b8edaedccad0fc8c23d4d1de7e2480 (diff)
NVMe: Fix reset/remove race
This fixes a scenario where device is present and being reset, but a request to unbind the driver occurs. A previous patch series addressing a device failure removal scenario flushed reset_work after controller disable to unblock reset_work waiting on a completion that wouldn't occur. This isn't safe as-is. The broken scenario can potentially be induced with: modprobe nvme && modprobe -r nvme To fix, the reset work is flushed immediately after setting the controller removing flag, and any subsequent reset will not proceed with controller initialization if the flag is set. The controller status must be polled while active, so the watchdog timer is also left active until the controller is disabled to cleanup requests that may be stuck during namespace removal. [Fixes: ff23a2a15a2117245b4599c1352343c8b8fb4c43] Signed-off-by: Keith Busch <keith.busch@intel.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> Reviewed-by: Sagi Grimberg <sagi@grimberg.me> Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--drivers/nvme/host/pci.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 24ccda303efb..660ec84bc40f 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1859,6 +1859,9 @@ static void nvme_reset_work(struct work_struct *work)
1859 if (dev->ctrl.ctrl_config & NVME_CC_ENABLE) 1859 if (dev->ctrl.ctrl_config & NVME_CC_ENABLE)
1860 nvme_dev_disable(dev, false); 1860 nvme_dev_disable(dev, false);
1861 1861
1862 if (test_bit(NVME_CTRL_REMOVING, &dev->flags))
1863 goto out;
1864
1862 set_bit(NVME_CTRL_RESETTING, &dev->flags); 1865 set_bit(NVME_CTRL_RESETTING, &dev->flags);
1863 1866
1864 result = nvme_pci_enable(dev); 1867 result = nvme_pci_enable(dev);
@@ -2078,11 +2081,10 @@ static void nvme_remove(struct pci_dev *pdev)
2078{ 2081{
2079 struct nvme_dev *dev = pci_get_drvdata(pdev); 2082 struct nvme_dev *dev = pci_get_drvdata(pdev);
2080 2083
2081 del_timer_sync(&dev->watchdog_timer);
2082
2083 set_bit(NVME_CTRL_REMOVING, &dev->flags); 2084 set_bit(NVME_CTRL_REMOVING, &dev->flags);
2084 pci_set_drvdata(pdev, NULL); 2085 pci_set_drvdata(pdev, NULL);
2085 flush_work(&dev->async_work); 2086 flush_work(&dev->async_work);
2087 flush_work(&dev->reset_work);
2086 flush_work(&dev->scan_work); 2088 flush_work(&dev->scan_work);
2087 nvme_remove_namespaces(&dev->ctrl); 2089 nvme_remove_namespaces(&dev->ctrl);
2088 nvme_uninit_ctrl(&dev->ctrl); 2090 nvme_uninit_ctrl(&dev->ctrl);