Skip to contentSkip to conversation

blk: Define blk_set_queue_dying in header

PATCH New Keith Busch 2 participants 4 messages Apr 29, 2015 – May 15, 2015

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/2 blk: Define blk_set_queue_dying in header

The 'blk_set_queue_dying()' function is an exported symbol, but it wasn't defined in a header so wasn't usable to other components.

Signed-off-by Keith Busch <keith.busch at intel.com>
---
 include/linux/blkdev.h |    1 +
 1 file changed, 1 insertion(+)
include/linux/blkdev.h +1 -0
index 7f9a516..105a48a 100644
@@ -1000,6 +1000,7 @@ extern struct request_queue *blk_init_queue_node(request_fn_proc *rfn,
 extern struct request_queue *blk_init_queue(request_fn_proc *, spinlock_t *);
 extern struct request_queue *blk_init_allocated_queue(struct request_queue *,
 						      request_fn_proc *, spinlock_t *);
+extern void blk_set_queue_dying(struct request_queue *q);
 extern void blk_cleanup_queue(struct request_queue *);
 extern void blk_queue_make_request(struct request_queue *, make_request_fn *);
 extern void blk_queue_bounce_limit(struct request_queue *, u64);
Signature · 1 line
1.7.10.4
#1 lore raw

PATCH 2/2 NVMe: Kill request queues on dead controllers

This fixes device removal from waiting forever on a h/w queue that isn't available. There are two parts for this:

First, the controller is shutdown after the disks are removed. This allows del_gendisk to sync dirty pages in an orderly removal scenario.

Second, if the nvme controller is incapable of performing IO, kill the request queue prior to deleting gendisks. This prevents del_gendisk from waiting indefinitely to sync dirty pages when there controller is no longer accepting new requests.

Reported-by Sunad Bhandary <sunad.s at samsung.com>
Signed-off-by Keith Busch <keith.busch at intel.com>
---
 drivers/block/nvme-core.c |   20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)
drivers/block/nvme-core.c +17 -3
index 85b8036..77aa061 100644
@@ -2633,17 +2633,31 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
 		nvme_clear_queue(dev->queues[i]);
 }
 
