summaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2014-08-19 19:15:59 -0600
committerJens Axboe <axboe@fb.com>2014-11-04 13:17:09 -0700
commita96d4f5c2da66a0c1537bfd8aaa868b69595476a (patch)
tree59758fc29e667a858e6d072126178ea9d709d7a7 /drivers/block
parent062261be4e39e35bdf2fba16a4b2d8a432ae8281 (diff)
downloadop-kernel-dev-a96d4f5c2da66a0c1537bfd8aaa868b69595476a.zip
op-kernel-dev-a96d4f5c2da66a0c1537bfd8aaa868b69595476a.tar.gz
NVMe: Reference count pci device
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>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/nvme-core.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index c1e3c1a..955b569 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -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);
OpenPOWER on IntegriCloud