aboutsummaryrefslogtreecommitdiff
path: root/hw/pci.c
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2010-05-11 06:44:21 -0400
committerMichael S. Tsirkin <mst@redhat.com>2010-05-12 01:59:11 +0300
commit925fe64ae7b487fdb7bd56fcab63e2f87653c226 (patch)
treede0ad9b6677f69773d4c5349a59d5c26858aeb7c /hw/pci.c
parent54d7cf136f040713095cbc064f62d753bff6f9d2 (diff)
pci: cleanly backout of pci_qdev_init()
If the init function of a device fails, as might happen with device assignment, we never undo the work done by do_pci_register_device(). This not only causes a bit of a memory leak, but also leaves a bogus pointer in the bus devices array that can cause a segfault or garbage data from 'info pci'. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/pci.c')
-rw-r--r--hw/pci.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/hw/pci.c b/hw/pci.c
index f167436edc..3ca5f0953f 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -625,6 +625,13 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
return pci_dev;
}
+static void do_pci_unregister_device(PCIDevice *pci_dev)
+{
+ qemu_free_irqs(pci_dev->irq);
+ pci_dev->bus->devices[pci_dev->devfn] = NULL;
+ pci_config_free(pci_dev);
+}
+
PCIDevice *pci_register_device(PCIBus *bus, const char *name,
int instance_size, int devfn,
PCIConfigReadFunc *config_read,
@@ -680,10 +687,7 @@ static int pci_unregister_device(DeviceState *dev)
return ret;
pci_unregister_io_regions(pci_dev);
-
- qemu_free_irqs(pci_dev->irq);
- pci_dev->bus->devices[pci_dev->devfn] = NULL;
- pci_config_free(pci_dev);
+ do_pci_unregister_device(pci_dev);
return 0;
}
@@ -1652,8 +1656,10 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
if (pci_dev == NULL)
return -1;
rc = info->init(pci_dev);
- if (rc != 0)
+ if (rc != 0) {
+ do_pci_unregister_device(pci_dev);
return rc;
+ }
/* rom loading */
if (pci_dev->romfile == NULL && info->romfile != NULL)