qdev: DEVICE_DELETED event
libvirt has a long-standing bug: when removing the device, it can request removal but does not know when the removal completes. Add an event so we can fix this in a robust way. Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
b1999e87b4
commit
0402a5d65e
@ -136,6 +136,22 @@ Example:
|
|||||||
Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
|
Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
|
||||||
event.
|
event.
|
||||||
|
|
||||||
|
DEVICE_DELETED
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Emitted whenever the device removal completion is acknowledged
|
||||||
|
by the guest.
|
||||||
|
At this point, it's safe to reuse the specified device ID.
|
||||||
|
Device removal can be initiated by the guest or by HMP/QMP commands.
|
||||||
|
|
||||||
|
Data:
|
||||||
|
|
||||||
|
- "device": device name (json-string, optional)
|
||||||
|
|
||||||
|
{ "event": "DEVICE_DELETED",
|
||||||
|
"data": { "device": "virtio-net-pci-0" },
|
||||||
|
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
||||||
|
|
||||||
DEVICE_TRAY_MOVED
|
DEVICE_TRAY_MOVED
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
11
hw/qdev.c
11
hw/qdev.c
@ -30,6 +30,8 @@
|
|||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
|
#include "qapi/qmp/qjson.h"
|
||||||
|
#include "monitor/monitor.h"
|
||||||
|
|
||||||
int qdev_hotplug = 0;
|
int qdev_hotplug = 0;
|
||||||
static bool qdev_hot_added = false;
|
static bool qdev_hot_added = false;
|
||||||
@ -761,6 +763,7 @@ static void device_unparent(Object *obj)
|
|||||||
DeviceState *dev = DEVICE(obj);
|
DeviceState *dev = DEVICE(obj);
|
||||||
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||||
BusState *bus;
|
BusState *bus;
|
||||||
|
QObject *event_data;
|
||||||
|
|
||||||
while (dev->num_child_bus) {
|
while (dev->num_child_bus) {
|
||||||
bus = QLIST_FIRST(&dev->child_bus);
|
bus = QLIST_FIRST(&dev->child_bus);
|
||||||
@ -779,6 +782,14 @@ static void device_unparent(Object *obj)
|
|||||||
object_unref(OBJECT(dev->parent_bus));
|
object_unref(OBJECT(dev->parent_bus));
|
||||||
dev->parent_bus = NULL;
|
dev->parent_bus = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->id) {
|
||||||
|
event_data = qobject_from_jsonf("{ 'device': %s }", dev->id);
|
||||||
|
} else {
|
||||||
|
event_data = qobject_from_jsonf("{ }");
|
||||||
|
}
|
||||||
|
monitor_protocol_event(QEVENT_DEVICE_DELETED, event_data);
|
||||||
|
qobject_decref(event_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void device_class_init(ObjectClass *class, void *data)
|
static void device_class_init(ObjectClass *class, void *data)
|
||||||
|
@ -39,6 +39,7 @@ typedef enum MonitorEvent {
|
|||||||
QEVENT_BLOCK_JOB_CANCELLED,
|
QEVENT_BLOCK_JOB_CANCELLED,
|
||||||
QEVENT_BLOCK_JOB_ERROR,
|
QEVENT_BLOCK_JOB_ERROR,
|
||||||
QEVENT_BLOCK_JOB_READY,
|
QEVENT_BLOCK_JOB_READY,
|
||||||
|
QEVENT_DEVICE_DELETED,
|
||||||
QEVENT_DEVICE_TRAY_MOVED,
|
QEVENT_DEVICE_TRAY_MOVED,
|
||||||
QEVENT_SUSPEND,
|
QEVENT_SUSPEND,
|
||||||
QEVENT_SUSPEND_DISK,
|
QEVENT_SUSPEND_DISK,
|
||||||
|
@ -458,6 +458,7 @@ static const char *monitor_event_names[] = {
|
|||||||
[QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED",
|
[QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED",
|
||||||
[QEVENT_BLOCK_JOB_ERROR] = "BLOCK_JOB_ERROR",
|
[QEVENT_BLOCK_JOB_ERROR] = "BLOCK_JOB_ERROR",
|
||||||
[QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY",
|
[QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY",
|
||||||
|
[QEVENT_DEVICE_DELETED] = "DEVICE_DELETED",
|
||||||
[QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
|
[QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
|
||||||
[QEVENT_SUSPEND] = "SUSPEND",
|
[QEVENT_SUSPEND] = "SUSPEND",
|
||||||
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
|
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
|
||||||
|
@ -2354,7 +2354,9 @@
|
|||||||
# Notes: When this command completes, the device may not be removed from the
|
# Notes: When this command completes, the device may not be removed from the
|
||||||
# guest. Hot removal is an operation that requires guest cooperation.
|
# guest. Hot removal is an operation that requires guest cooperation.
|
||||||
# This command merely requests that the guest begin the hot removal
|
# This command merely requests that the guest begin the hot removal
|
||||||
# process.
|
# process. Completion of the device removal process is signaled with a
|
||||||
|
# DEVICE_DELETED event. Guest reset will automatically complete removal
|
||||||
|
# for all devices.
|
||||||
#
|
#
|
||||||
# Since: 0.14.0
|
# Since: 0.14.0
|
||||||
##
|
##
|
||||||
|
Loading…
Reference in New Issue
Block a user