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 <armbru@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									1f6245e5ab
								
							
						
					
					
						commit
						352e8da743
					
				| @ -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); | ||||
|  | ||||
| @ -156,6 +156,7 @@ struct DeviceState { | ||||
| 
 | ||||
|     const char *id; | ||||
|     bool realized; | ||||
|     bool pending_deleted_event; | ||||
|     QemuOpts *opts; | ||||
|     int hotplugged; | ||||
|     BusState *parent_bus; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Paolo Bonzini
						Paolo Bonzini