diff options
-rw-r--r-- | drivers/vfio/vfio.c | 76 |
1 files changed, 71 insertions, 5 deletions
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index f018d8d0f975..43d5622b19b7 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c | |||
@@ -63,6 +63,11 @@ struct vfio_container { | |||
63 | void *iommu_data; | 63 | void *iommu_data; |
64 | }; | 64 | }; |
65 | 65 | ||
66 | struct vfio_unbound_dev { | ||
67 | struct device *dev; | ||
68 | struct list_head unbound_next; | ||
69 | }; | ||
70 | |||
66 | struct vfio_group { | 71 | struct vfio_group { |
67 | struct kref kref; | 72 | struct kref kref; |
68 | int minor; | 73 | int minor; |
@@ -75,6 +80,8 @@ struct vfio_group { | |||
75 | struct notifier_block nb; | 80 | struct notifier_block nb; |
76 | struct list_head vfio_next; | 81 | struct list_head vfio_next; |
77 | struct list_head container_next; | 82 | struct list_head container_next; |
83 | struct list_head unbound_list; | ||
84 | struct mutex unbound_lock; | ||
78 | atomic_t opened; | 85 | atomic_t opened; |
79 | }; | 86 | }; |
80 | 87 | ||
@@ -204,6 +211,8 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) | |||
204 | kref_init(&group->kref); | 211 | kref_init(&group->kref); |
205 | INIT_LIST_HEAD(&group->device_list); | 212 | INIT_LIST_HEAD(&group->device_list); |
206 | mutex_init(&group->device_lock); | 213 | mutex_init(&group->device_lock); |
214 | INIT_LIST_HEAD(&group->unbound_list); | ||
215 | mutex_init(&group->unbound_lock); | ||
207 | atomic_set(&group->container_users, 0); | 216 | atomic_set(&group->container_users, 0); |
208 | atomic_set(&group->opened, 0); | 217 | atomic_set(&group->opened, 0); |
209 | group->iommu_group = iommu_group; | 218 | group->iommu_group = iommu_group; |
@@ -264,9 +273,16 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) | |||
264 | static void vfio_group_release(struct kref *kref) | 273 | static void vfio_group_release(struct kref *kref) |
265 | { | 274 | { |
266 | struct vfio_group *group = container_of(kref, struct vfio_group, kref); | 275 | struct vfio_group *group = container_of(kref, struct vfio_group, kref); |
276 | struct vfio_unbound_dev *unbound, *tmp; | ||
267 | 277 | ||
268 | WARN_ON(!list_empty(&group->device_list)); | 278 | WARN_ON(!list_empty(&group->device_list)); |
269 | 279 | ||
280 | list_for_each_entry_safe(unbound, tmp, | ||
281 | &group->unbound_list, unbound_next) { | ||
282 | list_del(&unbound->unbound_next); | ||
283 | kfree(unbound); | ||
284 | } | ||
285 | |||
270 | device_destroy(vfio.class, MKDEV(MAJOR(vfio.group_devt), group->minor)); | 286 | device_destroy(vfio.class, MKDEV(MAJOR(vfio.group_devt), group->minor)); |
271 | list_del(&group->vfio_next); | 287 | list_del(&group->vfio_next); |
272 | vfio_free_group_minor(group->minor); | 288 | vfio_free_group_minor(group->minor); |
@@ -440,17 +456,36 @@ static bool vfio_whitelisted_driver(struct device_driver *drv) | |||
440 | } | 456 | } |
441 | 457 | ||
442 | /* | 458 | /* |
443 | * A vfio group is viable for use by userspace if all devices are either | 459 | * A vfio group is viable for use by userspace if all devices are in |
444 | * driver-less or bound to a vfio or whitelisted driver. We test the | 460 | * one of the following states: |
445 | * latter by the existence of a struct vfio_device matching the dev. | 461 | * - driver-less |
462 | * - bound to a vfio driver | ||
463 | * - bound to a whitelisted driver | ||
464 | * | ||
465 | * We use two methods to determine whether a device is bound to a vfio | ||
466 | * driver. The first is to test whether the device exists in the vfio | ||
467 | * group. The second is to test if the device exists on the group | ||
468 | * unbound_list, indicating it's in the middle of transitioning from | ||
469 | * a vfio driver to driver-less. | ||
446 | */ | 470 | */ |
447 | static int vfio_dev_viable(struct device *dev, void *data) | 471 | static int vfio_dev_viable(struct device *dev, void *data) |
448 | { | 472 | { |
449 | struct vfio_group *group = data; | 473 | struct vfio_group *group = data; |
450 | struct vfio_device *device; | 474 | struct vfio_device *device; |
451 | struct device_driver *drv = ACCESS_ONCE(dev->driver); | 475 | struct device_driver *drv = ACCESS_ONCE(dev->driver); |
476 | struct vfio_unbound_dev *unbound; | ||
477 | int ret = -EINVAL; | ||
452 | 478 | ||
453 | if (!drv || vfio_whitelisted_driver(drv)) | 479 | mutex_lock(&group->unbound_lock); |
480 | list_for_each_entry(unbound, &group->unbound_list, unbound_next) { | ||
481 | if (dev == unbound->dev) { | ||
482 | ret = 0; | ||
483 | break; | ||
484 | } | ||
485 | } | ||
486 | mutex_unlock(&group->unbound_lock); | ||
487 | |||
488 | if (!ret || !drv || vfio_whitelisted_driver(drv)) | ||
454 | return 0; | 489 | return 0; |
455 | 490 | ||
456 | device = vfio_group_get_device(group, dev); | 491 | device = vfio_group_get_device(group, dev); |
@@ -459,7 +494,7 @@ static int vfio_dev_viable(struct device *dev, void *data) | |||
459 | return 0; | 494 | return 0; |
460 | } | 495 | } |
461 | 496 | ||
462 | return -EINVAL; | 497 | return ret; |
463 | } | 498 | } |
464 | 499 | ||
465 | /** | 500 | /** |
@@ -501,6 +536,7 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb, | |||
501 | { | 536 | { |
502 | struct vfio_group *group = container_of(nb, struct vfio_group, nb); | 537 | struct vfio_group *group = container_of(nb, struct vfio_group, nb); |
503 | struct device *dev = data; | 538 | struct device *dev = data; |
539 | struct vfio_unbound_dev *unbound; | ||
504 | 540 | ||
505 | /* | 541 | /* |
506 | * Need to go through a group_lock lookup to get a reference or we | 542 | * Need to go through a group_lock lookup to get a reference or we |
@@ -550,6 +586,17 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb, | |||
550 | * stop the system to maintain isolation. At a minimum, we'd | 586 | * stop the system to maintain isolation. At a minimum, we'd |
551 | * want a toggle to disable driver auto probe for this device. | 587 | * want a toggle to disable driver auto probe for this device. |
552 | */ | 588 | */ |
589 | |||
590 | mutex_lock(&group->unbound_lock); | ||
591 | list_for_each_entry(unbound, | ||
592 | &group->unbound_list, unbound_next) { | ||
593 | if (dev == unbound->dev) { | ||
594 | list_del(&unbound->unbound_next); | ||
595 | kfree(unbound); | ||
596 | break; | ||
597 | } | ||
598 | } | ||
599 | mutex_unlock(&group->unbound_lock); | ||
553 | break; | 600 | break; |
554 | } | 601 | } |
555 | 602 | ||
@@ -657,6 +704,7 @@ void *vfio_del_group_dev(struct device *dev) | |||
657 | struct vfio_group *group = device->group; | 704 | struct vfio_group *group = device->group; |
658 | struct iommu_group *iommu_group = group->iommu_group; | 705 | struct iommu_group *iommu_group = group->iommu_group; |
659 | void *device_data = device->device_data; | 706 | void *device_data = device->device_data; |
707 | struct vfio_unbound_dev *unbound; | ||
660 | 708 | ||
661 | /* | 709 | /* |
662 | * The group exists so long as we have a device reference. Get | 710 | * The group exists so long as we have a device reference. Get |
@@ -664,6 +712,24 @@ void *vfio_del_group_dev(struct device *dev) | |||
664 | */ | 712 | */ |
665 | vfio_group_get(group); | 713 | vfio_group_get(group); |
666 | 714 | ||
715 | /* | ||
716 | * When the device is removed from the group, the group suddenly | ||
717 | * becomes non-viable; the device has a driver (until the unbind | ||
718 | * completes), but it's not present in the group. This is bad news | ||
719 | * for any external users that need to re-acquire a group reference | ||
720 | * in order to match and release their existing reference. To | ||
721 | * solve this, we track such devices on the unbound_list to bridge | ||
722 | * the gap until they're fully unbound. | ||
723 | */ | ||
724 | unbound = kzalloc(sizeof(*unbound), GFP_KERNEL); | ||
725 | if (unbound) { | ||
726 | unbound->dev = dev; | ||
727 | mutex_lock(&group->unbound_lock); | ||
728 | list_add(&unbound->unbound_next, &group->unbound_list); | ||
729 | mutex_unlock(&group->unbound_lock); | ||
730 | } | ||
731 | WARN_ON(!unbound); | ||
732 | |||
667 | vfio_device_put(device); | 733 | vfio_device_put(device); |
668 | 734 | ||
669 | /* TODO send a signal to encourage this to be released */ | 735 | /* TODO send a signal to encourage this to be released */ |