summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2013-01-25 14:12:34 +0100
committerAnthony Liguori <aliguori@us.ibm.com>2013-02-01 15:53:10 -0600
commit06f7f2bb562826101468f387b4a34971b16e9aee (patch)
tree17379e83fd14c60f1c83402ed76bf186bbf6582c
parent6853d27a1253cd29c43d08b0624e7938a48d52a7 (diff)
qdev: move unrealization of devices from finalize to unparent
Similarly, a bus holds a reference back to the device, and this will prevent the device from going away as soon as this reference is counted properly. To avoid this, move the unrealization of devices to the unparent callback. This includes recursively unparenting all the buses and (after the previous patch) the devices on those buses, which ensures that the web of references completely disappears for all devices that reside (in the qdev tree) below the one being unplugged. After this patch, the qdev tree and the bus<->child relationship is defined as "A is above B, iff unplugging A will automatically unplug B". Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
-rw-r--r--hw/qdev.c35
1 files changed, 17 insertions, 18 deletions
diff --git a/hw/qdev.c b/hw/qdev.c
index 3c1ec7df44..6f1b3117ff 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -738,23 +738,8 @@ static void device_initfn(Object *obj)
static void device_finalize(Object *obj)
{
DeviceState *dev = DEVICE(obj);
- BusState *bus;
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
- if (dev->realized) {
- while (dev->num_child_bus) {
- bus = QLIST_FIRST(&dev->child_bus);
- qbus_free(bus);
- }
- if (qdev_get_vmsd(dev)) {
- vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
- }
- if (dc->exit) {
- dc->exit(dev);
- }
- if (dev->opts) {
- qemu_opts_del(dev->opts);
- }
+ if (dev->opts) {
+ qemu_opts_del(dev->opts);
}
}
@@ -771,8 +756,22 @@ static void device_class_base_init(ObjectClass *class, void *data)
static void device_unparent(Object *obj)
{
DeviceState *dev = DEVICE(obj);
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ BusState *bus;
- if (dev->parent_bus != NULL) {
+ while (dev->num_child_bus) {
+ bus = QLIST_FIRST(&dev->child_bus);
+ qbus_free(bus);
+ }
+ if (dev->realized) {
+ if (qdev_get_vmsd(dev)) {
+ vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
+ }
+ if (dc->exit) {
+ dc->exit(dev);
+ }
+ }
+ if (dev->parent_bus) {
bus_remove_child(dev->parent_bus, dev);
}
}