From 352e8da743f26948cb12d0ee53c455f328f59bbe Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 26 Jun 2014 15:10:03 +0200 Subject: qdev: correctly send DEVICE_DELETED for recursively-deleted devices When a device is unparented (i.e. made completely hidden from management) we want to send a DEVICE_DELETED event only if the device actually was realized. This avoids raising DEVICE_DELETED events when device_add fails. However, this does not work right for recursively-deleted devices: the whole tree is _first_ unrealized, _then_ unparented. Then device_unparent sees realized==false and fails to trigger the event. The solution is simply to move have_realized into the DeviceState struct. If device_add fails, we never set the new field to true and DEVICE_DELETED is not sent. Fixes qemu-iotests testcase 067 (broken by commit 5942a19, though that commit in turn fixed a possible segfault in the same test). Reported-by: Markus Armbruster Reviewed-by: Markus Armbruster Signed-off-by: Paolo Bonzini --- hw/core/qdev.c | 5 +++-- include/hw/qdev-core.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index d1eba3cc3d..c52041543d 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -848,6 +848,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) if (dev->hotplugged && local_err == NULL) { device_reset(dev); } + dev->pending_deleted_event = false; } else if (!value && dev->realized) { QLIST_FOREACH(bus, &dev->child_bus, sibling) { object_property_set_bool(OBJECT(bus), false, "realized", @@ -862,6 +863,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) if (dc->unrealize && local_err == NULL) { dc->unrealize(dev, &local_err); } + dev->pending_deleted_event = true; } if (local_err != NULL) { @@ -972,7 +974,6 @@ static void device_unparent(Object *obj) { DeviceState *dev = DEVICE(obj); BusState *bus; - bool have_realized = dev->realized; if (dev->realized) { object_property_set_bool(obj, false, "realized", NULL); @@ -988,7 +989,7 @@ static void device_unparent(Object *obj) } /* Only send event if the device had been completely realized */ - if (have_realized) { + if (dev->pending_deleted_event) { gchar *path = object_get_canonical_path(OBJECT(dev)); qapi_event_send_device_deleted(!!dev->id, dev->id, path, &error_abort); diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 9221cfc879..0799ff29b0 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -156,6 +156,7 @@ struct DeviceState { const char *id; bool realized; + bool pending_deleted_event; QemuOpts *opts; int hotplugged; BusState *parent_bus; -- cgit v1.2.3