[PATCH] nvme: fix doulbe irq free

Tong Zhang ztong0001 at gmail.com
Wed Sep 16 11:37:00 EDT 2020


the irq might already been released before reset work can run

[   81.137630] ------------[ cut here ]------------
[   81.137913] Trying to free already-free IRQ 11
[   81.138145] WARNING: CPU: 1 PID: 7 at kernel/irq/manage.c:1751 free_irq+0x389/0x590
[   81.138525] Modules linked in:
[   81.138681] CPU: 1 PID: 7 Comm: kworker/u4:0 Not tainted 5.9.0-rc4+ #83
[   81.139579] Workqueue: nvme-reset-wq nvme_reset_work
[   81.139828] RIP: 0010:free_irq+0x389/0x590
[   81.140035] Code: 8b 65 50 e8 69 6d 1d 00 48 83 c4 38 4c 89 e0 5b 5d 41 5c 41 5d 41 5e 41 5f c3 8b 74 24 24 48 c7 c7 20 1c 86 8a e8 d7 8e f6 ff <0f0e
[   81.140951] RSP: 0000:ffff88806c06fb18 EFLAGS: 00010082
[   81.141216] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[   81.141569] RDX: 0000000000000001 RSI: 0000000000000004 RDI: ffffed100d80df55
[   81.141924] RBP: ffff88806cac88c0 R08: 0000000000000001 R09: ffffed100d80df29
[   81.142278] R10: 0000000000000003 R11: ffffed100d80df28 R12: ffff88806cac8800
[   81.142632] R13: ffff88806cac8870 R14: ffff88806cac8840 R15: ffff88806cac8960
[   81.142987] FS:  0000000000000000(0000) GS:ffff88806d100000(0000) knlGS:0000000000000000
[   81.143388] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   81.143673] CR2: 0000000000000000 CR3: 0000000026c0e000 CR4: 00000000000006e0
[   81.144028] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   81.144382] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   81.144734] Call Trace:
[   81.144862]  ? nvme_start_ctrl+0x180/0x180
[   81.145072]  pci_free_irq+0x13/0x20
[   81.145248]  nvme_reset_work+0xcf2/0x1ec0
[   81.145451]  ? __update_load_avg_cfs_rq+0x1a3/0x530
[   81.145695]  ? __update_load_avg_cfs_rq+0x4b/0x530
[   81.145935]  ? nvme_remove+0x1e0/0x1e0
[   81.146124]  ? ttwu_queue_wakelist+0x12e/0x150
[   81.146348]  ? try_to_wake_up+0x37c/0x900
[   81.146550]  ? migration_cpu_stop+0x1e0/0x1e0
[   81.146769]  ? __schedule+0x581/0xc40
[   81.146954]  ? read_word_at_a_time+0xe/0x20
[   81.147164]  ? strscpy+0xbf/0x190
[   81.147333]  process_one_work+0x4ad/0x7e0
[   81.147535]  worker_thread+0x73/0x690
[   81.147720]  ? process_one_work+0x7e0/0x7e0
[   81.147930]  kthread+0x199/0x1f0
[   81.148094]  ? kthread_create_on_node+0xd0/0xd0
[   81.148321]  ret_from_fork+0x22/0x30
[   81.148502] ---[ end trace 374ff42ced5b661f ]---

Signed-off-by: Tong Zhang <ztong0001 at gmail.com>
---
 drivers/nvme/host/pci.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 899d2f4d7ab6..c2b083dcfd17 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -2086,6 +2086,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
 	unsigned int nr_io_queues;
 	unsigned long size;
 	int result;
+	int adminq_irq_enabled = test_bit(NVMEQ_ENABLED, &adminq->flags);
 
 	/*
 	 * Sample the module parameters once at reset time so that we have
@@ -2133,14 +2134,16 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
 	adminq->q_db = dev->dbs;
 
  retry:
-	/* Deregister the admin queue's interrupt */
-	pci_free_irq(pdev, 0, adminq);
+	if (adminq_irq_enabled) {
+		/* Deregister the admin queue's interrupt */
+		pci_free_irq(pdev, 0, adminq);
 
-	/*
-	 * If we enable msix early due to not intx, disable it again before
-	 * setting up the full range we need.
-	 */
-	pci_free_irq_vectors(pdev);
+		/*
+		 * If we enable msix early due to not intx, disable it again before
+		 * setting up the full range we need.
+		 */
+		pci_free_irq_vectors(pdev);
+	}
 
 	result = nvme_setup_irqs(dev, nr_io_queues);
 	if (result <= 0)
@@ -2160,6 +2163,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
 	if (result)
 		return result;
 	set_bit(NVMEQ_ENABLED, &adminq->flags);
+	adminq_irq_enabled = 1;
 
 	result = nvme_create_io_queues(dev);
 	if (result || dev->online_queues < 2)
-- 
2.25.1




More information about the Linux-nvme mailing list