vfio: Test realized when using VFIOGroup.device_list iterator

VFIOGroup.device_list is effectively our reference tracking mechanism
such that we can teardown a group when all of the device references
are removed.  However, we also use this list from our machine reset
handler for processing resets that affect multiple devices.  Generally
device removals are fully processed (exitfn + finalize) when this
reset handler is invoked, however if the removal is triggered via
another reset handler (piix4_reset->acpi_pcihp_reset) then the device
exitfn may run, but not finalize.  In this case we hit asserts when
we start trying to access PCI helpers since much of the PCI state of
the device is released.  To resolve this, add a pointer to the Object
DeviceState in our common base-device and skip non-realized devices
as we iterate.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
Alex Williamson 2017-07-10 10:39:43 -06:00
parent 6b06e3e49e
commit 7da624e26a
4 changed files with 11 additions and 4 deletions

View File

@ -858,13 +858,15 @@ void vfio_reset_handler(void *opaque)
QLIST_FOREACH(group, &vfio_group_list, next) { QLIST_FOREACH(group, &vfio_group_list, next) {
QLIST_FOREACH(vbasedev, &group->device_list, next) { QLIST_FOREACH(vbasedev, &group->device_list, next) {
if (vbasedev->dev->realized) {
vbasedev->ops->vfio_compute_needs_reset(vbasedev); vbasedev->ops->vfio_compute_needs_reset(vbasedev);
} }
} }
}
QLIST_FOREACH(group, &vfio_group_list, next) { QLIST_FOREACH(group, &vfio_group_list, next) {
QLIST_FOREACH(vbasedev, &group->device_list, next) { QLIST_FOREACH(vbasedev, &group->device_list, next) {
if (vbasedev->needs_reset) { if (vbasedev->dev->realized && vbasedev->needs_reset) {
vbasedev->ops->vfio_hot_reset_multi(vbasedev); vbasedev->ops->vfio_hot_reset_multi(vbasedev);
} }
} }

View File

@ -2116,7 +2116,8 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
/* Prep dependent devices for reset and clear our marker. */ /* Prep dependent devices for reset and clear our marker. */
QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) { if (!vbasedev_iter->dev->realized ||
vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
continue; continue;
} }
tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev); tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
@ -2197,7 +2198,8 @@ out:
} }
QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) { if (!vbasedev_iter->dev->realized ||
vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
continue; continue;
} }
tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev); tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
@ -2647,6 +2649,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
vdev->vbasedev.name = g_strdup(basename(vdev->vbasedev.sysfsdev)); vdev->vbasedev.name = g_strdup(basename(vdev->vbasedev.sysfsdev));
vdev->vbasedev.ops = &vfio_pci_ops; vdev->vbasedev.ops = &vfio_pci_ops;
vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI; vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI;
vdev->vbasedev.dev = &vdev->pdev.qdev;
tmp = g_strdup_printf("%s/iommu_group", vdev->vbasedev.sysfsdev); tmp = g_strdup_printf("%s/iommu_group", vdev->vbasedev.sysfsdev);
len = readlink(tmp, group_path, sizeof(group_path)); len = readlink(tmp, group_path, sizeof(group_path));

View File

@ -640,6 +640,7 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp)
int i, ret; int i, ret;
vbasedev->type = VFIO_DEVICE_TYPE_PLATFORM; vbasedev->type = VFIO_DEVICE_TYPE_PLATFORM;
vbasedev->dev = dev;
vbasedev->ops = &vfio_platform_ops; vbasedev->ops = &vfio_platform_ops;
trace_vfio_platform_realize(vbasedev->sysfsdev ? trace_vfio_platform_realize(vbasedev->sysfsdev ?

View File

@ -115,6 +115,7 @@ typedef struct VFIODevice {
struct VFIOGroup *group; struct VFIOGroup *group;
char *sysfsdev; char *sysfsdev;
char *name; char *name;
DeviceState *dev;
int fd; int fd;
int type; int type;
bool reset_works; bool reset_works;