]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
NVMe: Reference count pci device
authorKeith Busch <keith.busch@intel.com>
Wed, 20 Aug 2014 01:15:59 +0000 (19:15 -0600)
committerJens Axboe <axboe@fb.com>
Tue, 4 Nov 2014 20:17:09 +0000 (13:17 -0700)
If an nvme device is removed but user space has an open reference,
the nvme driver would have been holding an invalid reference to its pci
device. You may get a general protection fault on x86 h/w when the driver
uses that reference in dma_map_sg(), as is done in nvme_map_user_pages()
from the IOCTL interface.

This patch fixes the fault by taking a reference on the pci device and
holding it even after device removal until all opens on the nvme device
are closed.

Signed-off-by: Keith Busch <keith.busch@intel.com>
Reported-by: Nilesh Choudhury <nilesh.choudhury@oracle.com>
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
drivers/block/nvme-core.c

index c1e3c1a101b87ace954db7e247f559ee723322ea..955b5699ff96ba2870c6c38ae35450cd21083338 100644 (file)
@@ -2678,6 +2678,7 @@ static void nvme_free_dev(struct kref *kref)
 {
        struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref);
 
+       pci_dev_put(dev->pci_dev);
        nvme_free_namespaces(dev);
        free_percpu(dev->io_queue);
        kfree(dev->queues);
@@ -2853,11 +2854,11 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        dev->reset_workfn = nvme_reset_failed_dev;
        INIT_WORK(&dev->reset_work, nvme_reset_workfn);
        INIT_WORK(&dev->cpu_work, nvme_cpu_workfn);
-       dev->pci_dev = pdev;
+       dev->pci_dev = pci_dev_get(pdev);
        pci_set_drvdata(pdev, dev);
        result = nvme_set_instance(dev);
        if (result)
-               goto free;
+               goto put_pci;
 
        result = nvme_setup_prp_pools(dev);
        if (result)
@@ -2895,6 +2896,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        nvme_release_prp_pools(dev);
  release:
        nvme_release_instance(dev);
+ put_pci:
+       pci_dev_put(dev->pci_dev);
  free:
        free_percpu(dev->io_queue);
        kfree(dev->queues);