summaryrefslogtreecommitdiffstats
path: root/drivers/vfio/vfio_main.c
diff options
context:
space:
mode:
authorJason Gunthorpe <jgg@nvidia.com>2022-09-08 15:44:59 -0300
committerJason Gunthorpe <jgg@nvidia.com>2022-12-05 08:56:01 -0400
commitdcb93d0364a238315dd71f834b199d4b95ae09eb (patch)
treea46678b05e2d1e785f9f26420c112380beaa9aac /drivers/vfio/vfio_main.c
parentf794eec86c7cd9a340a66109e6f32f8659ff30fa (diff)
downloadlinux-dcb93d0364a238315dd71f834b199d4b95ae09eb.tar.bz2
vfio: Move the sanity check of the group to vfio_create_group()
This avoids opening group specific code in __vfio_register_dev() for the sanity check if an (existing) group is not corrupted by having two copies of the same struct device in it. It also simplifies the error unwind for this sanity check since the failure can be detected in the group allocation. This also prepares for moving the group specific code into separate group.c. Grabbed from: https://lore.kernel.org/kvm/20220922152338.2a2238fe.alex.williamson@redhat.com/ Link: https://lore.kernel.org/r/20221201145535.589687-3-yi.l.liu@intel.com Reviewed-by: Kevin Tian <kevin.tian@intel.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Tested-by: Lixiao Yang <lixiao.yang@intel.com> Tested-by: Yu He <yu.he@intel.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Yi Liu <yi.l.liu@intel.com>
Diffstat (limited to 'drivers/vfio/vfio_main.c')
-rw-r--r--drivers/vfio/vfio_main.c62
1 files changed, 25 insertions, 37 deletions
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index f913d862a386..87d9a1670a2f 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -143,7 +143,7 @@ EXPORT_SYMBOL_GPL(vfio_device_set_open_count);
* Group objects - create, release, get, put, search
*/
static struct vfio_group *
-vfio_group_get_from_iommu(struct iommu_group *iommu_group)
+vfio_group_find_from_iommu(struct iommu_group *iommu_group)
{
struct vfio_group *group;
@@ -154,10 +154,8 @@ vfio_group_get_from_iommu(struct iommu_group *iommu_group)
* under the vfio.group_lock.
*/
list_for_each_entry(group, &vfio.group_list, vfio_next) {
- if (group->iommu_group == iommu_group) {
- refcount_inc(&group->drivers);
+ if (group->iommu_group == iommu_group)
return group;
- }
}
return NULL;
}
@@ -307,23 +305,6 @@ static bool vfio_device_try_get_registration(struct vfio_device *device)
return refcount_inc_not_zero(&device->refcount);
}
-static struct vfio_device *vfio_group_get_device(struct vfio_group *group,
- struct device *dev)
-{
- struct vfio_device *device;
-
- mutex_lock(&group->device_lock);
- list_for_each_entry(device, &group->device_list, group_next) {
- if (device->dev == dev &&
- vfio_device_try_get_registration(device)) {
- mutex_unlock(&group->device_lock);
- return device;
- }
- }
- mutex_unlock(&group->device_lock);
- return NULL;
-}
-
/*
* VFIO driver API
*/
@@ -467,6 +448,21 @@ out_put_group:
return ERR_PTR(ret);
}
+static bool vfio_group_has_device(struct vfio_group *group, struct device *dev)
+{
+ struct vfio_device *device;
+
+ mutex_lock(&group->device_lock);
+ list_for_each_entry(device, &group->device_list, group_next) {
+ if (device->dev == dev) {
+ mutex_unlock(&group->device_lock);
+ return true;
+ }
+ }
+ mutex_unlock(&group->device_lock);
+ return false;
+}
+
static struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
{
struct iommu_group *iommu_group;
@@ -502,9 +498,15 @@ static struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
}
mutex_lock(&vfio.group_lock);
- group = vfio_group_get_from_iommu(iommu_group);
- if (!group)
+ group = vfio_group_find_from_iommu(iommu_group);
+ if (group) {
+ if (WARN_ON(vfio_group_has_device(group, dev)))
+ group = ERR_PTR(-EINVAL);
+ else
+ refcount_inc(&group->drivers);
+ } else {
group = vfio_create_group(iommu_group, VFIO_IOMMU);
+ }
mutex_unlock(&vfio.group_lock);
/* The vfio_group holds a reference to the iommu_group */
@@ -515,7 +517,6 @@ static struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
static int __vfio_register_dev(struct vfio_device *device,
struct vfio_group *group)
{
- struct vfio_device *existing_device;
int ret;
/*
@@ -537,19 +538,6 @@ static int __vfio_register_dev(struct vfio_device *device,
if (!device->dev_set)
vfio_assign_device_set(device, device);
- existing_device = vfio_group_get_device(group, device->dev);
- if (existing_device) {
- /*
- * group->iommu_group is non-NULL because we hold the drivers
- * refcount.
- */
- dev_WARN(device->dev, "Device already exists on group %d\n",
- iommu_group_id(group->iommu_group));
- vfio_device_put_registration(existing_device);
- ret = -EBUSY;
- goto err_out;
- }
-
/* Our reference on group is moved to the device */
device->group = group;