@@ -780,6 +780,21 @@ void vfio_device_group_unregister(struct vfio_device *device)
mutex_unlock(&device->group->device_lock);
}
+/*
+ * This shall be used without group lock as group and group->container
+ * should be fixed before group is set to df->group.
+ */
+bool vfio_device_group_uses_container(struct vfio_device_file *df)
+{
+ /*
+ * Use the df->group instead of the df->device->group as no
+ * lock is acquired here.
+ */
+ if (WARN_ON(!df->group))
+ return false;
+ return READ_ONCE(df->group->container);
+}
+
int vfio_device_group_use_iommu(struct vfio_device *device)
{
struct vfio_group *group = device->group;
@@ -95,6 +95,7 @@ int vfio_device_set_group(struct vfio_device *device,
void vfio_device_remove_group(struct vfio_device *device);
void vfio_device_group_register(struct vfio_device *device);
void vfio_device_group_unregister(struct vfio_device *device);
+bool vfio_device_group_uses_container(struct vfio_device_file *df);
int vfio_device_group_use_iommu(struct vfio_device *device);
void vfio_device_group_unuse_iommu(struct vfio_device *device);
void vfio_device_group_close(struct vfio_device_file *df);
@@ -423,16 +423,29 @@ static int vfio_device_first_open(struct vfio_device_file *df)
{
struct vfio_device *device = df->device;
struct iommufd_ctx *iommufd = df->iommufd;
- int ret;
+ int ret = 0;
lockdep_assert_held(&device->dev_set->lock);
if (!try_module_get(device->dev->driver->owner))
return -ENODEV;
+ /*
+ * The handling here depends on what the user is using.
+ *
+ * If user uses iommufd in the group compat mode or the
+ * cdev path, call vfio_iommufd_bind().
+ *
+ * If user uses container in the group legacy mode, call
+ * vfio_device_group_use_iommu().
+ *
+ * If user doesn't use iommufd nor container, this is
+ * the noiommufd mode in the cdev path, nothing needs
+ * to be done here just go ahead to open device.
+ */
if (iommufd)
ret = vfio_iommufd_bind(device, iommufd);
- else
+ else if (vfio_device_group_uses_container(df))
ret = vfio_device_group_use_iommu(device);
if (ret)
goto err_module_put;
@@ -447,7 +460,7 @@ static int vfio_device_first_open(struct vfio_device_file *df)
err_unuse_iommu:
if (iommufd)
vfio_iommufd_unbind(device);
- else
+ else if (vfio_device_group_uses_container(df))
vfio_device_group_unuse_iommu(device);
err_module_put:
module_put(device->dev->driver->owner);
@@ -465,7 +478,7 @@ static void vfio_device_last_close(struct vfio_device_file *df)
device->ops->close_device(device);
if (iommufd)
vfio_iommufd_unbind(device);
- else
+ else if (vfio_device_group_uses_container(df))
vfio_device_group_unuse_iommu(device);
module_put(device->dev->driver->owner);
}
vfio_device_first_open() now covers the below two cases: 1) user uses iommufd (e.g. the group path in iommufd compat mode); 2) user uses container (e.g. the group path in legacy mode); The above two paths have their own noiommu mode support accordingly. The cdev path also uses iommufd, so for the case user provides a valid iommufd, this helper is able to support it. But for noiommu mode, the cdev path just provides a NULL iommufd. So this needs to be able to cover it. As there is no special things to do for the cdev path in noiommu mode, it can be covered by simply differentiate it from the container case. If user is not using iommufd nor container, it is the noiommu mode. Signed-off-by: Yi Liu <yi.l.liu@intel.com> --- drivers/vfio/group.c | 15 +++++++++++++++ drivers/vfio/vfio.h | 1 + drivers/vfio/vfio_main.c | 21 +++++++++++++++++---- 3 files changed, 33 insertions(+), 4 deletions(-)