[PATCH 3/8] qdev: Support forced device_del in QMP and HMP
Dongli Zhang <[email protected]>
| Newsgroups | org.xenproject.lists.xen-devel,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Add an optional force argument to the QMP device_del command and expose it in HMP as "device_del -f". When force is requested, qdev_unplug() bypasses the pending deletion guard and asks the selected hotplug controller to complete removal through its force_unplug callback. Controllers that do not implement the callback reject the operation. Forced removal bypasses guest cooperation. Signed-off-by: Dongli Zhang <[email protected]> --- hmp-commands.hx | 11 ++++++----- qapi/qdev.json | 11 +++++++++-- system/qdev-monitor.c | 11 +++++++---- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 43ff220b5f..022502b20f 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -708,17 +708,18 @@ ERST { .name = "device_del", - .args_type = "id:s", - .params = "device", - .help = "remove device", + .args_type = "force:-f,id:s", + .params = "[-f] device", + .help = "remove device, use -f to force removal", .cmd = hmp_device_del, .command_completion = device_del_completion, }, SRST -``device_del`` *id* +``device_del`` [*-f*] *id* Remove device *id*. *id* may be a short ID - or a QOM object path. + or a QOM object path. Use -f to force removal without waiting for + guest cooperation. ERST { diff --git a/qapi/qdev.json b/qapi/qdev.json index 974cf9c583..cb5b5ad1db 100644 --- a/qapi/qdev.json +++ b/qapi/qdev.json @@ -90,6 +90,11 @@ # # @id: the device's ID or QOM path # +# @force: if true, remove the device without waiting for guest +# cooperation. The guest may still be using the device. This can +# cause guest-visible errors, I/O failures, or guest crashes. +# (since 11.2) +# # Errors: # - If @id is not a valid device, DeviceNotFound # @@ -101,7 +106,9 @@ # will automatically complete removal for all devices. If a # guest-side error in the hot removal process is detected, the # device will not be removed and a `DEVICE_UNPLUG_GUEST_ERROR` -# event is sent. Some errors cannot be detected. +# event is sent. Some errors cannot be detected. If @force is +# true, guest cooperation is bypassed, but backend cleanup is still +# performed through the device's normal unrealize path. # # Since: 0.14 # @@ -117,7 +124,7 @@ # "arguments": { "id": "/machine/peripheral-anon/device[0]" } } # <- { "return": {} } ## -{ 'command': 'device_del', 'data': {'id': 'str'} } +{ 'command': 'device_del', 'data': {'id': 'str', '*force': 'bool'} } ## # @DEVICE_DELETED: diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index fa3cae246b..ca10a25c46 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -956,11 +956,13 @@ void qdev_unplug(DeviceState *dev, bool force, Error **errp) error_propagate(errp, local_err); } -void qmp_device_del(const char *id, Error **errp) +void qmp_device_del(const char *id, bool has_force, bool force, Error **errp) { DeviceState *dev = find_device_state(id, false, errp); + bool do_force = has_force && force; + if (dev != NULL) { - if (dev->pending_deleted_event && + if (!do_force && dev->pending_deleted_event && (dev->pending_deleted_expires_ms == 0 || dev->pending_deleted_expires_ms > qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL))) { error_setg(errp, "Device %s is already in the " @@ -968,7 +970,7 @@ void qmp_device_del(const char *id, Error **errp) return; } - qdev_unplug(dev, false, errp); + qdev_unplug(dev, do_force, errp); } } @@ -1046,9 +1048,10 @@ out: void hmp_device_del(Monitor *mon, const QDict *qdict) { const char *id = qdict_get_str(qdict, "id"); + bool force = qdict_get_try_bool(qdict, "force", false); Error *err = NULL; - qmp_device_del(id, &err); + qmp_device_del(id, true, force, &err); hmp_handle_error(mon, err); } -- 2.43.5