|
@@ -85,6 +85,7 @@ struct vfio_group {
|
|
|
struct list_head unbound_list;
|
|
|
struct mutex unbound_lock;
|
|
|
atomic_t opened;
|
|
|
+ wait_queue_head_t container_q;
|
|
|
bool noiommu;
|
|
|
struct kvm *kvm;
|
|
|
struct blocking_notifier_head notifier;
|
|
@@ -338,6 +339,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
|
|
|
mutex_init(&group->unbound_lock);
|
|
|
atomic_set(&group->container_users, 0);
|
|
|
atomic_set(&group->opened, 0);
|
|
|
+ init_waitqueue_head(&group->container_q);
|
|
|
group->iommu_group = iommu_group;
|
|
|
#ifdef CONFIG_VFIO_NOIOMMU
|
|
|
group->noiommu = (iommu_group_get_iommudata(iommu_group) == &noiommu);
|
|
@@ -994,6 +996,23 @@ void *vfio_del_group_dev(struct device *dev)
|
|
|
}
|
|
|
} while (ret <= 0);
|
|
|
|
|
|
+ /*
|
|
|
+ * In order to support multiple devices per group, devices can be
|
|
|
+ * plucked from the group while other devices in the group are still
|
|
|
+ * in use. The container persists with this group and those remaining
|
|
|
+ * devices still attached. If the user creates an isolation violation
|
|
|
+ * by binding this device to another driver while the group is still in
|
|
|
+ * use, that's their fault. However, in the case of removing the last,
|
|
|
+ * or potentially the only, device in the group there can be no other
|
|
|
+ * in-use devices in the group. The user has done their due diligence
|
|
|
+ * and we should lay no claims to those devices. In order to do that,
|
|
|
+ * we need to make sure the group is detached from the container.
|
|
|
+ * Without this stall, we're potentially racing with a user process
|
|
|
+ * that may attempt to immediately bind this device to another driver.
|
|
|
+ */
|
|
|
+ if (list_empty(&group->device_list))
|
|
|
+ wait_event(group->container_q, !group->container);
|
|
|
+
|
|
|
vfio_group_put(group);
|
|
|
|
|
|
return device_data;
|
|
@@ -1299,6 +1318,7 @@ static void __vfio_group_unset_container(struct vfio_group *group)
|
|
|
group->iommu_group);
|
|
|
|
|
|
group->container = NULL;
|
|
|
+ wake_up(&group->container_q);
|
|
|
list_del(&group->container_next);
|
|
|
|
|
|
/* Detaching the last group deprivileges a container, remove iommu */
|