+static inline bool nvme_io_incapable(struct nvme_dev *dev)
+{
+	return (!dev->bar || readl(&dev->bar->csts) == -1 ||
+						dev->online_queues < 2);
+}
+
 static void nvme_dev_remove(struct nvme_dev *dev)
 {
 	struct nvme_ns *ns;
 
+	/*
+	 * If controller is not IO capable, kill request queues prior to
+	 * deleting gendisks to prevent filesystem sync from blocking.
+	 */
+	bool kill = nvme_io_incapable(dev);
+
 	list_for_each_entry(ns, &dev->namespaces, list) {
+		if (kill && !blk_queue_dying(ns->queue))
+			blk_set_queue_dying(ns->queue);
 		if (ns->disk->flags & GENHD_FL_UP) {
 			if (blk_get_integrity(ns->disk))
 				blk_integrity_unregister(ns->disk);
 			del_gendisk(ns->disk);
 		}
-		if (!blk_queue_dying(ns->queue)) {
+		if (kill || !blk_queue_dying(ns->queue)) {
 			blk_mq_abort_requeue_list(ns->queue);
 			blk_cleanup_queue(ns->queue);
 		}
@@ -2879,8 +2893,8 @@ static void nvme_remove_disks(struct work_struct *ws)
 {
 	struct nvme_dev *dev = container_of(ws, struct nvme_dev, reset_work);
 
-	nvme_free_queues(dev, 1);
 	nvme_dev_remove(dev);
+	nvme_free_queues(dev, 1);
 }
 
 static int nvme_dev_resume(struct nvme_dev *dev)
@@ -3042,8 +3056,8 @@ static void nvme_remove(struct pci_dev *pdev)
 	pci_set_drvdata(pdev, NULL);
 	flush_work(&dev->probe_work);
 	flush_work(&dev->reset_work);
-	nvme_dev_shutdown(dev);
 	nvme_dev_remove(dev);
+	nvme_dev_shutdown(dev);
 	nvme_dev_remove_admin(dev);
 	device_destroy(nvme_class, MKDEV(nvme_char_major, dev->instance));
 	nvme_free_queues(dev, 0);
Signature · 1 line
1.7.10.4
#2 lore raw

PATCH 2/2 NVMe: Kill request queues on dead controllers

Hi,

Any thoughts on this one? Hot plug regressions are very concerning to me. Can we try to get this, or a different fix if there are issues with this, in 4.1?

Quoted 75 lines · Keith Busch

This fixes device removal from waiting forever on a h/w queue that isn't available. There are two parts for this:

First, the controller is shutdown after the disks are removed. This allows del_gendisk to sync dirty pages in an orderly removal scenario.

Second, if the nvme controller is incapable of performing IO, kill the request queue prior to deleting gendisks. This prevents del_gendisk from waiting indefinitely to sync dirty pages when there controller is no longer accepting new requests.

Reported-by Sunad Bhandary <sunad.s at samsung.com>
Signed-off-by Keith Busch <keith.busch at intel.com>

---
drivers/block/nvme-core.c | 20 +++++++++++++++++---

1 file changed, 17 insertions(+), 3 deletions(-)
drivers/block/nvme-core.c +17 -4
index 85b8036..77aa061 100644
@@ -2633,17 +2633,31 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
 		nvme_clear_queue(dev->queues[i]);
 }
 
+static inline bool nvme_io_incapable(struct nvme_dev *dev)
+{
+	return (!dev->bar || readl(&dev->bar->csts) == -1 ||
+						dev->online_queues < 2);
+}
+
 static void nvme_dev_remove(struct nvme_dev *dev)
 {
 	struct nvme_ns *ns;
 
+	/*
+	 * If controller is not IO capable, kill request queues prior to
+	 * deleting gendisks to prevent filesystem sync from blocking.
+	 */
+	bool kill = nvme_io_incapable(dev);
+
 	list_for_each_entry(ns, &dev->namespaces, list) {
+		if (kill && !blk_queue_dying(ns->queue))
+			blk_set_queue_dying(ns->queue);
 		if (ns->disk->flags & GENHD_FL_UP) {
 			if (blk_get_integrity(ns->disk))
 				blk_integrity_unregister(ns->disk);
 			del_gendisk(ns->disk);
 		}
-		if (!blk_queue_dying(ns->queue)) {
+		if (kill || !blk_queue_dying(ns->queue)) {
 			blk_mq_abort_requeue_list(ns->queue);
 			blk_cleanup_queue(ns->queue);
 		}
@@ -2879,8 +2893,8 @@ static void nvme_remove_disks(struct work_struct *ws)
 {
 	struct nvme_dev *dev = container_of(ws, struct nvme_dev, reset_work);
 
-	nvme_free_queues(dev, 1);
 	nvme_dev_remove(dev);
+	nvme_free_queues(dev, 1);
 }
 
 static int nvme_dev_resume(struct nvme_dev *dev)
@@ -3042,8 +3056,8 @@ static void nvme_remove(struct pci_dev *pdev)
 	pci_set_drvdata(pdev, NULL);
 	flush_work(&dev->probe_work);
 	flush_work(&dev->reset_work);
-	nvme_dev_shutdown(dev);
 	nvme_dev_remove(dev);
+	nvme_dev_shutdown(dev);
 	nvme_dev_remove_admin(dev);
 	device_destroy(nvme_class, MKDEV(nvme_char_major, dev->instance));
 	nvme_free_queues(dev, 0);
--
#3 lore raw

PATCH 2/2 NVMe: Kill request queues on dead controllers

Hi Keith,

This patch fixes the hot-remove issue for me.

Thanks and regards,
Sunad

-----Original Message-----
From: Linux-nvme [mailto:[email protected]] On Behalf Of Keith Busch
Sent: Friday, May 15, 2015 12:21 AM
To: Keith Busch
Cc: Jens Axboe; Sunad Bhandary; linux-nvme at lists.infradead.org
Subject: Re: [PATCH 2/2] NVMe: Kill request queues on dead controllers

Hi,

Any thoughts on this one? Hot plug regressions are very concerning to me. Can we try to get this, or a different fix if there are issues with this, in 4.1?

drivers/block/nvme-core.c static void nvme_dev_shutdown(struct nvme_dev

Quoted 22 lines · Keith Busch

This fixes device removal from waiting forever on a h/w queue that isn't available. There are two parts for this:

First, the controller is shutdown after the disks are removed. This allows del_gendisk to sync dirty pages in an orderly removal scenario.

Second, if the nvme controller is incapable of performing IO, kill the request queue prior to deleting gendisks. This prevents del_gendisk from waiting indefinitely to sync dirty pages when there controller is no longer accepting new requests.

Reported-by Sunad Bhandary <sunad.s at samsung.com>
Signed-off-by Keith Busch <keith.busch at intel.com>

---
drivers/block/nvme-core.c | 20 +++++++++++++++++---

1 file changed, 17 insertions(+), 3 deletions(-)
drivers/block/nvme-core.c +0 -0
index 85b8036..77aa061 100644
@@ -2633,17 +2633,31 @@ static void nvme_dev_shutdown(struct nvme_dev

*dev)

Quoted 31 lines
drivers/block/nvme-core.c +14 -1
 		nvme_clear_queue(dev->queues[i]);
 }
 
+static inline bool nvme_io_incapable(struct nvme_dev *dev) {
+	return (!dev->bar || readl(&dev->bar->csts) == -1 ||
+						dev->online_queues < 2);
+}
+
 static void nvme_dev_remove(struct nvme_dev *dev) {
 	struct nvme_ns *ns;
 
+	/*
+	 * If controller is not IO capable, kill request queues prior to
+	 * deleting gendisks to prevent filesystem sync from blocking.
+	 */
+	bool kill = nvme_io_incapable(dev);
+
 	list_for_each_entry(ns, &dev->namespaces, list) {
+		if (kill && !blk_queue_dying(ns->queue))
+			blk_set_queue_dying(ns->queue);
 		if (ns->disk->flags & GENHD_FL_UP) {
 			if (blk_get_integrity(ns->disk))
 				blk_integrity_unregister(ns->disk);
 			del_gendisk(ns->disk);
 		}
-		if (!blk_queue_dying(ns->queue)) {
+		if (kill || !blk_queue_dying(ns->queue)) {
 			blk_mq_abort_requeue_list(ns->queue);
 			blk_cleanup_queue(ns->queue);
 		}

drivers/block/nvme-core.c static void nvme_remove_disks(struct work_struct · line 2894

Quoted 2 lines
drivers/block/nvme-core.c +0 -0
@@ -2879,8 +2893,8 @@ static void nvme_remove_disks(struct work_struct 
 *ws) {
 	struct nvme_dev *dev = container_of(ws, struct nvme_dev,

reset_work);

Quoted 17 lines
drivers/block/nvme-core.c +1 -1
-	nvme_free_queues(dev, 1);
 	nvme_dev_remove(dev);
+	nvme_free_queues(dev, 1);
 }
 

static int nvme_dev_resume(struct nvme_dev *dev) @@ -3042,8 +3056,8 @@ static void nvme_remove(struct pci_dev *pdev)

	pci_set_drvdata(pdev, NULL);
	flush_work(&dev->probe_work);
	flush_work(&dev->reset_work);
drivers/block/nvme-core.c +0 -1
-	nvme_dev_shutdown(dev);
	nvme_dev_remove(dev);
drivers/block/nvme-core.c +1 -0
+	nvme_dev_shutdown(dev);
	nvme_dev_remove_admin(dev);
	device_destroy(nvme_class, MKDEV(nvme_char_major, dev->instance));
	nvme_free_queues(dev, 0);
Quoted 1 line

--

_______________________________________________
Linux-nvme mailing list
Linux-nvme at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme