]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/vfio/vfio.c
Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[karo-tx-linux.git] / drivers / vfio / vfio.c
index e1278fe04b1e7ba16eddbece247c21620b6e8fb7..2fb29dfeffbd7fa70a8a881f025d73ffd50b0b25 100644 (file)
@@ -661,18 +661,29 @@ int vfio_add_group_dev(struct device *dev,
 EXPORT_SYMBOL_GPL(vfio_add_group_dev);
 
 /**
- * Get a reference to the vfio_device for a device that is known to
- * be bound to a vfio driver.  The driver implicitly holds a
- * vfio_device reference between vfio_add_group_dev and
- * vfio_del_group_dev.  We can therefore use drvdata to increment
- * that reference from the struct device.  This additional
- * reference must be released by calling vfio_device_put.
+ * Get a reference to the vfio_device for a device.  Even if the
+ * caller thinks they own the device, they could be racing with a
+ * release call path, so we can't trust drvdata for the shortcut.
+ * Go the long way around, from the iommu_group to the vfio_group
+ * to the vfio_device.
  */
 struct vfio_device *vfio_device_get_from_dev(struct device *dev)
 {
-       struct vfio_device *device = dev_get_drvdata(dev);
+       struct iommu_group *iommu_group;
+       struct vfio_group *group;
+       struct vfio_device *device;
+
+       iommu_group = iommu_group_get(dev);
+       if (!iommu_group)
+               return NULL;
 
-       vfio_device_get(device);
+       group = vfio_group_get_from_iommu(iommu_group);
+       iommu_group_put(iommu_group);
+       if (!group)
+               return NULL;
+
+       device = vfio_group_get_device(group, dev);
+       vfio_group_put(group);
 
        return device;
 }