vfio: Use IOMMU_CAP_ENFORCE_CACHE_COHERENCY for vfio_file_enforced_coherent()
authorJason Gunthorpe <jgg@nvidia.com>
Tue, 29 Nov 2022 20:31:49 +0000 (16:31 -0400)
committerJason Gunthorpe <jgg@nvidia.com>
Fri, 2 Dec 2022 15:52:03 +0000 (11:52 -0400)
iommufd doesn't establish the iommu_domains until after the device FD is
opened, even if the container has been set. This design is part of moving
away from the group centric iommu APIs.

This is fine, except that the normal sequence of establishing the kvm
wbinvd won't work:

   group = open("/dev/vfio/XX")
   ioctl(group, VFIO_GROUP_SET_CONTAINER)
   ioctl(kvm, KVM_DEV_VFIO_GROUP_ADD)
   ioctl(group, VFIO_GROUP_GET_DEVICE_FD)

As the domains don't start existing until GET_DEVICE_FD. Further,
GET_DEVICE_FD requires that KVM_DEV_VFIO_GROUP_ADD already be done as that
is what sets the group->kvm and thus device->kvm for the driver to use
during open.

Now that we have device centric cap ops and the new
IOMMU_CAP_ENFORCE_CACHE_COHERENCY we know what the iommu_domain will be
capable of without having to create it. Use this to compute
vfio_file_enforced_coherent() and resolve the ordering problems.

VFIO always tries to upgrade domains to enforce cache coherency, it never
attaches a device that supports enforce cache coherency to a less capable
domain, so the cap test is a sufficient proxy for the ultimate
outcome. iommufd also ensures that devices that set the cap will be
connected to enforcing domains.

Link: https://lore.kernel.org/r/4-v4-42cd2eb0e3eb+335a-vfio_iommufd_jgg@nvidia.com
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
Tested-by: Alex Williamson <alex.williamson@redhat.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Tested-by: Yi Liu <yi.l.liu@intel.com>
Tested-by: Lixiao Yang <lixiao.yang@intel.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Tested-by: Yu He <yu.he@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/vfio/container.c
drivers/vfio/vfio.h
drivers/vfio/vfio_main.c

index 499777930b08fa7d92e6c699ab3514fa32766eb6..d97747dfb05d02b93c89336b64969763bf2f4495 100644 (file)
@@ -188,8 +188,9 @@ void vfio_device_container_unregister(struct vfio_device *device)
                        device->group->container->iommu_data, device);
 }
 
-long vfio_container_ioctl_check_extension(struct vfio_container *container,
-                                         unsigned long arg)
+static long
+vfio_container_ioctl_check_extension(struct vfio_container *container,
+                                    unsigned long arg)
 {
        struct vfio_iommu_driver *driver;
        long ret = 0;
index f95f4925b83bbdee488db703b545a9e24c373aba..731561258704279d033e24cb5a26a3d36d6ae286 100644 (file)
@@ -119,8 +119,6 @@ int vfio_container_attach_group(struct vfio_container *container,
 void vfio_group_detach_container(struct vfio_group *group);
 void vfio_device_container_register(struct vfio_device *device);
 void vfio_device_container_unregister(struct vfio_device *device);
-long vfio_container_ioctl_check_extension(struct vfio_container *container,
-                                         unsigned long arg);
 int __init vfio_container_init(void);
 void vfio_container_cleanup(void);
 
index 8c2dcb481ae10b0de57f2dbff02bf95219900fd9..77d6c0ba6a83026af928f1acbbe9f7894691a41e 100644 (file)
@@ -1622,24 +1622,27 @@ EXPORT_SYMBOL_GPL(vfio_file_is_group);
 bool vfio_file_enforced_coherent(struct file *file)
 {
        struct vfio_group *group = file->private_data;
-       bool ret;
+       struct vfio_device *device;
+       bool ret = true;
 
        if (!vfio_file_is_group(file))
                return true;
 
-       mutex_lock(&group->group_lock);
-       if (group->container) {
-               ret = vfio_container_ioctl_check_extension(group->container,
-                                                          VFIO_DMA_CC_IOMMU);
-       } else {
-               /*
-                * Since the coherency state is determined only once a container
-                * is attached the user must do so before they can prove they
-                * have permission.
-                */
-               ret = true;
+       /*
+        * If the device does not have IOMMU_CAP_ENFORCE_CACHE_COHERENCY then
+        * any domain later attached to it will also not support it. If the cap
+        * is set then the iommu_domain eventually attached to the device/group
+        * must use a domain with enforce_cache_coherency().
+        */
+       mutex_lock(&group->device_lock);
+       list_for_each_entry(device, &group->device_list, group_next) {
+               if (!device_iommu_capable(device->dev,
+                                         IOMMU_CAP_ENFORCE_CACHE_COHERENCY)) {
+                       ret = false;
+                       break;
+               }
        }
-       mutex_unlock(&group->group_lock);
+       mutex_unlock(&group->device_lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(vfio_file_enforced_coherent);