From 6a2ee1fd8d36ed8407b403a7307de1633462759c Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 9 Oct 2019 12:39:45 +0100 Subject: [PATCH 19/22] qdev/machine: Introduce hotplug_allowed hook RH-Author: Peter Xu Message-id: <20191009123947.21505-4-peterx@redhat.com> Patchwork-id: 91351 O-Subject: [RHEL-8.2.0 qemu-kvm PATCH 3/5] qdev/machine: Introduce hotplug_allowed hook Bugzilla: 1738440 RH-Acked-by: Paolo Bonzini RH-Acked-by: Auger Eric RH-Acked-by: Alex Williamson Signed-off-by: Danilo C. L. de Paula Conflicts: hw/core/qdev.c: don't have 14405c274e86e ("qdev: Provide qdev_get_bus_hotplug_handler()") include/hw/boards: plenty of new things missing in MachineClass (kvm_type, numa_mem_supported, smp_parse) include/hw/qdev-core.h: don't have 17cc0128da3 ("qdev: Let machine hotplug handler to override bus hotplug handler") Introduce this new per-machine hook to give any machine class a chance to do a sanity check on the to-be-hotplugged device as a sanity test. This will be used for x86 to try to detect some illegal configuration of devices, e.g., possible conflictions between vfio-pci and x86 vIOMMU. Reviewed-by: Eric Auger Signed-off-by: Peter Xu Message-Id: <20190916080718.3299-3-peterx@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit d2321d31ff98b75b652c2b1594f00a4cfd48102a) Signed-off-by: Peter Xu Signed-off-by: Danilo C. L. de Paula --- hw/core/qdev.c | 17 +++++++++++++++++ include/hw/boards.h | 9 +++++++++ include/hw/qdev-core.h | 1 + qdev-monitor.c | 7 +++++++ 4 files changed, 34 insertions(+) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 24f1ae7..5971242 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -259,6 +259,23 @@ HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev) return NULL; } +bool qdev_hotplug_allowed(DeviceState *dev, Error **errp) +{ + MachineState *machine; + MachineClass *mc; + Object *m_obj = qdev_get_machine(); + + if (object_dynamic_cast(m_obj, TYPE_MACHINE)) { + machine = MACHINE(m_obj); + mc = MACHINE_GET_CLASS(machine); + if (mc->hotplug_allowed) { + return mc->hotplug_allowed(machine, dev, errp); + } + } + + return true; +} + HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev) { HotplugHandler *hotplug_ctrl; diff --git a/include/hw/boards.h b/include/hw/boards.h index 9b4a69b..e568a3c 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -156,6 +156,13 @@ typedef struct { * should instead use "unimplemented-device" for all memory ranges where * the guest will attempt to probe for a device that QEMU doesn't * implement and a stub device is required. + * @hotplug_allowed: + * If the hook is provided, then it'll be called for each device + * hotplug to check whether the device hotplug is allowed. Return + * true to grant allowance or false to reject the hotplug. When + * false is returned, an error must be set to show the reason of + * the rejection. If the hook is not provided, all hotplug will be + * allowed. */ struct MachineClass { /*< private >*/ @@ -210,6 +217,8 @@ struct MachineClass { HotplugHandler *(*get_hotplug_handler)(MachineState *machine, DeviceState *dev); + bool (*hotplug_allowed)(MachineState *state, DeviceState *dev, + Error **errp); CpuInstanceProperties (*cpu_index_to_instance_props)(MachineState *machine, unsigned cpu_index); const CPUArchIdList *(*possible_cpu_arch_ids)(MachineState *machine); diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 9453588..b8d1cac 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -286,6 +286,7 @@ void qdev_init_nofail(DeviceState *dev); void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, int required_for_version); HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev); +bool qdev_hotplug_allowed(DeviceState *dev, Error **errp); HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev); void qdev_unplug(DeviceState *dev, Error **errp); void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, diff --git a/qdev-monitor.c b/qdev-monitor.c index f439b83..70bce8f 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -606,6 +606,13 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) /* create device */ dev = DEVICE(object_new(driver)); + /* Check whether the hotplug is allowed by the machine */ + if (qdev_hotplug && !qdev_hotplug_allowed(dev, &err)) { + /* Error must be set in the machine hook */ + assert(err); + goto err_del_dev; + } + if (bus) { qdev_set_parent_bus(dev, bus); } else if (qdev_hotplug && !qdev_get_machine_hotplug_handler(dev)) { -- 1.8.3.1