NVMe: IO ending fixes on surprise removal
PATCH 1/1 NVMe: IO ending fixes on surprise removal
This patch fixes a lost request discovered during IO + hot removal.
The driver's pci removal deletes gendisks prior to shutting down the controller to allow dirty data to sync. Dirty data can not be synced on a surprise removal, though, and would potentially block indefinitely.
The driver previously had marked the queue as dying in this scenario to prevent new requests from attempting, however it will still block for requests that already entered the queue. This patch fixes this by quiescing IO first, then aborting the requeued requests before deleting disks.
--- drivers/nvme/host/pci.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
drivers/nvme/host/pci.c +19 -1
@@ -2540,8 +2540,17 @@ static void nvme_ns_remove(struct nvme_ns *ns) {bool kill =nvme_io_incapable (ns->dev) && !blk_queue_dying (ns->queue); -if (kill) +if (kill) {blk_set_queue_dying (ns->queue); + +/* +* The controller was shutdown first if we got here through +* device removal. The shutdown may requeue outstanding +* requests. These need to be aborted immediately so +* del_gendisk doesn't block indefinitely for their completion. +*/ +blk_mq_abort_requeue_list (ns->queue); + }if (ns->disk->flags &GENHD_FL_UP )del_gendisk (ns->disk);if (kill || !blk_queue_dying (ns->queue)) {
@@ -2977,6 +2986,15 @@ static void nvme_dev_remove(struct nvme_dev *dev) {struct nvme_ns *ns, *next; +if (nvme_io_incapable (dev)) { +/* +* If the device is not capable of IO (surprise hot-removal, +* for example), we need to quiesce prior to deleting the +* namespaces. This will end outstanding requests and prevent +* attempts to sync dirty data. +*/ +nvme_dev_shutdown (dev); + }list_for_each_entry_safe (ns, next, &dev->namespaces, list)nvme_ns_remove (ns); }
Signature · 1 line
2.6.2.307.g37023ba
PATCH 1/1 NVMe: IO ending fixes on surprise removal
drivers/nvme/host/pci.c static void nvme_ns_remove(struct nvme_ns *ns) · line 2552
Quoted 12 lines
drivers/nvme/host/pci.c +9
-1-if (kill) +if (kill) {blk_set_queue_dying (ns->queue); + +/* +* The controller was shutdown first if we got here through +* device removal. The shutdown may requeue outstanding +* requests. These need to be aborted immediately so +* del_gendisk doesn't block indefinitely for their completion. +*/ +blk_mq_abort_requeue_list (ns->queue);
Something looks convoluted a bit here.
We abort_requeue_list here and...
drivers/nvme/host/pci.c static void nvme_ns_remove(struct nvme_ns *ns) · line 2556
Quoted 4 lines
drivers/nvme/host/pci.c +1
-0+ }if (ns->disk->flags &GENHD_FL_UP )del_gendisk (ns->disk);if (kill || !blk_queue_dying (ns->queue)) {
Here again?
PATCH 1/1 NVMe: IO ending fixes on surprise removal
Quoted 10 lines · Sagi Grimberg
drivers/nvme/host/pci.c static void nvme_ns_remove(struct nvme_ns *ns) · line 2552
Quoted 6 lines
drivers/nvme/host/pci.c +6
-0+* The controller was shutdown first if we got here through +* device removal. The shutdown may requeue outstanding +* requests. These need to be aborted immediately so +* del_gendisk doesn't block indefinitely for their completion. +*/ +blk_mq_abort_requeue_list (ns->queue);Something looks convoluted a bit here.
Weabort_requeue_listhere and...
Quoted 6 lines
drivers/nvme/host/pci.c static void nvme_ns_remove(struct nvme_ns *ns) · line 2556
Quoted 4 lines
drivers/nvme/host/pci.c +1
-0+ }if (ns->disk->flags &GENHD_FL_UP )del_gendisk (ns->disk);if (kill || !blk_queue_dying (ns->queue)) {Here again?
Correct. It's solving two different problems. The first is to end requeued commands that del_gendisk would wait for, like what happens on a surprise removal with filesystem data syncing. The second is to end requeued commands that blk_cleanup_queue would wait for, like direct and passthrough.
One might wonder why the first requeue list abort doesn't address the second case: we don't execute the path containing the first abort requeue list on an orderly removal to allow filesystem data to sync first.
The whole shutdown and removal sequence is a little different today than when it was originally implemented, so will need to verify if it is even possible to have commands on the requeue list at the second point anymore.
PATCH 1/1 NVMe: IO ending fixes on surprise removal
Quoted 24 lines · Keith Busch
Quoted 10 lines · Sagi Grimberg
drivers/nvme/host/pci.c static void nvme_ns_remove(struct nvme_ns *ns) · line 2552
Quoted 6 lines
drivers/nvme/host/pci.c +6
-0+* The controller was shutdown first if we got here through +* device removal. The shutdown may requeue outstanding +* requests. These need to be aborted immediately so +* del_gendisk doesn't block indefinitely for their completion. +*/ +blk_mq_abort_requeue_list (ns->queue);Something looks convoluted a bit here.
Weabort_requeue_listhere and...Quoted 6 lines
drivers/nvme/host/pci.c static void nvme_ns_remove(struct nvme_ns *ns) · line 2556
Quoted 4 lines
drivers/nvme/host/pci.c +1
-0+ }if (ns->disk->flags &GENHD_FL_UP )del_gendisk (ns->disk);if (kill || !blk_queue_dying (ns->queue)) {Here again?
Correct. It's solving two different problems. The first is to end requeued commands that
del_gendiskwould wait for, like what happens on a surprise removal with filesystem data syncing. The second is to end requeued commands thatblk_cleanup_queuewould wait for, like direct and passthrough.
Quoted 3 lines
One might wonder why the first requeue list abort doesn't address the second case: we don't execute the path containing the first abort requeue list on an orderly removal to allow filesystem data to sync first.
Makes sense, the arrangement is just a bit confusing here.
PATCH 1/1 NVMe: IO ending fixes on surprise removal
In reply to Keith BuschQuoted 6 lines · Keith Busch
This patch fixes a lost request discovered during IO + hot removal.
The driver's pci removal deletes gendisks prior to shutting down the controller to allow dirty data to sync. Dirty data can not be synced on a surprise removal, though, and would potentially block indefinitely.
Quoted 8 lines
The driver previously had marked the queue as dying in this scenario to prevent new requests from attempting, however it will still block for requests that already entered the queue. This patch fixes this by quiescing IO first, then aborting the requeued requests before deleting disks.
Reported-by Sujith Pandel <sujith_pandel at dell.com>Signed-off-by Keith Busch <keith.busch at intel.com>
Tested this patch against linux-4.4-rc4.
I/O terminated successfully everytime and hotplug-removal is clean i.e no remnants of the removed NVMe disk is present.
Thanks and Regards,
Sujith