[PATCH 4/6 Xenial SRU V2] NVMe: Fix reset/remove race

Tim Gardner tim.gardner at canonical.com
Tue Jul 19 21:36:57 UTC 2016

From: Keith Busch <keith.busch at intel.com>

BugLink: http://bugs.launchpad.net/bugs/1602724

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 at intel.com>
Reviewed-by: Christoph Hellwig <hch at lst.de>
Reviewed-by: Johannes Thumshirn <jthumshirn at suse.de>
Reviewed-by: Sagi Grimberg <sagi at grimberg.me>
Signed-off-by: Jens Axboe <axboe at fb.com>

(cherry picked from commit 9bf2b972afeaffd173fe2ce211ebc555ea7e8a87)
Signed-off-by: Tim Gardner <tim.gardner at canonical.com>
 drivers/nvme/host/pci.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index e338ce2..6621216 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1874,6 +1874,9 @@ static void nvme_reset_work(struct work_struct *work)
 	if (dev->bar)
 		nvme_dev_disable(dev, false);
+	if (test_bit(NVME_CTRL_REMOVING, &dev->flags))
+		goto out;
 	set_bit(NVME_CTRL_RESETTING, &dev->flags);
 	result = nvme_dev_map(dev);
@@ -2077,8 +2080,6 @@ static void nvme_remove(struct pci_dev *pdev)
 	struct nvme_dev *dev = pci_get_drvdata(pdev);
-	del_timer_sync(&dev->watchdog_timer);
 	set_bit(NVME_CTRL_REMOVING, &dev->flags);
 	pci_set_drvdata(pdev, NULL);

More information about the kernel-team mailing list