|
@@ -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;
|
|
|
}
|