aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/vfio/vfio.c
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2013-02-14 16:02:13 -0500
committerAlex Williamson <alex.williamson@redhat.com>2013-02-14 16:02:13 -0500
commite014e9444aedc365742d533e1443b22470cc67b9 (patch)
tree5647eca5f1a28297b023fd1a7b9b1c37030de9a6 /drivers/vfio/vfio.c
parent906ee99dd2a5c819c1171ce5eaf6c080c027e58c (diff)
vfio: Protect vfio_dev_present against device_del
vfio_dev_present is meant to give us a wait_event callback so that we can block removing a device from vfio until it becomes unused. The root of this check depends on being able to get the iommu group from the device. Unfortunately if the BUS_NOTIFY_DEL_DEVICE notifier has fired then the device-group reference is no longer searchable and we fail the lookup. We don't need to go to such extents for this though. We have a reference to the device, from which we can acquire a reference to the group. We can then use the group reference to search for the device and properly block removal. Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Diffstat (limited to 'drivers/vfio/vfio.c')
-rw-r--r--drivers/vfio/vfio.c33
1 files changed, 12 insertions, 21 deletions
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index 12c264d3b058..8e6dcecbc407 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -642,33 +642,16 @@ int vfio_add_group_dev(struct device *dev,
642} 642}
643EXPORT_SYMBOL_GPL(vfio_add_group_dev); 643EXPORT_SYMBOL_GPL(vfio_add_group_dev);
644 644
645/* Test whether a struct device is present in our tracking */ 645/* Given a referenced group, check if it contains the device */
646static bool vfio_dev_present(struct device *dev) 646static bool vfio_dev_present(struct vfio_group *group, struct device *dev)
647{ 647{
648 struct iommu_group *iommu_group;
649 struct vfio_group *group;
650 struct vfio_device *device; 648 struct vfio_device *device;
651 649
652 iommu_group = iommu_group_get(dev);
653 if (!iommu_group)
654 return false;
655
656 group = vfio_group_get_from_iommu(iommu_group);
657 if (!group) {
658 iommu_group_put(iommu_group);
659 return false;
660 }
661
662 device = vfio_group_get_device(group, dev); 650 device = vfio_group_get_device(group, dev);
663 if (!device) { 651 if (!device)
664 vfio_group_put(group);
665 iommu_group_put(iommu_group);
666 return false; 652 return false;
667 }
668 653
669 vfio_device_put(device); 654 vfio_device_put(device);
670 vfio_group_put(group);
671 iommu_group_put(iommu_group);
672 return true; 655 return true;
673} 656}
674 657
@@ -682,10 +665,18 @@ void *vfio_del_group_dev(struct device *dev)
682 struct iommu_group *iommu_group = group->iommu_group; 665 struct iommu_group *iommu_group = group->iommu_group;
683 void *device_data = device->device_data; 666 void *device_data = device->device_data;
684 667
668 /*
669 * The group exists so long as we have a device reference. Get
670 * a group reference and use it to scan for the device going away.
671 */
672 vfio_group_get(group);
673
685 vfio_device_put(device); 674 vfio_device_put(device);
686 675
687 /* TODO send a signal to encourage this to be released */ 676 /* TODO send a signal to encourage this to be released */
688 wait_event(vfio.release_q, !vfio_dev_present(dev)); 677 wait_event(vfio.release_q, !vfio_dev_present(group, dev));
678
679 vfio_group_put(group);
689 680
690 iommu_group_put(iommu_group); 681 iommu_group_put(iommu_group);
691 682