Linux NVME Driver - Added Single MSI supoort

Busch, Keith keith.busch at intel.com
Thu Jan 24 17:54:08 EST 2013


On Thu, Jan 24, 2013 at 9:40 AM, Ramachandra Rao Gajula wrote:
> -----
> Fixes include:
> 1. Support for single MSI interrupt; if MSI-X fails, then a single MSI
> is enabled.
>  - Old code didn't enable MSI-X for the initial admin queue setup time,
> and later enables it at the time of setting up all the queues.
> The new code enables 1 MSI-X vector for admin queue setup time,
> disables it and later enables all the vectors needed for the number of
> queues at the time of setting up all the queues.; not sure if this code
> is correct for MSI-X and requires some review.

We use the legacy interrupt for the admin queue until we know how many MSI-x vectors we need to allocate. It is used for only one command. It doesn't seem to be worth the trouble to allocate MSI-x for a single command only to bring it down immediately after.

> 2. Free all the queues before deleting thee nvme devices at the time of
> driver unload/shutdown.

What you've done here is introduce a potential use-after-free error. You freed the queue's memory while there are still potentially active gendisks and their request_queues in use that may call the make_request_fn, and the kthread may still use the queue. Maybe we need to move the dev_list remove to after the namespaces are deleted so that the kthread can timeout potentially active IO's while we are deleting the gendisks.

Why do you have a completely different ISR for MSI? You can use the same one to make it a lot easier, and we still need to fall back to legacy in the worst case scenario. This all seems a lot more complicated than it has to be. Maybe do something like this instead?

diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 993c014..cd586e4 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -1458,6 +1458,9 @@ static int __devinit nvme_setup_io_queues(struct nvme_dev *dev)
 			continue;
 		} else {
 			nr_io_queues = 1;
+			result = pci_enable_msi(dev->pci_dev);
+			if (result == 0)
+				dev->entry[0].vector = dev->pci_dev->irq;
 			break;
 		}
 	}
@@ -1721,7 +1724,10 @@ static void __devexit nvme_remove(struct pci_dev *pdev)
 {
 	struct nvme_dev *dev = pci_get_drvdata(pdev);
 	nvme_dev_remove(dev);
-	pci_disable_msix(pdev);
+	if (pdev->msix_enabled)
+		pci_disable_msix(pdev);
+	else if (pdev->msi_enabled)
+		pci_disable_msi(pdev);
 	iounmap(dev->bar);
 	nvme_release_instance(dev);
 	nvme_release_prp_pools(dev)



More information about the Linux-nvme mailing list