aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorCédric Le Goater <clg@redhat.com>2024-07-01 12:14:53 +0200
committerMichael S. Tsirkin <mst@redhat.com>2024-07-03 18:14:07 -0400
commit1b889d6e39c32d709f1114699a014b381bcf1cb1 (patch)
tree146fff77a24c9bfeb08d75b58b18b9350ef92ce0 /hw
parent7aa6492401e95fb296dec7cda81e67d91f6037d7 (diff)
downloadqemu-1b889d6e39c32d709f1114699a014b381bcf1cb1.zip
qemu-1b889d6e39c32d709f1114699a014b381bcf1cb1.tar.gz
qemu-1b889d6e39c32d709f1114699a014b381bcf1cb1.tar.bz2
virtio-iommu: Clear IOMMUDevice when VFIO device is unplugged
When a VFIO device is hoplugged in a VM using virtio-iommu, IOMMUPciBus and IOMMUDevice cache entries are created in the .get_address_space() handler of the machine IOMMU device. However, these entries are never destroyed, not even when the VFIO device is detached from the machine. This can lead to an assert if the device is reattached again. When reattached, the .get_address_space() handler reuses an IOMMUDevice entry allocated when the VFIO device was first attached. virtio_iommu_set_host_iova_ranges() is called later on from the .set_iommu_device() handler an fails with an assert on 'probe_done' because the device appears to have been already probed when this is not the case. The IOMMUDevice entry is allocated in pci_device_iommu_address_space() called from under vfio_realize(), the VFIO PCI realize handler. Since pci_device_unset_iommu_device() is called from vfio_exitfn(), a sub function of the PCIDevice unrealize() handler, it seems that the .unset_iommu_device() handler is the best place to release resources allocated at realize time. Clear the IOMMUDevice cache entry there to fix hotplug. Fixes: 817ef10da23c ("virtio-iommu: Implement set|unset]_iommu_device() callbacks") Signed-off-by: Cédric Le Goater <clg@redhat.com> Message-Id: <20240701101453.203985-1-clg@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/virtio/virtio-iommu.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index ed7426a..7c54c6b 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -467,6 +467,26 @@ static AddressSpace *virtio_iommu_find_add_as(PCIBus *bus, void *opaque,
return &sdev->as;
}
+static void virtio_iommu_device_clear(VirtIOIOMMU *s, PCIBus *bus, int devfn)
+{
+ IOMMUPciBus *sbus = g_hash_table_lookup(s->as_by_busptr, bus);
+ IOMMUDevice *sdev;
+
+ if (!sbus) {
+ return;
+ }
+
+ sdev = sbus->pbdev[devfn];
+ if (!sdev) {
+ return;
+ }
+
+ g_list_free_full(sdev->resv_regions, g_free);
+ sdev->resv_regions = NULL;
+ g_free(sdev);
+ sbus->pbdev[devfn] = NULL;
+}
+
static gboolean hiod_equal(gconstpointer v1, gconstpointer v2)
{
const struct hiod_key *key1 = v1;
@@ -650,6 +670,7 @@ virtio_iommu_unset_iommu_device(PCIBus *bus, void *opaque, int devfn)
}
g_hash_table_remove(viommu->host_iommu_devices, &key);
+ virtio_iommu_device_clear(viommu, bus, devfn);
}
static const PCIIOMMUOps virtio_iommu_ops = {