[PATCH 2/8] qdev: hotplug: Add force_unplug handler callback
Dongli Zhang <[email protected]>
| Newsgroups | org.xenproject.lists.xen-devel,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Add a HotplugHandlerClass force_unplug callback and a wrapper used by the generic qdev unplug path. When qdev_unplug() is called with force=true, delegate to the hotplug controller if it implements force_unplug. Controllers without the callback return a normal error. This makes forced removal available only for controllers that explicitly implement the operation. Signed-off-by: Dongli Zhang <[email protected]> --- hw/core/hotplug.c | 11 +++++++++++ include/hw/core/hotplug.h | 12 ++++++++++++ system/qdev-monitor.c | 10 +++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/hw/core/hotplug.c b/hw/core/hotplug.c index 68aabad8ae..0e44d98cf7 100644 --- a/hw/core/hotplug.c +++ b/hw/core/hotplug.c @@ -57,6 +57,17 @@ void hotplug_handler_unplug(HotplugHandler *plug_handler, } } +void hotplug_handler_force_unplug(HotplugHandler *plug_handler, + DeviceState *plugged_dev, + Error **errp) +{ + HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler); + + if (hdc->force_unplug) { + hdc->force_unplug(plug_handler, plugged_dev, errp); + } +} + static const TypeInfo hotplug_handler_info = { .name = TYPE_HOTPLUG_HANDLER, .parent = TYPE_INTERFACE, diff --git a/include/hw/core/hotplug.h b/include/hw/core/hotplug.h index a9840ed485..300ac4fa8f 100644 --- a/include/hw/core/hotplug.h +++ b/include/hw/core/hotplug.h @@ -48,6 +48,8 @@ typedef void (*hotplug_fn)(HotplugHandler *plug_handler, * @unplug: unplug callback. * Used for device removal with devices that implement * asynchronous and synchronous (surprise) removal. + * @force_unplug: force unplug callback. + * Used to complete enforced removal without guest cooperation. * @is_hotpluggable_bus: called to check if bus/its parent allow hotplug on bus */ struct HotplugHandlerClass { @@ -59,6 +61,7 @@ struct HotplugHandlerClass { hotplug_fn plug; hotplug_fn unplug_request; hotplug_fn unplug; + hotplug_fn force_unplug; bool (*is_hotpluggable_bus)(HotplugHandler *plug_handler, BusState *bus); }; @@ -96,4 +99,13 @@ void hotplug_handler_unplug_request(HotplugHandler *plug_handler, void hotplug_handler_unplug(HotplugHandler *plug_handler, DeviceState *plugged_dev, Error **errp); + +/** + * hotplug_handler_force_unplug: + * + * Calls #HotplugHandlerClass.force_unplug callback of @plug_handler. + */ +void hotplug_handler_force_unplug(HotplugHandler *plug_handler, + DeviceState *plugged_dev, + Error **errp); #endif diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index 3606a347a0..fa3cae246b 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -937,7 +937,15 @@ void qdev_unplug(DeviceState *dev, bool force, Error **errp) /* If device supports async unplug just request it to be done, * otherwise just remove it synchronously */ hdc = HOTPLUG_HANDLER_GET_CLASS(hotplug_ctrl); - if (hdc->unplug_request) { + + if (force) { + if (!hdc->force_unplug) { + error_setg(&local_err, "Device '%s' does not support forced unplug", + dev->id ? dev->id : object_get_typename(OBJECT(dev))); + } else { + hotplug_handler_force_unplug(hotplug_ctrl, dev, &local_err); + } + } else if (hdc->unplug_request) { hotplug_handler_unplug_request(hotplug_ctrl, dev, &local_err); } else { hotplug_handler_unplug(hotplug_ctrl, dev, &local_err); -- 2.43.5