From: Salil Mehta <salil.mehta@huawei.com>
This patch adds a "device_set" interface for modifying properties of devices
that already exist in the guest topology. Unlike 'device_add'/'device_del'
(hot-plug), 'device_set' does not create or destroy devices. It is intended
for guest-visible hot-add semantics where hardware is provisioned at boot but
logically enabled/disabled later via administrative policy.
Compared to the existing 'qom-set' command, which is less intuitive and works
only with object IDs, device_set provides a more device-oriented interface.
It can be invoked at the QEMU prompt using natural device arguments, and the
new '-deviceset' CLI option allows properties to be set at boot time, similar
to how '-device' specifies device creation.
While the initial implementation focuses on "admin-state" changes (e.g.,
enable/disable a CPU already described by ACPI/DT), the interface is designed
to be generic. In future, it could be used for other per-device set/unset
style controls — beyond administrative power-states — provided the target
device explicitly allows such changes. This enables fine-grained runtime
control of device properties.
Key pieces:
* QMP: qmp_device_set() to update an existing device. The device can be
located by "id" or via driver+property match using a DeviceListener
callback (qdev_find_device()).
* HMP: "device_set" command with tab-completion. Errors are surfaced via
hmp_handle_error().
* CLI: "-deviceset" option for setting startup/admin properties at boot,
including a JSON form. Options are parsed into qemu_deviceset_opts and
applied after device creation.
* Docs/help: HMP help text and qemu-options.hx additions explain usage and
explicitly note that no hot-plug occurs.
* Safety: disallowed during live migration (migration_is_idle() check).
Semantics:
* Operates on an existing DeviceState; no enumeration/new device appears.
* Complements device_add/device_del by providing state mutation only.
* Backward compatible: no behavior change unless "device_set"/"-deviceset"
is used.
Examples:
HMP:
(qemu) device_set host-arm-cpu,core-id=3,admin-state=enable
CLI (at boot):
-smp cpus=4,maxcpus=4 \
-deviceset host-arm-cpu,core-id=2,admin-state=disable
QMP (JSON form):
{ "execute": "device_set",
"arguments": {
"driver": "host-arm-cpu",
"core-id": 1,
"admin-state": "disable"
}
}
NOTE: The qdev_enable()/qdev_disable() hooks for acting on admin-state will be
added in subsequent patches. Device classes must explicitly support any
property they want to expose through device_set.
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
hmp-commands.hx | 30 +++++++++
hw/arm/virt.c | 86 +++++++++++++++++++++++++
hw/core/cpu-common.c | 12 ++++
hw/core/qdev.c | 21 ++++++
include/hw/arm/virt.h | 1 +
include/hw/core/cpu.h | 11 ++++
include/hw/qdev-core.h | 22 +++++++
include/monitor/hmp.h | 2 +
include/monitor/qdev.h | 30 +++++++++
include/system/system.h | 1 +
qemu-options.hx | 51 +++++++++++++--
system/qdev-monitor.c | 139 +++++++++++++++++++++++++++++++++++++++-
system/vl.c | 39 +++++++++++
13 files changed, 440 insertions(+), 5 deletions(-)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index d0e4f35a30..18056cf21d 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -707,6 +707,36 @@ SRST
or a QOM object path.
ERST
+{
+ .name = "device_set",
+ .args_type = "device:O",
+ .params = "driver[,prop=value][,...]",
+ .help = "set/unset existing device property",
+ .cmd = hmp_device_set,
+ .command_completion = device_set_completion,
+},
+
+SRST
+``device_set`` *driver[,prop=value][,...]*
+ Change the administrative power state of an existing device.
+
+ This command enables or disables a known device (e.g., CPU) using the
+ "device_set" interface. It does not hotplug or add a new device.
+
+ Depending on platform support (e.g., PSCI or ACPI), this may trigger
+ corresponding operational changes — such as powering down a CPU or
+ transitioning it to active use.
+
+ Administrative state:
+ * *enabled* — Allows the guest to use the device (e.g., CPU_ON)
+ * *disabled* — Prevents guest use; device is powered off (e.g., CPU_OFF)
+
+ Note: The device must already exist (be declared during machine creation).
+
+ Example:
+ (qemu) device_set host-arm-cpu,core-id=3,admin-state=disabled
+ERST
+
{
.name = "cpu",
.args_type = "index:i",
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 9a41a0682b..7bd37ffb75 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -74,6 +74,7 @@
#include "qapi/visitor.h"
#include "qapi/qapi-visit-common.h"
#include "qobject/qlist.h"
+#include "qobject/qdict.h"
#include "standard-headers/linux/input.h"
#include "hw/arm/smmuv3.h"
#include "hw/acpi/acpi.h"
@@ -1824,6 +1825,88 @@ void virt_machine_done(Notifier *notifier, void *data)
virt_build_smbios(vms);
}
+static DeviceState *virt_find_cpu(const QDict *opts, Error **errp)
+{
+ int64_t socket_id, cluster_id, core_id, thread_id;
+ MachineState *ms = MACHINE(qdev_get_machine());
+ int64_t T, C, K, cpu_id;
+ CPUState *cpu;
+ const char *s;
+
+ /* parse topology */
+ socket_id = (s = qdict_get_try_str(opts, "socket-id")) ?
+ strtoll(s, NULL, 10) : 0;
+ cluster_id = (s = qdict_get_try_str(opts, "cluster-id")) ?
+ strtoll(s, NULL, 10) : 0;
+ core_id = (s = qdict_get_try_str(opts, "core-id")) ?
+ strtoll(s, NULL, 10) : 0;
+ thread_id = (s = qdict_get_try_str(opts, "thread-id")) ?
+ strtoll(s, NULL, 10) : 0;
+
+ /* Range checks */
+ if (thread_id < 0 || thread_id >= ms->smp.threads) {
+ error_setg(errp,
+ "Couldn't find cpu(%ld:%ld:%ld:%ld), Invalid thread-id %ld",
+ socket_id, cluster_id, core_id, thread_id, thread_id);
+ return NULL;
+ }
+ if (core_id < 0 || core_id >= ms->smp.cores) {
+ error_setg(errp,
+ "Couldn't find cpu(%ld:%ld:%ld:%ld), Invalid core-id %ld",
+ socket_id, cluster_id, core_id, thread_id, core_id);
+ return NULL;
+ }
+ if (cluster_id < 0 || cluster_id >= ms->smp.clusters) {
+ error_setg(errp,
+ "Couldn't find cpu(%ld:%ld:%ld:%ld), Invalid cluster-id %ld",
+ socket_id, cluster_id, core_id, thread_id, cluster_id);
+ return NULL;
+ }
+ if (socket_id < 0 || socket_id >= ms->smp.sockets) {
+ error_setg(errp,
+ "Couldn't find cpu(%ld:%ld:%ld:%ld), Invalid socket-id %ld",
+ socket_id, cluster_id, core_id, thread_id, socket_id);
+ return NULL;
+ }
+
+ /* Compute logical CPU index: t + T*(c + C*(k + K*s)). */
+ T = ms->smp.threads;
+ C = ms->smp.cores;
+ K = ms->smp.clusters;
+ cpu_id = thread_id + T * (core_id + C * (cluster_id + K * socket_id));
+
+ cpu = machine_get_possible_cpu((int)cpu_id);
+ if (!cpu) {
+ error_setg(errp,
+ "Couldn't find cpu(%ld:%ld:%ld:%ld), Invalid cpu-index %ld",
+ socket_id, cluster_id, core_id, thread_id, cpu_id);
+ return NULL;
+ }
+
+ return DEVICE(cpu);
+}
+
+static DeviceState *
+virt_find_device(DeviceListener *listener, const QDict *opts, Error **errp)
+{
+ const char *typename;
+
+ g_assert(opts);
+
+ typename = qdict_get_try_str(opts, "driver");
+ if (!typename)
+ {
+ error_setg(errp, "no driver specified");
+ return NULL;
+ }
+
+ if (cpu_typename_is_a(typename, TYPE_ARM_CPU)) {
+ return virt_find_cpu(opts, errp);
+ }
+
+ return NULL;
+}
+
static void virt_park_cpu_in_userspace(CPUState *cs)
{
/* we don't want to migrate 'disabled' vCPU state(even if realized) */
@@ -2545,6 +2628,9 @@ static void machvirt_init(MachineState *machine)
create_fdt(vms);
+ vms->device_listener.find_device = virt_find_device;
+ device_listener_register(&vms->device_listener);
+
assert(possible_cpus->len == max_cpus);
for (n = 0; n < possible_cpus->len; n++) {
Object *cpuobj;
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 39e674aca2..6883dba75e 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -170,6 +170,18 @@ char *cpu_model_from_type(const char *typename)
return g_strdup(typename);
}
+bool cpu_typename_is_a(const char *typename, const char *base_typename)
+{
+ ObjectClass *oc;
+
+ if (!typename || !base_typename) {
+ return false;
+ }
+
+ oc = object_class_by_name(typename);
+ return oc && object_class_dynamic_cast(oc, base_typename);
+}
+
static void cpu_common_parse_features(const char *typename, char *features,
Error **errp)
{
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 3aba99b912..4fa2988ca0 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -226,6 +226,27 @@ bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp)
return false;
}
+DeviceState *
+qdev_find_device(const QDict *opts, Error **errp)
+{
+ ERRP_GUARD();
+ DeviceListener *listener;
+ DeviceState *dev;
+
+ QTAILQ_FOREACH(listener, &device_listeners, link) {
+ if (listener->find_device) {
+ dev = listener->find_device(listener, opts, errp);
+ if (*errp) {
+ return NULL;
+ } else if (dev) {
+ return dev;
+ }
+ }
+ }
+
+ return NULL;
+}
+
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
int required_for_version)
{
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 0898e8eed3..de4a08175e 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -182,6 +182,7 @@ struct VirtMachineState {
char *oem_table_id;
bool ns_el2_virt_timer_irq;
CXLState cxl_devices_state;
+ DeviceListener device_listener;
};
#define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index ccf5588011..c9ce9bbdaf 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -853,6 +853,17 @@ ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model);
*/
char *cpu_model_from_type(const char *typename);
+/**
+ * cpu_typename_is_a:
+ * @typename: QOM type name to check (e.g. "host-arm-cpu").
+ * @base_typename: Base QOM typename to test against (e.g. TYPE_ARM_CPU).
+ *
+ * Return: true if @typename names a class that is-a @base_typename, else false.
+ *
+ * Notes: Safe for common code; depends only on QOM (no target headers).
+ */
+bool cpu_typename_is_a(const char *typename, const char *base_typename);
+
/**
* cpu_create:
* @typename: The CPU type.
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 3e08cfb59f..19d1d1a144 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -371,6 +371,15 @@ struct DeviceListener {
*/
bool (*hide_device)(DeviceListener *listener, const QDict *device_opts,
bool from_json, Error **errp);
+ /*
+ * Used by qdev to find any device corresponding to the device opts
+ *
+ * Returns the `DeviceState` on sucess and NULL if device was not found.
+ * On errors, it returns NULL and errp is set
+ */
+ DeviceState * (*find_device)(DeviceListener *listener,
+ const QDict *device_opts,
+ Error **errp);
QTAILQ_ENTRY(DeviceListener) link;
};
@@ -1252,6 +1261,19 @@ void device_listener_unregister(DeviceListener *listener);
*/
bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp);
+/**
+ * qdev_find_device() - find the device
+ *
+ * @opts: options QDict
+ * @errp: pointer to error object
+ *
+ * Called when device state is toggled via qdev_device_state()
+ *
+ * Return: a DeviceState on success and NULL on failure
+ */
+DeviceState *
+qdev_find_device(const QDict *opts, Error **errp);
+
typedef enum MachineInitPhase {
/* current_machine is NULL. */
PHASE_NO_MACHINE,
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index ae116d9804..3e8c492c28 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -84,6 +84,7 @@ void hmp_change_medium(Monitor *mon, const char *device, const char *target,
void hmp_migrate(Monitor *mon, const QDict *qdict);
void hmp_device_add(Monitor *mon, const QDict *qdict);
void hmp_device_del(Monitor *mon, const QDict *qdict);
+void hmp_device_set(Monitor *mon, const QDict *qdict);
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict);
void hmp_netdev_add(Monitor *mon, const QDict *qdict);
void hmp_netdev_del(Monitor *mon, const QDict *qdict);
@@ -117,6 +118,7 @@ void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
void device_del_completion(ReadLineState *rs, int nb_args, const char *str);
+void device_set_completion(ReadLineState *rs, int nb_args, const char *str);
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str);
void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str);
void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str);
diff --git a/include/monitor/qdev.h b/include/monitor/qdev.h
index 1d57bf6577..b10040e27f 100644
--- a/include/monitor/qdev.h
+++ b/include/monitor/qdev.h
@@ -6,6 +6,36 @@
void hmp_info_qtree(Monitor *mon, const QDict *qdict);
void hmp_info_qdm(Monitor *mon, const QDict *qdict);
void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp);
+/**
+ * qmp_device_set:
+ * @qdict: Boxed arguments identifying the target device and property changes.
+ *
+ * The device can be identified in one of two ways:
+ * 1. By "id": Device instance ID (string), or
+ * 2. By "driver": Device type (string) plus one or more
+ * property=value pairs to match.
+ *
+ * Must also include at least one property assignment to change.
+ * Currently used for:
+ * - "admin-state": "enable" | "disable"
+ *
+ * Additional properties may be supported by specific devices
+ * in future.
+ *
+ * @errp: Pointer to error object (set on failure).
+ *
+ * Change one or more mutable properties of an existing device at runtime.
+ * Initially intended for administrative CPU power-state control via
+ * "admin-state" on CPU devices, but may be extended to support other
+ * per-device set/unset controls when allowed by the target device class.
+ *
+ * Returns: Nothing. On success, replies with `{ "return": true }` via QMP.
+ *
+ * Errors:
+ * - DeviceNotFound: No matching device found
+ * - GenericError: Parameter validation failed or operation unsupported
+ */
+void qmp_device_set(const QDict *qdict, Error **errp);
int qdev_device_help(QemuOpts *opts);
DeviceState *qdev_device_add(QemuOpts *opts, Error **errp);
diff --git a/include/system/system.h b/include/system/system.h
index a7effe7dfd..3702325cfb 100644
--- a/include/system/system.h
+++ b/include/system/system.h
@@ -116,6 +116,7 @@ extern QemuOptsList qemu_drive_opts;
extern QemuOptsList bdrv_runtime_opts;
extern QemuOptsList qemu_chardev_opts;
extern QemuOptsList qemu_device_opts;
+extern QemuOptsList qemu_deviceset_opts;
extern QemuOptsList qemu_netdev_opts;
extern QemuOptsList qemu_nic_opts;
extern QemuOptsList qemu_net_opts;
diff --git a/qemu-options.hx b/qemu-options.hx
index 83ccde341b..f517b91042 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -375,7 +375,10 @@ SRST
This is different from CPU hotplug where additional CPUs are not even
present in the system description. Administratively disabled CPUs appear in
ACPI tables i.e. are provisioned, but cannot be used until explicitly
- enabled via QMP/HMP or the deviceset API.
+ enabled via QMP/HMP or the deviceset API. On ACPI guests, each vCPU counted
+ by 'disabledcpus=' is provisioned with '\ ``_STA``\ ' reporting Present=1
+ and Enabled=0 (present-offline) at boot; it becomes Enabled=1 when brought
+ online via 'device_set ... admin-state=enable'.
On boards supporting CPU hotplug, the optional '\ ``maxcpus``\ ' parameter
can be set to enable further CPUs to be added at runtime. When both
@@ -455,6 +458,15 @@ SRST
-smp 2
+ Note: The cluster topology will only be generated in ACPI and exposed
+ to guest if it's explicitly specified in -smp.
+
+ Note: Administratively disabled CPUs (specified via 'disabledcpus=' and
+ '-deviceset' at CLI during boot) are especially useful for platforms like
+ ARM that lack native CPU hotplug support. These CPUs will appear to the
+ guest as unavailable, and any attempt to bring them online must go through
+ QMP/HMP commands like 'device_set'.
+
Examples using 'disabledcpus':
For a board without CPU hotplug, enable 4 CPUs at boot and provision
@@ -472,9 +484,6 @@ SRST
::
-smp cpus=4,disabledcpus=2,maxcpus=8
-
- Note: The cluster topology will only be generated in ACPI and exposed
- to guest if it's explicitly specified in -smp.
ERST
DEF("numa", HAS_ARG, QEMU_OPTION_numa,
@@ -1281,6 +1290,40 @@ SRST
ERST
+DEF("deviceset", HAS_ARG, QEMU_OPTION_deviceset,
+ "-deviceset driver[,prop[=value]][,...]\n"
+ " Set administrative power state of an existing device.\n"
+ " Does not hotplug a new device. Can disable or enable\n"
+ " devices (such as CPUs) at boot based on policy.\n"
+ " Example:\n"
+ " -deviceset host-arm-cpu,core-id=2,admin-state=disabled\n"
+ " Use '-deviceset help' for supported drivers\n"
+ " Use '-deviceset driver,help' for driver-specific properties\n",
+ QEMU_ARCH_ALL)
+SRST
+``-deviceset driver[,prop[=value]][,...]``
+ Configure an existing device's administrative power state or properties.
+
+ Unlike ``-device``, this option does not create a new device. Instead,
+ it sets startup properties (such as administrative power state) for
+ a device already declared via -smp or other machine configuration.
+
+ Example:
+ -smp cpus=4
+ -deviceset host-arm-cpu,core-id=2,admin-state=disabled
+
+ The above disables CPU core 2 at boot using administrative offlining.
+ The guest may later re-enable the core (if permitted by platform policy).
+
+ ``state=enabled|disabled``
+ Sets the administrative state of the device:
+ - ``enabled``: device is made available at boot
+ - ``disabled``: device is administratively disabled and powered off
+
+ Use ``-deviceset help`` to view all supported drivers.
+ Use ``-deviceset driver,help`` for property-specific help.
+ERST
+
DEF("name", HAS_ARG, QEMU_OPTION_name,
"-name string1[,process=string2][,debug-threads=on|off]\n"
" set the name of the guest\n"
diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c
index 2ac92d0a07..1099b1237d 100644
--- a/system/qdev-monitor.c
+++ b/system/qdev-monitor.c
@@ -263,12 +263,20 @@ static DeviceClass *qdev_get_device_class(const char **driver, Error **errp)
}
dc = DEVICE_CLASS(oc);
- if (!dc->user_creatable) {
+ if (!dc->user_creatable && !dc->admin_power_state_supported) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
"a pluggable device type");
return NULL;
}
+ if (phase_check(PHASE_MACHINE_READY) &&
+ (!dc->hotpluggable || !dc->admin_power_state_supported)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
+ "a pluggable device type or which supports changing power-"
+ "state administratively");
+ return NULL;
+ }
+
if (object_class_dynamic_cast(oc, TYPE_SYS_BUS_DEVICE)) {
/* sysbus devices need to be allowed by the machine */
MachineClass *mc = MACHINE_CLASS(object_get_class(qdev_get_machine()));
@@ -939,6 +947,76 @@ void qmp_device_del(const char *id, Error **errp)
}
}
+void qmp_device_set(const QDict *qdict, Error **errp)
+{
+ const char *state;
+ const char *driver;
+ DeviceState *dev;
+ DeviceClass *dc;
+ const char *id;
+
+ driver = qdict_get_try_str(qdict, "driver");
+ if (!driver) {
+ error_setg(errp, "Parameter 'driver' is missing");
+ return;
+ }
+
+ /* check driver exists and we are at the right phase of machine init */
+ dc = qdev_get_device_class(&driver, errp);
+ if (!dc) {
+ error_setg(errp, "driver '%s' not supported", driver);
+ return;
+ }
+
+ if (migration_is_running()) {
+ error_setg(errp, "device_set not allowed while migrating");
+ return;
+ }
+
+ id = qdict_get_try_str(qdict, "id");
+
+ if (id) {
+ /* Lookup by ID */
+ dev = find_device_state(id, false, errp);
+ if (errp && *errp) {
+ error_prepend(errp, "Device lookup failed for ID '%s': ", id);
+ return;
+ }
+ } else {
+ /* Lookup using driver and properties */
+ dev = qdev_find_device(qdict, errp);
+ if (errp && *errp) {
+ error_prepend(errp, "Device lookup for %s failed: ", driver);
+ return;
+ }
+ }
+ if (!dev) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "No device found for driver '%s'", driver);
+ return;
+ }
+
+ state = qdict_get_try_str(qdict, "admin-state");
+ if (!state) {
+ error_setg(errp, "no device state change specified for device %s ",
+ dev->id);
+ return;
+ } else if (!strcmp(state, "enable")) {
+
+ if (!qdev_enable(dev, qdev_get_parent_bus(DEVICE(dev)), errp)) {
+ return;
+ }
+ } else if (!strcmp(state, "disable")) {
+ if (!qdev_disable(dev, qdev_get_parent_bus(DEVICE(dev)), errp)) {
+ return;
+ }
+ } else {
+ error_setg(errp, "unrecognized specified state *%s* for device %s",
+ state, dev->id);
+ return;
+ }
+}
+
int qdev_sync_config(DeviceState *dev, Error **errp)
{
DeviceClass *dc = DEVICE_GET_CLASS(dev);
@@ -1019,6 +1097,14 @@ void hmp_device_del(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, err);
}
+void hmp_device_set(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+
+ qmp_device_set(qdict, &err);
+ hmp_handle_error(mon, err);
+}
+
void device_add_completion(ReadLineState *rs, int nb_args, const char *str)
{
GSList *list, *elt;
@@ -1101,6 +1187,41 @@ void device_del_completion(ReadLineState *rs, int nb_args, const char *str)
peripheral_device_del_completion(rs, str);
}
+void device_set_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ GSList *list, *elt;
+ size_t len;
+
+ if (nb_args == 2) {
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+
+ list = elt = object_class_get_list(TYPE_DEVICE, false);
+ while (elt) {
+ DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data,
+ TYPE_DEVICE);
+ readline_add_completion_of(
+ rs, str, object_class_get_name(OBJECT_CLASS(dc)));
+ elt = elt->next;
+ }
+ g_slist_free(list);
+ return;
+ }
+
+ if (nb_args == 3) {
+ readline_set_completion_index(rs, strlen(str));
+ readline_add_completion_of(rs, str, "admin-state");
+ return;
+ }
+
+ if (nb_args == 4) {
+ readline_set_completion_index(rs, strlen(str));
+ readline_add_completion_of(rs, str, "enable");
+ readline_add_completion_of(rs, str, "disable");
+ return;
+ }
+}
+
BlockBackend *blk_by_qdev_id(const char *id, Error **errp)
{
DeviceState *dev;
@@ -1134,6 +1255,22 @@ QemuOptsList qemu_device_opts = {
},
};
+QemuOptsList qemu_deviceset_opts = {
+ .name = "deviceset",
+ .implied_opt_name = "driver",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_deviceset_opts.head),
+ .desc = {
+ /*
+ * no fixed schema; parameters include:
+ * - driver=<device-name>
+ * - id=<device-id> (optional)
+ * - admin-state=enabled|disabled
+ * - other optional props for locating the device
+ */
+ { /* end of list */ }
+ },
+};
+
QemuOptsList qemu_global_opts = {
.name = "global",
.head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
diff --git a/system/vl.c b/system/vl.c
index 2f0fd21a1f..c1731de202 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -1218,6 +1218,16 @@ static int device_init_func(void *opaque, QemuOpts *opts, Error **errp)
return 0;
}
+static int deviceset_init_func(void *opaque, QemuOpts *opts, Error **errp)
+{
+ QDict *qdict = qemu_opts_to_qdict(opts, NULL);
+
+ qmp_device_set(qdict, errp);
+ qobject_unref(qdict);
+
+ return *errp ? -1 : 0;
+}
+
static int chardev_init_func(void *opaque, QemuOpts *opts, Error **errp)
{
Error *local_err = NULL;
@@ -2755,6 +2765,10 @@ static void qemu_create_cli_devices(void)
assert(ret_data == NULL); /* error_fatal aborts */
loc_pop(&opt->loc);
}
+
+ /* add deferred 'deviceset' list handling - common to JSON/non-JSON path */
+ qemu_opts_foreach(qemu_find_opts("deviceset"), deviceset_init_func, NULL,
+ &error_fatal);
}
static bool qemu_machine_creation_done(Error **errp)
@@ -2855,6 +2869,7 @@ void qemu_init(int argc, char **argv)
qemu_add_drive_opts(&bdrv_runtime_opts);
qemu_add_opts(&qemu_chardev_opts);
qemu_add_opts(&qemu_device_opts);
+ qemu_add_opts(&qemu_deviceset_opts);
qemu_add_opts(&qemu_netdev_opts);
qemu_add_opts(&qemu_nic_opts);
qemu_add_opts(&qemu_net_opts);
@@ -3458,6 +3473,30 @@ void qemu_init(int argc, char **argv)
}
}
break;
+ case QEMU_OPTION_deviceset:
+ if (optarg[0] == '{') {
+ /* JSON input: convert to QDict and then to QemuOpts */
+ QObject *obj = qobject_from_json(optarg, &error_fatal);
+ QDict *qdict = qobject_to(QDict, obj);
+ if (!qdict) {
+ error_report("Invalid JSON object for -deviceset");
+ exit(1);
+ }
+
+ opts = qemu_opts_from_qdict(qemu_find_opts("deviceset"),
+ qdict, &error_fatal);
+ qobject_unref(qdict);
+ if (!opts) {
+ error_report_err(error_fatal);
+ exit(1);
+ }
+ } else {
+ if (!qemu_opts_parse_noisily(qemu_find_opts("deviceset"),
+ optarg, true)) {
+ exit(1);
+ }
+ }
+ break;
case QEMU_OPTION_smp:
machine_parse_property_opt(qemu_find_opts("smp-opts"),
"smp", optarg);
--
2.34.1
salil.mehta@opnsrc.net writes:
> From: Salil Mehta <salil.mehta@huawei.com>
>
> This patch adds a "device_set" interface for modifying properties of devices
> that already exist in the guest topology. Unlike 'device_add'/'device_del'
> (hot-plug), 'device_set' does not create or destroy devices. It is intended
> for guest-visible hot-add semantics where hardware is provisioned at boot but
> logically enabled/disabled later via administrative policy.
>
> Compared to the existing 'qom-set' command, which is less intuitive and works
> only with object IDs, device_set provides a more device-oriented interface.
> It can be invoked at the QEMU prompt using natural device arguments, and the
> new '-deviceset' CLI option allows properties to be set at boot time, similar
> to how '-device' specifies device creation.
Why can't we use -device?
> While the initial implementation focuses on "admin-state" changes (e.g.,
> enable/disable a CPU already described by ACPI/DT), the interface is designed
> to be generic. In future, it could be used for other per-device set/unset
> style controls — beyond administrative power-states — provided the target
> device explicitly allows such changes. This enables fine-grained runtime
> control of device properties.
Beware, designing a generic interface can be harder, sometimes much
harder, than designing a specialized one.
device_add and qom-set are generic, and they have issues:
* device_add effectively bypasses QAPI by using 'gen': false.
This bypasses QAPI's enforcement of documentation. Property
documentation is separate and poor.
It also defeats introspection with query-qmp-schema. You need to
resort to other means instead, say QOM introspection (which is a bag
of design flaws on its own), then map from QOM to qdev.
* device_add lets you specify any qdev property, even properties that
are intended only for use by C code.
This results in accidental external interfaces.
We tend to name properties like "x-prop" to discourage external use,
but I wouldn't bet my own money on us getting that always right.
Moreover, there's beauties like "x-origin".
* qom-set & friends effectively bypass QAPI by using type 'any'.
Again, the bypass results in poor documentation and a defeat of
query-qmp-schema.
* qom-set lets you mess with any QOM property with a setter callback.
Again, accidental external interfaces: most of these properties are
not meant for use with qom-set. For some, qom-set works, for some it
silently does nothing, and for some it crashes. A lot more dangerous
than device_add.
The "x-" convention can't help here: some properties are intended for
external use with object-add, but not with qom-set.
We should avoid such issues in new interfaces.
We'll examine how this applies to device_set when I review the QAPI
schema.
> Key pieces:
> * QMP: qmp_device_set() to update an existing device. The device can be
> located by "id" or via driver+property match using a DeviceListener
> callback (qdev_find_device()).
> * HMP: "device_set" command with tab-completion. Errors are surfaced via
> hmp_handle_error().
> * CLI: "-deviceset" option for setting startup/admin properties at boot,
> including a JSON form. Options are parsed into qemu_deviceset_opts and
> applied after device creation.
> * Docs/help: HMP help text and qemu-options.hx additions explain usage and
> explicitly note that no hot-plug occurs.
> * Safety: disallowed during live migration (migration_is_idle() check).
>
> Semantics:
> * Operates on an existing DeviceState; no enumeration/new device appears.
> * Complements device_add/device_del by providing state mutation only.
> * Backward compatible: no behavior change unless "device_set"/"-deviceset"
> is used.
>
> Examples:
> HMP:
> (qemu) device_set host-arm-cpu,core-id=3,admin-state=enable
>
> CLI (at boot):
> -smp cpus=4,maxcpus=4 \
> -deviceset host-arm-cpu,core-id=2,admin-state=disable
>
> QMP (JSON form):
> { "execute": "device_set",
> "arguments": {
> "driver": "host-arm-cpu",
> "core-id": 1,
> "admin-state": "disable"
> }
> }
{"error": {"class": "CommandNotFound", "desc": "The command device_set has not been found"}}
Clue below.
> NOTE: The qdev_enable()/qdev_disable() hooks for acting on admin-state will be
> added in subsequent patches. Device classes must explicitly support any
> property they want to expose through device_set.
>
> Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
> ---
> hmp-commands.hx | 30 +++++++++
> hw/arm/virt.c | 86 +++++++++++++++++++++++++
> hw/core/cpu-common.c | 12 ++++
> hw/core/qdev.c | 21 ++++++
> include/hw/arm/virt.h | 1 +
> include/hw/core/cpu.h | 11 ++++
> include/hw/qdev-core.h | 22 +++++++
> include/monitor/hmp.h | 2 +
> include/monitor/qdev.h | 30 +++++++++
> include/system/system.h | 1 +
> qemu-options.hx | 51 +++++++++++++--
> system/qdev-monitor.c | 139 +++++++++++++++++++++++++++++++++++++++-
> system/vl.c | 39 +++++++++++
> 13 files changed, 440 insertions(+), 5 deletions(-)
Clue: no update to the QAPI schema, i.e. the QMP command does not exist.
>
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index d0e4f35a30..18056cf21d 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -707,6 +707,36 @@ SRST
> or a QOM object path.
> ERST
>
> +{
> + .name = "device_set",
> + .args_type = "device:O",
> + .params = "driver[,prop=value][,...]",
> + .help = "set/unset existing device property",
> + .cmd = hmp_device_set,
> + .command_completion = device_set_completion,
> +},
> +
> +SRST
> +``device_set`` *driver[,prop=value][,...]*
> + Change the administrative power state of an existing device.
> +
> + This command enables or disables a known device (e.g., CPU) using the
> + "device_set" interface. It does not hotplug or add a new device.
> +
> + Depending on platform support (e.g., PSCI or ACPI), this may trigger
> + corresponding operational changes — such as powering down a CPU or
> + transitioning it to active use.
> +
> + Administrative state:
> + * *enabled* — Allows the guest to use the device (e.g., CPU_ON)
> + * *disabled* — Prevents guest use; device is powered off (e.g., CPU_OFF)
> +
> + Note: The device must already exist (be declared during machine creation).
> +
> + Example:
> + (qemu) device_set host-arm-cpu,core-id=3,admin-state=disabled
> +ERST
How exactly is the device selected? You provide a clue above: 'can be
located by "id" or via driver+property match'.
I assume by "id" is just like device_del, i.e. by qdev ID or QOM path.
By "driver+property match" is not obvious. Which of the arguments are
for matching, and which are for setting?
If "id" is specified, is there any matching?
The matching feature complicates this interface quite a bit. I doubt
it's worth the complexity. If you think it is, please split it off into
a separate patch.
Next question. Is there a way for management applications to detect
whether a certain device supports device_set for a certain property?
Without that, what are management application supposed to do? Hard-code
what works? Run the command and see whether it fails?
I understand right now the command supports just "admin-state" for a
certain set of devices, so hard-coding would be possible. But every new
(device, property) pair then requires management application updates,
and the hard-coded information becomes version specific. This will
become unworkable real quick. Not good enough for a command designed to
be generic.
> +
> {
> .name = "cpu",
> .args_type = "index:i",
[...]
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 83ccde341b..f517b91042 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -375,7 +375,10 @@ SRST
> This is different from CPU hotplug where additional CPUs are not even
> present in the system description. Administratively disabled CPUs appear in
> ACPI tables i.e. are provisioned, but cannot be used until explicitly
> - enabled via QMP/HMP or the deviceset API.
> + enabled via QMP/HMP or the deviceset API. On ACPI guests, each vCPU counted
> + by 'disabledcpus=' is provisioned with '\ ``_STA``\ ' reporting Present=1
> + and Enabled=0 (present-offline) at boot; it becomes Enabled=1 when brought
> + online via 'device_set ... admin-state=enable'.
>
> On boards supporting CPU hotplug, the optional '\ ``maxcpus``\ ' parameter
> can be set to enable further CPUs to be added at runtime. When both
> @@ -455,6 +458,15 @@ SRST
>
> -smp 2
>
> + Note: The cluster topology will only be generated in ACPI and exposed
> + to guest if it's explicitly specified in -smp.
> +
> + Note: Administratively disabled CPUs (specified via 'disabledcpus=' and
> + '-deviceset' at CLI during boot) are especially useful for platforms like
> + ARM that lack native CPU hotplug support. These CPUs will appear to the
> + guest as unavailable, and any attempt to bring them online must go through
> + QMP/HMP commands like 'device_set'.
> +
> Examples using 'disabledcpus':
>
> For a board without CPU hotplug, enable 4 CPUs at boot and provision
> @@ -472,9 +484,6 @@ SRST
> ::
>
> -smp cpus=4,disabledcpus=2,maxcpus=8
> -
> - Note: The cluster topology will only be generated in ACPI and exposed
> - to guest if it's explicitly specified in -smp.
> ERST
>
> DEF("numa", HAS_ARG, QEMU_OPTION_numa,
> @@ -1281,6 +1290,40 @@ SRST
>
> ERST
>
> +DEF("deviceset", HAS_ARG, QEMU_OPTION_deviceset,
> + "-deviceset driver[,prop[=value]][,...]\n"
> + " Set administrative power state of an existing device.\n"
> + " Does not hotplug a new device. Can disable or enable\n"
> + " devices (such as CPUs) at boot based on policy.\n"
> + " Example:\n"
> + " -deviceset host-arm-cpu,core-id=2,admin-state=disabled\n"
> + " Use '-deviceset help' for supported drivers\n"
> + " Use '-deviceset driver,help' for driver-specific properties\n",
> + QEMU_ARCH_ALL)
> +SRST
> +``-deviceset driver[,prop[=value]][,...]``
> + Configure an existing device's administrative power state or properties.
> +
> + Unlike ``-device``, this option does not create a new device. Instead,
> + it sets startup properties (such as administrative power state) for
> + a device already declared via -smp or other machine configuration.
> +
> + Example:
> + -smp cpus=4
> + -deviceset host-arm-cpu,core-id=2,admin-state=disabled
> +
> + The above disables CPU core 2 at boot using administrative offlining.
> + The guest may later re-enable the core (if permitted by platform policy).
> +
> + ``state=enabled|disabled``
> + Sets the administrative state of the device:
> + - ``enabled``: device is made available at boot
> + - ``disabled``: device is administratively disabled and powered off
> +
> + Use ``-deviceset help`` to view all supported drivers.
> + Use ``-deviceset driver,help`` for property-specific help.
> +ERST
> +
> DEF("name", HAS_ARG, QEMU_OPTION_name,
> "-name string1[,process=string2][,debug-threads=on|off]\n"
> " set the name of the guest\n"
> diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c
> index 2ac92d0a07..1099b1237d 100644
> --- a/system/qdev-monitor.c
> +++ b/system/qdev-monitor.c
> @@ -263,12 +263,20 @@ static DeviceClass *qdev_get_device_class(const char **driver, Error **errp)
> }
>
> dc = DEVICE_CLASS(oc);
> - if (!dc->user_creatable) {
> + if (!dc->user_creatable && !dc->admin_power_state_supported) {
> error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
> "a pluggable device type");
> return NULL;
> }
>
> + if (phase_check(PHASE_MACHINE_READY) &&
> + (!dc->hotpluggable || !dc->admin_power_state_supported)) {
> + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
> + "a pluggable device type or which supports changing power-"
> + "state administratively");
> + return NULL;
> + }
> +
> if (object_class_dynamic_cast(oc, TYPE_SYS_BUS_DEVICE)) {
> /* sysbus devices need to be allowed by the machine */
> MachineClass *mc = MACHINE_CLASS(object_get_class(qdev_get_machine()));
> @@ -939,6 +947,76 @@ void qmp_device_del(const char *id, Error **errp)
> }
> }
>
> +void qmp_device_set(const QDict *qdict, Error **errp)
> +{
> + const char *state;
> + const char *driver;
> + DeviceState *dev;
> + DeviceClass *dc;
> + const char *id;
> +
> + driver = qdict_get_try_str(qdict, "driver");
> + if (!driver) {
> + error_setg(errp, "Parameter 'driver' is missing");
> + return;
> + }
> +
> + /* check driver exists and we are at the right phase of machine init */
> + dc = qdev_get_device_class(&driver, errp);
> + if (!dc) {
Since qdev_get_device_class() sets an error when it fails, *errp is not
null here, ...
> + error_setg(errp, "driver '%s' not supported", driver);
... which makes this wrong. Caught by error_setv()'s assertion.
Please test your error paths.
> + return;
> + }
> +
> + if (migration_is_running()) {
> + error_setg(errp, "device_set not allowed while migrating");
> + return;
> + }
> +
> + id = qdict_get_try_str(qdict, "id");
> +
> + if (id) {
> + /* Lookup by ID */
> + dev = find_device_state(id, false, errp);
> + if (errp && *errp) {
> + error_prepend(errp, "Device lookup failed for ID '%s': ", id);
> + return;
> + }
> + } else {
> + /* Lookup using driver and properties */
> + dev = qdev_find_device(qdict, errp);
> + if (errp && *errp) {
> + error_prepend(errp, "Device lookup for %s failed: ", driver);
> + return;
> + }
> + }
> + if (!dev) {
> + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
> + "No device found for driver '%s'", driver);
> + return;
> + }
> +
> + state = qdict_get_try_str(qdict, "admin-state");
> + if (!state) {
> + error_setg(errp, "no device state change specified for device %s ",
> + dev->id);
> + return;
> + } else if (!strcmp(state, "enable")) {
> +
> + if (!qdev_enable(dev, qdev_get_parent_bus(DEVICE(dev)), errp)) {
> + return;
> + }
> + } else if (!strcmp(state, "disable")) {
> + if (!qdev_disable(dev, qdev_get_parent_bus(DEVICE(dev)), errp)) {
> + return;
> + }
> + } else {
> + error_setg(errp, "unrecognized specified state *%s* for device %s",
> + state, dev->id);
> + return;
> + }
> +}
> +
> int qdev_sync_config(DeviceState *dev, Error **errp)
> {
> DeviceClass *dc = DEVICE_GET_CLASS(dev);
[...]
On Thu, 09 Oct 2025 10:55:40 +0200
Markus Armbruster <armbru@redhat.com> wrote:
> salil.mehta@opnsrc.net writes:
>
> > From: Salil Mehta <salil.mehta@huawei.com>
> >
> > This patch adds a "device_set" interface for modifying properties of devices
> > that already exist in the guest topology. Unlike 'device_add'/'device_del'
> > (hot-plug), 'device_set' does not create or destroy devices. It is intended
> > for guest-visible hot-add semantics where hardware is provisioned at boot but
> > logically enabled/disabled later via administrative policy.
> >
> > Compared to the existing 'qom-set' command, which is less intuitive and works
> > only with object IDs, device_set provides a more device-oriented interface.
> > It can be invoked at the QEMU prompt using natural device arguments, and the
> > new '-deviceset' CLI option allows properties to be set at boot time, similar
> > to how '-device' specifies device creation.
>
> Why can't we use -device?
that's was my concern/suggestion in reply to cover letter
(as a place to put high level review and what can be done for the next revision)
(PS: It looks like I'm having email receiving issues (i.e. not getting from
mail list my own emails that it bonces to me, so threading is all broken on
my side and I'm might miss replies). But on positive side it looks like my
replies reach the list and CCed just fine)
> > While the initial implementation focuses on "admin-state" changes (e.g.,
> > enable/disable a CPU already described by ACPI/DT), the interface is designed
> > to be generic. In future, it could be used for other per-device set/unset
> > style controls — beyond administrative power-states — provided the target
> > device explicitly allows such changes. This enables fine-grained runtime
> > control of device properties.
>
> Beware, designing a generic interface can be harder, sometimes much
> harder, than designing a specialized one.
>
> device_add and qom-set are generic, and they have issues:
>
> * device_add effectively bypasses QAPI by using 'gen': false.
>
> This bypasses QAPI's enforcement of documentation. Property
> documentation is separate and poor.
>
> It also defeats introspection with query-qmp-schema. You need to
> resort to other means instead, say QOM introspection (which is a bag
> of design flaws on its own), then map from QOM to qdev.
>
> * device_add lets you specify any qdev property, even properties that
> are intended only for use by C code.
>
> This results in accidental external interfaces.
>
> We tend to name properties like "x-prop" to discourage external use,
> but I wouldn't bet my own money on us getting that always right.
> Moreover, there's beauties like "x-origin".
>
> * qom-set & friends effectively bypass QAPI by using type 'any'.
>
> Again, the bypass results in poor documentation and a defeat of
> query-qmp-schema.
>
> * qom-set lets you mess with any QOM property with a setter callback.
>
> Again, accidental external interfaces: most of these properties are
> not meant for use with qom-set. For some, qom-set works, for some it
> silently does nothing, and for some it crashes. A lot more dangerous
> than device_add.
>
> The "x-" convention can't help here: some properties are intended for
> external use with object-add, but not with qom-set.
>
> We should avoid such issues in new interfaces.
>
> We'll examine how this applies to device_set when I review the QAPI
> schema.
>
> > Key pieces:
> > * QMP: qmp_device_set() to update an existing device. The device can be
> > located by "id" or via driver+property match using a DeviceListener
> > callback (qdev_find_device()).
> > * HMP: "device_set" command with tab-completion. Errors are surfaced via
> > hmp_handle_error().
> > * CLI: "-deviceset" option for setting startup/admin properties at boot,
> > including a JSON form. Options are parsed into qemu_deviceset_opts and
> > applied after device creation.
> > * Docs/help: HMP help text and qemu-options.hx additions explain usage and
> > explicitly note that no hot-plug occurs.
> > * Safety: disallowed during live migration (migration_is_idle() check).
> >
> > Semantics:
> > * Operates on an existing DeviceState; no enumeration/new device appears.
> > * Complements device_add/device_del by providing state mutation only.
> > * Backward compatible: no behavior change unless "device_set"/"-deviceset"
> > is used.
> >
> > Examples:
> > HMP:
> > (qemu) device_set host-arm-cpu,core-id=3,admin-state=enable
> >
> > CLI (at boot):
> > -smp cpus=4,maxcpus=4 \
> > -deviceset host-arm-cpu,core-id=2,admin-state=disable
> >
> > QMP (JSON form):
> > { "execute": "device_set",
> > "arguments": {
> > "driver": "host-arm-cpu",
> > "core-id": 1,
> > "admin-state": "disable"
> > }
> > }
>
> {"error": {"class": "CommandNotFound", "desc": "The command device_set has not been found"}}
>
> Clue below.
>
> > NOTE: The qdev_enable()/qdev_disable() hooks for acting on admin-state will be
> > added in subsequent patches. Device classes must explicitly support any
> > property they want to expose through device_set.
> >
> > Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
> > ---
> > hmp-commands.hx | 30 +++++++++
> > hw/arm/virt.c | 86 +++++++++++++++++++++++++
> > hw/core/cpu-common.c | 12 ++++
> > hw/core/qdev.c | 21 ++++++
> > include/hw/arm/virt.h | 1 +
> > include/hw/core/cpu.h | 11 ++++
> > include/hw/qdev-core.h | 22 +++++++
> > include/monitor/hmp.h | 2 +
> > include/monitor/qdev.h | 30 +++++++++
> > include/system/system.h | 1 +
> > qemu-options.hx | 51 +++++++++++++--
> > system/qdev-monitor.c | 139 +++++++++++++++++++++++++++++++++++++++-
> > system/vl.c | 39 +++++++++++
> > 13 files changed, 440 insertions(+), 5 deletions(-)
>
> Clue: no update to the QAPI schema, i.e. the QMP command does not exist.
>
> >
> > diff --git a/hmp-commands.hx b/hmp-commands.hx
> > index d0e4f35a30..18056cf21d 100644
> > --- a/hmp-commands.hx
> > +++ b/hmp-commands.hx
> > @@ -707,6 +707,36 @@ SRST
> > or a QOM object path.
> > ERST
> >
> > +{
> > + .name = "device_set",
> > + .args_type = "device:O",
> > + .params = "driver[,prop=value][,...]",
> > + .help = "set/unset existing device property",
> > + .cmd = hmp_device_set,
> > + .command_completion = device_set_completion,
> > +},
> > +
> > +SRST
> > +``device_set`` *driver[,prop=value][,...]*
> > + Change the administrative power state of an existing device.
> > +
> > + This command enables or disables a known device (e.g., CPU) using the
> > + "device_set" interface. It does not hotplug or add a new device.
> > +
> > + Depending on platform support (e.g., PSCI or ACPI), this may trigger
> > + corresponding operational changes — such as powering down a CPU or
> > + transitioning it to active use.
> > +
> > + Administrative state:
> > + * *enabled* — Allows the guest to use the device (e.g., CPU_ON)
> > + * *disabled* — Prevents guest use; device is powered off (e.g., CPU_OFF)
> > +
> > + Note: The device must already exist (be declared during machine creation).
> > +
> > + Example:
> > + (qemu) device_set host-arm-cpu,core-id=3,admin-state=disabled
> > +ERST
>
> How exactly is the device selected? You provide a clue above: 'can be
> located by "id" or via driver+property match'.
>
> I assume by "id" is just like device_del, i.e. by qdev ID or QOM path.
>
> By "driver+property match" is not obvious. Which of the arguments are
> for matching, and which are for setting?
>
> If "id" is specified, is there any matching?
>
> The matching feature complicates this interface quite a bit. I doubt
> it's worth the complexity. If you think it is, please split it off into
> a separate patch.
It's likely /me who to blame for asking to invent generic
device-set QMP command.
I see another application (beside ARM CPU power-on/off) for it,
PCI devices to simulate powering on/off them at runtime without
actually removing device.
wrt command,
I'd use only 'id' with it to identify target device
(i.e. no template matching nor QMP path either).
To enforce rule, what user hasn't named explicitly by providing 'id'
isn't meant to be accessed/manged by user later on.
potentially we can invent specialized power_set/get command as
an alternative if it makes design easier.
But then we would be spawning similar commands for other things,
where as device-set would cover it all. But then I might be
over-complicating things by suggesting a generic approach.
> Next question. Is there a way for management applications to detect
> whether a certain device supports device_set for a certain property?
is there some kind of QMP command to check what does a device support,
or at least what properties it supports? Can we piggy-back on that?
>
> Without that, what are management application supposed to do? Hard-code
> what works? Run the command and see whether it fails?
Adding libvirt list to discussion and possible ideas on what can be done here.
> I understand right now the command supports just "admin-state" for a
> certain set of devices, so hard-coding would be possible. But every new
> (device, property) pair then requires management application updates,
> and the hard-coded information becomes version specific. This will
> become unworkable real quick. Not good enough for a command designed to
> be generic.
>
> > +
> > {
> > .name = "cpu",
> > .args_type = "index:i",
We still do have a few legacy uses of cpu index (CLI|HMP), but
I'd avoid using cpu index or something similar in new interfaces.
> [...]
>
> > diff --git a/qemu-options.hx b/qemu-options.hx
> > index 83ccde341b..f517b91042 100644
> > --- a/qemu-options.hx
> > +++ b/qemu-options.hx
> > @@ -375,7 +375,10 @@ SRST
> > This is different from CPU hotplug where additional CPUs are not even
> > present in the system description. Administratively disabled CPUs appear in
> > ACPI tables i.e. are provisioned, but cannot be used until explicitly
> > - enabled via QMP/HMP or the deviceset API.
> > + enabled via QMP/HMP or the deviceset API. On ACPI guests, each vCPU counted
> > + by 'disabledcpus=' is provisioned with '\ ``_STA``\ ' reporting Present=1
> > + and Enabled=0 (present-offline) at boot; it becomes Enabled=1 when brought
> > + online via 'device_set ... admin-state=enable'.
> >
> > On boards supporting CPU hotplug, the optional '\ ``maxcpus``\ ' parameter
> > can be set to enable further CPUs to be added at runtime. When both
> > @@ -455,6 +458,15 @@ SRST
> >
> > -smp 2
> >
> > + Note: The cluster topology will only be generated in ACPI and exposed
> > + to guest if it's explicitly specified in -smp.
> > +
> > + Note: Administratively disabled CPUs (specified via 'disabledcpus=' and
> > + '-deviceset' at CLI during boot) are especially useful for platforms like
> > + ARM that lack native CPU hotplug support. These CPUs will appear to the
> > + guest as unavailable, and any attempt to bring them online must go through
> > + QMP/HMP commands like 'device_set'.
> > +
> > Examples using 'disabledcpus':
> >
> > For a board without CPU hotplug, enable 4 CPUs at boot and provision
> > @@ -472,9 +484,6 @@ SRST
> > ::
> >
> > -smp cpus=4,disabledcpus=2,maxcpus=8
> > -
> > - Note: The cluster topology will only be generated in ACPI and exposed
> > - to guest if it's explicitly specified in -smp.
> > ERST
> >
> > DEF("numa", HAS_ARG, QEMU_OPTION_numa,
> > @@ -1281,6 +1290,40 @@ SRST
> >
> > ERST
> >
> > +DEF("deviceset", HAS_ARG, QEMU_OPTION_deviceset,
> > + "-deviceset driver[,prop[=value]][,...]\n"
> > + " Set administrative power state of an existing device.\n"
> > + " Does not hotplug a new device. Can disable or enable\n"
> > + " devices (such as CPUs) at boot based on policy.\n"
> > + " Example:\n"
> > + " -deviceset host-arm-cpu,core-id=2,admin-state=disabled\n"
> > + " Use '-deviceset help' for supported drivers\n"
> > + " Use '-deviceset driver,help' for driver-specific properties\n",
> > + QEMU_ARCH_ALL)
> > +SRST
> > +``-deviceset driver[,prop[=value]][,...]``
> > + Configure an existing device's administrative power state or properties.
> > +
> > + Unlike ``-device``, this option does not create a new device. Instead,
> > + it sets startup properties (such as administrative power state) for
> > + a device already declared via -smp or other machine configuration.
> > +
> > + Example:
> > + -smp cpus=4
> > + -deviceset host-arm-cpu,core-id=2,admin-state=disabled
> > +
> > + The above disables CPU core 2 at boot using administrative offlining.
> > + The guest may later re-enable the core (if permitted by platform policy).
> > +
> > + ``state=enabled|disabled``
> > + Sets the administrative state of the device:
> > + - ``enabled``: device is made available at boot
> > + - ``disabled``: device is administratively disabled and powered off
> > +
> > + Use ``-deviceset help`` to view all supported drivers.
> > + Use ``-deviceset driver,help`` for property-specific help.
> > +ERST
> > +
> > DEF("name", HAS_ARG, QEMU_OPTION_name,
> > "-name string1[,process=string2][,debug-threads=on|off]\n"
> > " set the name of the guest\n"
> > diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c
> > index 2ac92d0a07..1099b1237d 100644
> > --- a/system/qdev-monitor.c
> > +++ b/system/qdev-monitor.c
> > @@ -263,12 +263,20 @@ static DeviceClass *qdev_get_device_class(const char **driver, Error **errp)
> > }
> >
> > dc = DEVICE_CLASS(oc);
> > - if (!dc->user_creatable) {
> > + if (!dc->user_creatable && !dc->admin_power_state_supported) {
> > error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
> > "a pluggable device type");
> > return NULL;
> > }
> >
> > + if (phase_check(PHASE_MACHINE_READY) &&
> > + (!dc->hotpluggable || !dc->admin_power_state_supported)) {
> > + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
> > + "a pluggable device type or which supports changing power-"
> > + "state administratively");
> > + return NULL;
> > + }
> > +
> > if (object_class_dynamic_cast(oc, TYPE_SYS_BUS_DEVICE)) {
> > /* sysbus devices need to be allowed by the machine */
> > MachineClass *mc = MACHINE_CLASS(object_get_class(qdev_get_machine()));
> > @@ -939,6 +947,76 @@ void qmp_device_del(const char *id, Error **errp)
> > }
> > }
> >
> > +void qmp_device_set(const QDict *qdict, Error **errp)
> > +{
> > + const char *state;
> > + const char *driver;
> > + DeviceState *dev;
> > + DeviceClass *dc;
> > + const char *id;
> > +
> > + driver = qdict_get_try_str(qdict, "driver");
> > + if (!driver) {
> > + error_setg(errp, "Parameter 'driver' is missing");
> > + return;
> > + }
> > +
> > + /* check driver exists and we are at the right phase of machine init */
> > + dc = qdev_get_device_class(&driver, errp);
> > + if (!dc) {
>
> Since qdev_get_device_class() sets an error when it fails, *errp is not
> null here, ...
>
> > + error_setg(errp, "driver '%s' not supported", driver);
>
> ... which makes this wrong. Caught by error_setv()'s assertion.
>
> Please test your error paths.
>
> > + return;
> > + }
> > +
> > + if (migration_is_running()) {
> > + error_setg(errp, "device_set not allowed while migrating");
> > + return;
> > + }
> > +
> > + id = qdict_get_try_str(qdict, "id");
> > +
> > + if (id) {
> > + /* Lookup by ID */
> > + dev = find_device_state(id, false, errp);
> > + if (errp && *errp) {
> > + error_prepend(errp, "Device lookup failed for ID '%s': ", id);
> > + return;
> > + }
> > + } else {
> > + /* Lookup using driver and properties */
> > + dev = qdev_find_device(qdict, errp);
> > + if (errp && *errp) {
> > + error_prepend(errp, "Device lookup for %s failed: ", driver);
> > + return;
> > + }
> > + }
> > + if (!dev) {
> > + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
> > + "No device found for driver '%s'", driver);
> > + return;
> > + }
> > +
> > + state = qdict_get_try_str(qdict, "admin-state");
> > + if (!state) {
> > + error_setg(errp, "no device state change specified for device %s ",
> > + dev->id);
> > + return;
> > + } else if (!strcmp(state, "enable")) {
> > +
> > + if (!qdev_enable(dev, qdev_get_parent_bus(DEVICE(dev)), errp)) {
> > + return;
> > + }
> > + } else if (!strcmp(state, "disable")) {
> > + if (!qdev_disable(dev, qdev_get_parent_bus(DEVICE(dev)), errp)) {
> > + return;
> > + }
> > + } else {
> > + error_setg(errp, "unrecognized specified state *%s* for device %s",
> > + state, dev->id);
> > + return;
> > + }
> > +}
> > +
> > int qdev_sync_config(DeviceState *dev, Error **errp)
> > {
> > DeviceClass *dc = DEVICE_GET_CLASS(dev);
>
> [...]
>
Igor Mammedov <imammedo@redhat.com> writes:
> On Thu, 09 Oct 2025 10:55:40 +0200
> Markus Armbruster <armbru@redhat.com> wrote:
>
>> salil.mehta@opnsrc.net writes:
>>
>> > From: Salil Mehta <salil.mehta@huawei.com>
>> >
>> > This patch adds a "device_set" interface for modifying properties of devices
>> > that already exist in the guest topology. Unlike 'device_add'/'device_del'
>> > (hot-plug), 'device_set' does not create or destroy devices. It is intended
>> > for guest-visible hot-add semantics where hardware is provisioned at boot but
>> > logically enabled/disabled later via administrative policy.
>> >
>> > Compared to the existing 'qom-set' command, which is less intuitive and works
>> > only with object IDs, device_set provides a more device-oriented interface.
>> > It can be invoked at the QEMU prompt using natural device arguments, and the
>> > new '-deviceset' CLI option allows properties to be set at boot time, similar
>> > to how '-device' specifies device creation.
>>
>> Why can't we use -device?
>
> that's was my concern/suggestion in reply to cover letter
> (as a place to put high level review and what can be done for the next revision)
Yes.
> (PS: It looks like I'm having email receiving issues (i.e. not getting from
> mail list my own emails that it bonces to me, so threading is all broken on
> my side and I'm might miss replies). But on positive side it looks like my
> replies reach the list and CCed just fine)
For what it's worth, your replies arrive fine here.
>> > While the initial implementation focuses on "admin-state" changes (e.g.,
>> > enable/disable a CPU already described by ACPI/DT), the interface is designed
>> > to be generic. In future, it could be used for other per-device set/unset
>> > style controls — beyond administrative power-states — provided the target
>> > device explicitly allows such changes. This enables fine-grained runtime
>> > control of device properties.
>>
>> Beware, designing a generic interface can be harder, sometimes much
>> harder, than designing a specialized one.
>>
>> device_add and qom-set are generic, and they have issues:
>>
>> * device_add effectively bypasses QAPI by using 'gen': false.
>>
>> This bypasses QAPI's enforcement of documentation. Property
>> documentation is separate and poor.
>>
>> It also defeats introspection with query-qmp-schema. You need to
>> resort to other means instead, say QOM introspection (which is a bag
>> of design flaws on its own), then map from QOM to qdev.
>>
>> * device_add lets you specify any qdev property, even properties that
>> are intended only for use by C code.
>>
>> This results in accidental external interfaces.
>>
>> We tend to name properties like "x-prop" to discourage external use,
>> but I wouldn't bet my own money on us getting that always right.
>> Moreover, there's beauties like "x-origin".
>>
>> * qom-set & friends effectively bypass QAPI by using type 'any'.
>>
>> Again, the bypass results in poor documentation and a defeat of
>> query-qmp-schema.
>>
>> * qom-set lets you mess with any QOM property with a setter callback.
>>
>> Again, accidental external interfaces: most of these properties are
>> not meant for use with qom-set. For some, qom-set works, for some it
>> silently does nothing, and for some it crashes. A lot more dangerous
>> than device_add.
>>
>> The "x-" convention can't help here: some properties are intended for
>> external use with object-add, but not with qom-set.
>>
>> We should avoid such issues in new interfaces.
[...]
>> > diff --git a/hmp-commands.hx b/hmp-commands.hx
>> > index d0e4f35a30..18056cf21d 100644
>> > --- a/hmp-commands.hx
>> > +++ b/hmp-commands.hx
>> > @@ -707,6 +707,36 @@ SRST
>> > or a QOM object path.
>> > ERST
>> >
>> > +{
>> > + .name = "device_set",
>> > + .args_type = "device:O",
>> > + .params = "driver[,prop=value][,...]",
>> > + .help = "set/unset existing device property",
>> > + .cmd = hmp_device_set,
>> > + .command_completion = device_set_completion,
>> > +},
>> > +
>> > +SRST
>> > +``device_set`` *driver[,prop=value][,...]*
>> > + Change the administrative power state of an existing device.
>> > +
>> > + This command enables or disables a known device (e.g., CPU) using the
>> > + "device_set" interface. It does not hotplug or add a new device.
>> > +
>> > + Depending on platform support (e.g., PSCI or ACPI), this may trigger
>> > + corresponding operational changes — such as powering down a CPU or
>> > + transitioning it to active use.
>> > +
>> > + Administrative state:
>> > + * *enabled* — Allows the guest to use the device (e.g., CPU_ON)
>> > + * *disabled* — Prevents guest use; device is powered off (e.g., CPU_OFF)
>> > +
>> > + Note: The device must already exist (be declared during machine creation).
>> > +
>> > + Example:
>> > + (qemu) device_set host-arm-cpu,core-id=3,admin-state=disabled
>> > +ERST
>>
>> How exactly is the device selected? You provide a clue above: 'can be
>> located by "id" or via driver+property match'.
>>
>> I assume by "id" is just like device_del, i.e. by qdev ID or QOM path.
>>
>> By "driver+property match" is not obvious. Which of the arguments are
>> for matching, and which are for setting?
>>
>> If "id" is specified, is there any matching?
>>
>> The matching feature complicates this interface quite a bit. I doubt
>> it's worth the complexity. If you think it is, please split it off into
>> a separate patch.
>
> It's likely /me who to blame for asking to invent generic
> device-set QMP command.
> I see another application (beside ARM CPU power-on/off) for it,
> PCI devices to simulate powering on/off them at runtime without
> actually removing device.
I prefer generic commands over collecting ad hoc single-purpose
commands, too. Getting the design right can be difficult.
> wrt command,
> I'd use only 'id' with it to identify target device
> (i.e. no template matching nor QMP path either).
> To enforce rule, what user hasn't named explicitly by providing 'id'
> isn't meant to be accessed/manged by user later on.
Works well, except when we need to access / manage onboard devices.
That's still an unsolved problem.
> potentially we can invent specialized power_set/get command as
> an alternative if it makes design easier.
> But then we would be spawning similar commands for other things,
> where as device-set would cover it all. But then I might be
> over-complicating things by suggesting a generic approach.
Unclear.
I feel it's best to start the design process with ensvisaged uses. Can
you tell me a bit more about the uses you have in mind?
>> Next question. Is there a way for management applications to detect
>> whether a certain device supports device_set for a certain property?
>
> is there some kind of QMP command to check what does a device support,
> or at least what properties it supports? Can we piggy-back on that?
Maybe.
QAPI schema introspection (query-qmp-schema) has been a success. It has
a reasonably expressive type system, deprecation information, and hides
much implementation detail. Sadly, it doesn't cover most of QOM and all
of qdev due to QAPI schema bypass.
QOM type introspection (qom-list-types and qom-list-properties) is weak.
You can retrieve a property's name and type. The latter is seriously
underspecified, and somewhere between annoying and impossible to use
reliably. Properties created in certain ways are not visible here.
These are rare.
QOM object introspection (qom-list) is the same for concrete objects
rather than types.
qdev introspection (device-list-properties) is like QOM type
introspection. I'm not sure why it exists. Use QOM type introspection
instead.
QOM introspection is servicable for checking whether a certain property
exists. Examining a property's type is unadvisable.
>> Without that, what are management application supposed to do? Hard-code
>> what works? Run the command and see whether it fails?
>
> Adding libvirt list to discussion and possible ideas on what can be done here.
>
>> I understand right now the command supports just "admin-state" for a
>> certain set of devices, so hard-coding would be possible. But every new
>> (device, property) pair then requires management application updates,
>> and the hard-coded information becomes version specific. This will
>> become unworkable real quick. Not good enough for a command designed to
>> be generic.
[...]
On Thu, 09 Oct 2025 16:55:54 +0200
Markus Armbruster <armbru@redhat.com> wrote:
> Igor Mammedov <imammedo@redhat.com> writes:
>
> > On Thu, 09 Oct 2025 10:55:40 +0200
> > Markus Armbruster <armbru@redhat.com> wrote:
> >
> >> salil.mehta@opnsrc.net writes:
> >>
> >> > From: Salil Mehta <salil.mehta@huawei.com>
> >> >
> >> > This patch adds a "device_set" interface for modifying properties of devices
> >> > that already exist in the guest topology. Unlike 'device_add'/'device_del'
> >> > (hot-plug), 'device_set' does not create or destroy devices. It is intended
> >> > for guest-visible hot-add semantics where hardware is provisioned at boot but
> >> > logically enabled/disabled later via administrative policy.
> >> >
> >> > Compared to the existing 'qom-set' command, which is less intuitive and works
> >> > only with object IDs, device_set provides a more device-oriented interface.
> >> > It can be invoked at the QEMU prompt using natural device arguments, and the
> >> > new '-deviceset' CLI option allows properties to be set at boot time, similar
> >> > to how '-device' specifies device creation.
> >>
> >> Why can't we use -device?
> >
> > that's was my concern/suggestion in reply to cover letter
> > (as a place to put high level review and what can be done for the next revision)
>
> Yes.
>
> > (PS: It looks like I'm having email receiving issues (i.e. not getting from
> > mail list my own emails that it bonces to me, so threading is all broken on
> > my side and I'm might miss replies). But on positive side it looks like my
> > replies reach the list and CCed just fine)
>
> For what it's worth, your replies arrive fine here.
>
> >> > While the initial implementation focuses on "admin-state" changes (e.g.,
> >> > enable/disable a CPU already described by ACPI/DT), the interface is designed
> >> > to be generic. In future, it could be used for other per-device set/unset
> >> > style controls — beyond administrative power-states — provided the target
> >> > device explicitly allows such changes. This enables fine-grained runtime
> >> > control of device properties.
> >>
> >> Beware, designing a generic interface can be harder, sometimes much
> >> harder, than designing a specialized one.
> >>
> >> device_add and qom-set are generic, and they have issues:
> >>
> >> * device_add effectively bypasses QAPI by using 'gen': false.
> >>
> >> This bypasses QAPI's enforcement of documentation. Property
> >> documentation is separate and poor.
> >>
> >> It also defeats introspection with query-qmp-schema. You need to
> >> resort to other means instead, say QOM introspection (which is a bag
> >> of design flaws on its own), then map from QOM to qdev.
> >>
> >> * device_add lets you specify any qdev property, even properties that
> >> are intended only for use by C code.
> >>
> >> This results in accidental external interfaces.
> >>
> >> We tend to name properties like "x-prop" to discourage external use,
> >> but I wouldn't bet my own money on us getting that always right.
> >> Moreover, there's beauties like "x-origin".
> >>
> >> * qom-set & friends effectively bypass QAPI by using type 'any'.
> >>
> >> Again, the bypass results in poor documentation and a defeat of
> >> query-qmp-schema.
> >>
> >> * qom-set lets you mess with any QOM property with a setter callback.
> >>
> >> Again, accidental external interfaces: most of these properties are
> >> not meant for use with qom-set. For some, qom-set works, for some it
> >> silently does nothing, and for some it crashes. A lot more dangerous
> >> than device_add.
> >>
> >> The "x-" convention can't help here: some properties are intended for
> >> external use with object-add, but not with qom-set.
> >>
> >> We should avoid such issues in new interfaces.
>
> [...]
>
> >> > diff --git a/hmp-commands.hx b/hmp-commands.hx
> >> > index d0e4f35a30..18056cf21d 100644
> >> > --- a/hmp-commands.hx
> >> > +++ b/hmp-commands.hx
> >> > @@ -707,6 +707,36 @@ SRST
> >> > or a QOM object path.
> >> > ERST
> >> >
> >> > +{
> >> > + .name = "device_set",
> >> > + .args_type = "device:O",
> >> > + .params = "driver[,prop=value][,...]",
> >> > + .help = "set/unset existing device property",
> >> > + .cmd = hmp_device_set,
> >> > + .command_completion = device_set_completion,
> >> > +},
> >> > +
> >> > +SRST
> >> > +``device_set`` *driver[,prop=value][,...]*
> >> > + Change the administrative power state of an existing device.
> >> > +
> >> > + This command enables or disables a known device (e.g., CPU) using the
> >> > + "device_set" interface. It does not hotplug or add a new device.
> >> > +
> >> > + Depending on platform support (e.g., PSCI or ACPI), this may trigger
> >> > + corresponding operational changes — such as powering down a CPU or
> >> > + transitioning it to active use.
> >> > +
> >> > + Administrative state:
> >> > + * *enabled* — Allows the guest to use the device (e.g., CPU_ON)
> >> > + * *disabled* — Prevents guest use; device is powered off (e.g., CPU_OFF)
> >> > +
> >> > + Note: The device must already exist (be declared during machine creation).
> >> > +
> >> > + Example:
> >> > + (qemu) device_set host-arm-cpu,core-id=3,admin-state=disabled
> >> > +ERST
> >>
> >> How exactly is the device selected? You provide a clue above: 'can be
> >> located by "id" or via driver+property match'.
> >>
> >> I assume by "id" is just like device_del, i.e. by qdev ID or QOM path.
> >>
> >> By "driver+property match" is not obvious. Which of the arguments are
> >> for matching, and which are for setting?
> >>
> >> If "id" is specified, is there any matching?
> >>
> >> The matching feature complicates this interface quite a bit. I doubt
> >> it's worth the complexity. If you think it is, please split it off into
> >> a separate patch.
> >
> > It's likely /me who to blame for asking to invent generic
> > device-set QMP command.
> > I see another application (beside ARM CPU power-on/off) for it,
> > PCI devices to simulate powering on/off them at runtime without
> > actually removing device.
>
> I prefer generic commands over collecting ad hoc single-purpose
> commands, too. Getting the design right can be difficult.
>
> > wrt command,
> > I'd use only 'id' with it to identify target device
> > (i.e. no template matching nor QMP path either).
> > To enforce rule, what user hasn't named explicitly by providing 'id'
> > isn't meant to be accessed/manged by user later on.
>
> Works well, except when we need to access / manage onboard devices.
> That's still an unsolved problem.
>
> > potentially we can invent specialized power_set/get command as
> > an alternative if it makes design easier.
> > But then we would be spawning similar commands for other things,
> > where as device-set would cover it all. But then I might be
> > over-complicating things by suggesting a generic approach.
>
> Unclear.
>
> I feel it's best to start the design process with ensvisaged uses. Can
> you tell me a bit more about the uses you have in mind?
We have nic failover 'feature'
https://www.qemu.org/docs/master/system/virtio-net-failover.html
to make it work we do abuse hotplug and that poses problem
during migration, since:
- unplugging primary device releases resources (which might not be
possible to claim back in case migration failure)
- it's similar on destination side, where attempt to hotplug
primary might fail die to insufficient resources leaving guest
on 'degraded' virtio-net link.
Idea was that instead of hotplug we can power off primary device,
(it will still exist and keep resources), initiate migration,
and then on target do the same starting with primary fully realized
but powered of (and failing migration early if it can't claim resources,
safely resuming QEMU on source incl. primary link), and then guest
failover driver on destination would power primary on as part of
switching to primary link.
Above would require -device/device_add support for specifying device's
power state as minimum.
> >> Next question. Is there a way for management applications to detect
> >> whether a certain device supports device_set for a certain property?
> >
> > is there some kind of QMP command to check what does a device support,
> > or at least what properties it supports? Can we piggy-back on that?
>
> Maybe.
>
> QAPI schema introspection (query-qmp-schema) has been a success. It has
> a reasonably expressive type system, deprecation information, and hides
> much implementation detail. Sadly, it doesn't cover most of QOM and all
> of qdev due to QAPI schema bypass.
>
> QOM type introspection (qom-list-types and qom-list-properties) is weak.
> You can retrieve a property's name and type. The latter is seriously
> underspecified, and somewhere between annoying and impossible to use
> reliably. Properties created in certain ways are not visible here.
> These are rare.
>
> QOM object introspection (qom-list) is the same for concrete objects
> rather than types.
>
> qdev introspection (device-list-properties) is like QOM type
> introspection. I'm not sure why it exists. Use QOM type introspection
> instead.
>
> QOM introspection is servicable for checking whether a certain property
> exists. Examining a property's type is unadvisable.
>
> >> Without that, what are management application supposed to do? Hard-code
> >> what works? Run the command and see whether it fails?
> >
> > Adding libvirt list to discussion and possible ideas on what can be done here.
> >
> >> I understand right now the command supports just "admin-state" for a
> >> certain set of devices, so hard-coding would be possible. But every new
> >> (device, property) pair then requires management application updates,
> >> and the hard-coded information becomes version specific. This will
> >> become unworkable real quick. Not good enough for a command designed to
> >> be generic.
>
> [...]
>
Igor Mammedov <imammedo@redhat.com> writes: > On Thu, 09 Oct 2025 16:55:54 +0200 > Markus Armbruster <armbru@redhat.com> wrote: > >> Igor Mammedov <imammedo@redhat.com> writes: [...] >> > It's likely /me who to blame for asking to invent generic >> > device-set QMP command. >> > I see another application (beside ARM CPU power-on/off) for it, >> > PCI devices to simulate powering on/off them at runtime without >> > actually removing device. >> >> I prefer generic commands over collecting ad hoc single-purpose >> commands, too. Getting the design right can be difficult. >> >> > wrt command, >> > I'd use only 'id' with it to identify target device >> > (i.e. no template matching nor QMP path either). >> > To enforce rule, what user hasn't named explicitly by providing 'id' >> > isn't meant to be accessed/manged by user later on. >> >> Works well, except when we need to access / manage onboard devices. >> That's still an unsolved problem. >> >> > potentially we can invent specialized power_set/get command as >> > an alternative if it makes design easier. >> > But then we would be spawning similar commands for other things, >> > where as device-set would cover it all. But then I might be >> > over-complicating things by suggesting a generic approach. >> >> Unclear. >> >> I feel it's best to start the design process with ensvisaged uses. Can >> you tell me a bit more about the uses you have in mind? > > We have nic failover 'feature' > https://www.qemu.org/docs/master/system/virtio-net-failover.html > to make it work we do abuse hotplug and that poses problem > during migration, since: > - unplugging primary device releases resources (which might not be > possible to claim back in case migration failure) Serious reliability issue with no work-around. > - it's similar on destination side, where attempt to hotplug > primary might fail die to insufficient resources leaving guest > on 'degraded' virtio-net link. Obvious work-around is failing the migration. Same as we do when we can't create devices. > Idea was that instead of hotplug we can power off primary device, > (it will still exist and keep resources), initiate migration, > and then on target do the same starting with primary fully realized > but powered of (and failing migration early if it can't claim resources, > safely resuming QEMU on source incl. primary link), and then guest > failover driver on destination would power primary on as part of > switching to primary link. I can see how power on / off makes more sense than hot plug / unplug. > Above would require -device/device_add support for specifying device's > power state as minimum. The obvious way to control a device's power state with -device / device_add is a qdev property. Easy enough. Do we need to control a device's power state after it's created? If I understand your use case correctly, the answer is yes. -device / device_add can't do that. qom-set could, but friends don't let friends use it in production. Any other prior art for controlling device state at run time via QMP? [...]
On Mon, 20 Oct 2025 13:22:08 +0200 Markus Armbruster <armbru@redhat.com> wrote: > Igor Mammedov <imammedo@redhat.com> writes: > > > On Thu, 09 Oct 2025 16:55:54 +0200 > > Markus Armbruster <armbru@redhat.com> wrote: > > > >> Igor Mammedov <imammedo@redhat.com> writes: > > [...] > > >> > It's likely /me who to blame for asking to invent generic > >> > device-set QMP command. > >> > I see another application (beside ARM CPU power-on/off) for it, > >> > PCI devices to simulate powering on/off them at runtime without > >> > actually removing device. > >> > >> I prefer generic commands over collecting ad hoc single-purpose > >> commands, too. Getting the design right can be difficult. > >> > >> > wrt command, > >> > I'd use only 'id' with it to identify target device > >> > (i.e. no template matching nor QMP path either). > >> > To enforce rule, what user hasn't named explicitly by providing 'id' > >> > isn't meant to be accessed/manged by user later on. > >> > >> Works well, except when we need to access / manage onboard devices. > >> That's still an unsolved problem. > >> > >> > potentially we can invent specialized power_set/get command as > >> > an alternative if it makes design easier. > >> > But then we would be spawning similar commands for other things, > >> > where as device-set would cover it all. But then I might be > >> > over-complicating things by suggesting a generic approach. > >> > >> Unclear. > >> > >> I feel it's best to start the design process with ensvisaged uses. Can > >> you tell me a bit more about the uses you have in mind? > > > > We have nic failover 'feature' > > https://www.qemu.org/docs/master/system/virtio-net-failover.html > > to make it work we do abuse hotplug and that poses problem > > during migration, since: > > - unplugging primary device releases resources (which might not be > > possible to claim back in case migration failure) > > Serious reliability issue with no work-around. > > > - it's similar on destination side, where attempt to hotplug > > primary might fail die to insufficient resources leaving guest > > on 'degraded' virtio-net link. > > Obvious work-around is failing the migration. Same as we do when we > can't create devices. > > > Idea was that instead of hotplug we can power off primary device, > > (it will still exist and keep resources), initiate migration, > > and then on target do the same starting with primary fully realized > > but powered of (and failing migration early if it can't claim resources, > > safely resuming QEMU on source incl. primary link), and then guest > > failover driver on destination would power primary on as part of > > switching to primary link. > > I can see how power on / off makes more sense than hot plug / unplug. > > > Above would require -device/device_add support for specifying device's > > power state as minimum. > > The obvious way to control a device's power state with -device / > device_add is a qdev property. Easy enough. > > Do we need to control a device's power state after it's created? If I > understand your use case correctly, the answer is yes. -device / > device_add can't do that. Could you elaborate why why -device/device_add can't do that? > > qom-set could, but friends don't let friends use it in production. > > Any other prior art for controlling device state at run time via QMP? > > [...] >
Igor Mammedov <imammedo@redhat.com> writes: > On Mon, 20 Oct 2025 13:22:08 +0200 > Markus Armbruster <armbru@redhat.com> wrote: > >> Igor Mammedov <imammedo@redhat.com> writes: >> >> > On Thu, 09 Oct 2025 16:55:54 +0200 >> > Markus Armbruster <armbru@redhat.com> wrote: [...] >> >> I feel it's best to start the design process with ensvisaged uses. Can >> >> you tell me a bit more about the uses you have in mind? >> > >> > We have nic failover 'feature' >> > https://www.qemu.org/docs/master/system/virtio-net-failover.html >> > to make it work we do abuse hotplug and that poses problem >> > during migration, since: >> > - unplugging primary device releases resources (which might not be >> > possible to claim back in case migration failure) >> >> Serious reliability issue with no work-around. >> >> > - it's similar on destination side, where attempt to hotplug >> > primary might fail die to insufficient resources leaving guest >> > on 'degraded' virtio-net link. >> >> Obvious work-around is failing the migration. Same as we do when we >> can't create devices. >> >> > Idea was that instead of hotplug we can power off primary device, >> > (it will still exist and keep resources), initiate migration, >> > and then on target do the same starting with primary fully realized >> > but powered of (and failing migration early if it can't claim resources, >> > safely resuming QEMU on source incl. primary link), and then guest >> > failover driver on destination would power primary on as part of >> > switching to primary link. >> >> I can see how power on / off makes more sense than hot plug / unplug. >> >> > Above would require -device/device_add support for specifying device's >> > power state as minimum. >> >> The obvious way to control a device's power state with -device / >> device_add is a qdev property. Easy enough. >> >> Do we need to control a device's power state after it's created? If I >> understand your use case correctly, the answer is yes. -device / >> device_add can't do that. > > Could you elaborate why why -device/device_add can't do that? -device / device_add create, configure, and realize a new device. They can't reconfigure an existing device. In particular, they can't be used to control an existing device's power state. >> qom-set could, but friends don't let friends use it in production. >> >> Any other prior art for controlling device state at run time via QMP? >> >> [...]
On Wed, 29 Oct 2025 12:38:02 +0100 Markus Armbruster <armbru@redhat.com> wrote: > Igor Mammedov <imammedo@redhat.com> writes: > > > On Mon, 20 Oct 2025 13:22:08 +0200 > > Markus Armbruster <armbru@redhat.com> wrote: > > > >> Igor Mammedov <imammedo@redhat.com> writes: > >> > >> > On Thu, 09 Oct 2025 16:55:54 +0200 > >> > Markus Armbruster <armbru@redhat.com> wrote: > > [...] > > >> >> I feel it's best to start the design process with ensvisaged uses. Can > >> >> you tell me a bit more about the uses you have in mind? > >> > > >> > We have nic failover 'feature' > >> > https://www.qemu.org/docs/master/system/virtio-net-failover.html > >> > to make it work we do abuse hotplug and that poses problem > >> > during migration, since: > >> > - unplugging primary device releases resources (which might not be > >> > possible to claim back in case migration failure) > >> > >> Serious reliability issue with no work-around. > >> > >> > - it's similar on destination side, where attempt to hotplug > >> > primary might fail die to insufficient resources leaving guest > >> > on 'degraded' virtio-net link. > >> > >> Obvious work-around is failing the migration. Same as we do when we > >> can't create devices. > >> > >> > Idea was that instead of hotplug we can power off primary device, > >> > (it will still exist and keep resources), initiate migration, > >> > and then on target do the same starting with primary fully realized > >> > but powered of (and failing migration early if it can't claim resources, > >> > safely resuming QEMU on source incl. primary link), and then guest > >> > failover driver on destination would power primary on as part of > >> > switching to primary link. > >> > >> I can see how power on / off makes more sense than hot plug / unplug. > >> > >> > Above would require -device/device_add support for specifying device's > >> > power state as minimum. > >> > >> The obvious way to control a device's power state with -device / > >> device_add is a qdev property. Easy enough. > >> > >> Do we need to control a device's power state after it's created? If I > >> understand your use case correctly, the answer is yes. -device / > >> device_add can't do that. > > > > Could you elaborate why why -device/device_add can't do that? > > -device / device_add create, configure, and realize a new device. > > They can't reconfigure an existing device. In particular, they can't be > used to control an existing device's power state. Sorry, I've misread as we can't use both for creating device in powered off state. Perhaps we should consider a new specialized QMP command to manipulate runtime power state. (Like it was suggested by Daniel) > > >> qom-set could, but friends don't let friends use it in production. > >> > >> Any other prior art for controlling device state at run time via QMP? > >> > >> [...] >
Igor Mammedov <imammedo@redhat.com> writes: > On Wed, 29 Oct 2025 12:38:02 +0100 > Markus Armbruster <armbru@redhat.com> wrote: > >> Igor Mammedov <imammedo@redhat.com> writes: >> >> > On Mon, 20 Oct 2025 13:22:08 +0200 >> > Markus Armbruster <armbru@redhat.com> wrote: >> > >> >> Igor Mammedov <imammedo@redhat.com> writes: >> >> >> >> > On Thu, 09 Oct 2025 16:55:54 +0200 >> >> > Markus Armbruster <armbru@redhat.com> wrote: >> >> [...] >> >> >> >> I feel it's best to start the design process with ensvisaged uses. Can >> >> >> you tell me a bit more about the uses you have in mind? >> >> > >> >> > We have nic failover 'feature' >> >> > https://www.qemu.org/docs/master/system/virtio-net-failover.html >> >> > to make it work we do abuse hotplug and that poses problem >> >> > during migration, since: >> >> > - unplugging primary device releases resources (which might not be >> >> > possible to claim back in case migration failure) >> >> >> >> Serious reliability issue with no work-around. >> >> >> >> > - it's similar on destination side, where attempt to hotplug >> >> > primary might fail die to insufficient resources leaving guest >> >> > on 'degraded' virtio-net link. >> >> >> >> Obvious work-around is failing the migration. Same as we do when we >> >> can't create devices. >> >> >> >> > Idea was that instead of hotplug we can power off primary device, >> >> > (it will still exist and keep resources), initiate migration, >> >> > and then on target do the same starting with primary fully realized >> >> > but powered of (and failing migration early if it can't claim resources, >> >> > safely resuming QEMU on source incl. primary link), and then guest >> >> > failover driver on destination would power primary on as part of >> >> > switching to primary link. >> >> >> >> I can see how power on / off makes more sense than hot plug / unplug. >> >> >> >> > Above would require -device/device_add support for specifying device's >> >> > power state as minimum. >> >> >> >> The obvious way to control a device's power state with -device / >> >> device_add is a qdev property. Easy enough. >> >> >> >> Do we need to control a device's power state after it's created? If I >> >> understand your use case correctly, the answer is yes. -device / >> >> device_add can't do that. >> > >> > Could you elaborate why why -device/device_add can't do that? >> >> -device / device_add create, configure, and realize a new device. >> >> They can't reconfigure an existing device. In particular, they can't be >> used to control an existing device's power state. > > Sorry, I've misread as we can't use both for creating device in powered off state. > > Perhaps we should consider a new specialized QMP command to > manipulate runtime power state. (Like it was suggested by Daniel) I prefer few generic commands to many specialized commands whenever practical. However, designing a generic interface can be harder, sometimes much harder, than designing a specialized one. The generic command Salil proposed has serious flaws, as discussed upthread. None of us has promising ideas on how to do a generic command that isn't flawed by design. A more specialized one seems to be the only visible path forward. >> >> qom-set could, but friends don't let friends use it in production. >> >> >> >> Any other prior art for controlling device state at run time via QMP? >> >> >> >> [...]
On Thu, 9 Oct 2025 at 15:56, Markus Armbruster <armbru@redhat.com> wrote: > qdev introspection (device-list-properties) is like QOM type > introspection. I'm not sure why it exists. It exists because it is the older of the two interfaces: device-list-properties was added in 2012, whereas qom-list-properties was only added in 2018. device-list-properties also does some device-specific sanitization that may or may not be helpful: it won't let you try it on an abstract base class, for instance, and it won't list "legacy-" properties. One problem you don't mention with QOM introspection is that we have no marking for whether properties are intended to be user-facing knobs, configurable things to be set by other parts of QEMU, or purely details of the implementation. thanks -- PMM
Peter Maydell <peter.maydell@linaro.org> writes: > On Thu, 9 Oct 2025 at 15:56, Markus Armbruster <armbru@redhat.com> wrote: >> qdev introspection (device-list-properties) is like QOM type >> introspection. I'm not sure why it exists. > > It exists because it is the older of the two interfaces: > device-list-properties was added in 2012, whereas > qom-list-properties was only added in 2018. I suspected it was, but didn't want to make unchecked claims. Thanks for checking! > device-list-properties also does some device-specific > sanitization that may or may not be helpful: it won't > let you try it on an abstract base class, for instance, Introspecting abstract bases is probably not useful. But what harm could it do? Can't see why preventing it is worth the bother. Of course, changing it now is not worth the bother, either :) > and it won't list "legacy-" properties. I remember these exist, but not what they're good for :) Should we deprecate device-list-properties in favour of qom-list-properties? > One problem you don't mention with QOM introspection is > that we have no marking for whether properties are intended > to be user-facing knobs, configurable things to be set > by other parts of QEMU, or purely details of the implementation. Yes. This is what I had in mind when I pointed out "accidental external interfaces".
On Thu, Oct 09, 2025 at 02:51:25PM +0200, Igor Mammedov via Devel wrote:
> On Thu, 09 Oct 2025 10:55:40 +0200
> Markus Armbruster <armbru@redhat.com> wrote:
>
> > salil.mehta@opnsrc.net writes:
> >
> > > From: Salil Mehta <salil.mehta@huawei.com>
> > >
> > > This patch adds a "device_set" interface for modifying properties of devices
> > > that already exist in the guest topology. Unlike 'device_add'/'device_del'
> > > (hot-plug), 'device_set' does not create or destroy devices. It is intended
> > > for guest-visible hot-add semantics where hardware is provisioned at boot but
> > > logically enabled/disabled later via administrative policy.
> > >
> > > Compared to the existing 'qom-set' command, which is less intuitive and works
> > > only with object IDs, device_set provides a more device-oriented interface.
> > > It can be invoked at the QEMU prompt using natural device arguments, and the
> > > new '-deviceset' CLI option allows properties to be set at boot time, similar
> > > to how '-device' specifies device creation.
> >
> > Why can't we use -device?
>
> that's was my concern/suggestion in reply to cover letter
> (as a place to put high level review and what can be done for the next revision)
>
> (PS: It looks like I'm having email receiving issues (i.e. not getting from
> mail list my own emails that it bonces to me, so threading is all broken on
> my side and I'm might miss replies). But on positive side it looks like my
> replies reach the list and CCed just fine)
>
>
> > > While the initial implementation focuses on "admin-state" changes (e.g.,
> > > enable/disable a CPU already described by ACPI/DT), the interface is designed
> > > to be generic. In future, it could be used for other per-device set/unset
> > > style controls — beyond administrative power-states — provided the target
> > > device explicitly allows such changes. This enables fine-grained runtime
> > > control of device properties.
> >
> > Beware, designing a generic interface can be harder, sometimes much
> > harder, than designing a specialized one.
> >
> > device_add and qom-set are generic, and they have issues:
> >
> > * device_add effectively bypasses QAPI by using 'gen': false.
> >
> > This bypasses QAPI's enforcement of documentation. Property
> > documentation is separate and poor.
> >
> > It also defeats introspection with query-qmp-schema. You need to
> > resort to other means instead, say QOM introspection (which is a bag
> > of design flaws on its own), then map from QOM to qdev.
> >
> > * device_add lets you specify any qdev property, even properties that
> > are intended only for use by C code.
> >
> > This results in accidental external interfaces.
> >
> > We tend to name properties like "x-prop" to discourage external use,
> > but I wouldn't bet my own money on us getting that always right.
> > Moreover, there's beauties like "x-origin".
> >
> > * qom-set & friends effectively bypass QAPI by using type 'any'.
> >
> > Again, the bypass results in poor documentation and a defeat of
> > query-qmp-schema.
> >
> > * qom-set lets you mess with any QOM property with a setter callback.
> >
> > Again, accidental external interfaces: most of these properties are
> > not meant for use with qom-set. For some, qom-set works, for some it
> > silently does nothing, and for some it crashes. A lot more dangerous
> > than device_add.
> >
> > The "x-" convention can't help here: some properties are intended for
> > external use with object-add, but not with qom-set.
> >
> > We should avoid such issues in new interfaces.
> >
> > We'll examine how this applies to device_set when I review the QAPI
> > schema.
> >
> > > Key pieces:
> > > * QMP: qmp_device_set() to update an existing device. The device can be
> > > located by "id" or via driver+property match using a DeviceListener
> > > callback (qdev_find_device()).
> > > * HMP: "device_set" command with tab-completion. Errors are surfaced via
> > > hmp_handle_error().
> > > * CLI: "-deviceset" option for setting startup/admin properties at boot,
> > > including a JSON form. Options are parsed into qemu_deviceset_opts and
> > > applied after device creation.
> > > * Docs/help: HMP help text and qemu-options.hx additions explain usage and
> > > explicitly note that no hot-plug occurs.
> > > * Safety: disallowed during live migration (migration_is_idle() check).
> > >
> > > Semantics:
> > > * Operates on an existing DeviceState; no enumeration/new device appears.
> > > * Complements device_add/device_del by providing state mutation only.
> > > * Backward compatible: no behavior change unless "device_set"/"-deviceset"
> > > is used.
> > >
> > > Examples:
> > > HMP:
> > > (qemu) device_set host-arm-cpu,core-id=3,admin-state=enable
> > >
> > > CLI (at boot):
> > > -smp cpus=4,maxcpus=4 \
> > > -deviceset host-arm-cpu,core-id=2,admin-state=disable
> > >
> > > QMP (JSON form):
> > > { "execute": "device_set",
> > > "arguments": {
> > > "driver": "host-arm-cpu",
> > > "core-id": 1,
> > > "admin-state": "disable"
> > > }
> > > }
> >
> > {"error": {"class": "CommandNotFound", "desc": "The command device_set has not been found"}}
> >
> > Clue below.
> >
> > > NOTE: The qdev_enable()/qdev_disable() hooks for acting on admin-state will be
> > > added in subsequent patches. Device classes must explicitly support any
> > > property they want to expose through device_set.
> > >
> > > Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
> > > ---
> > > hmp-commands.hx | 30 +++++++++
> > > hw/arm/virt.c | 86 +++++++++++++++++++++++++
> > > hw/core/cpu-common.c | 12 ++++
> > > hw/core/qdev.c | 21 ++++++
> > > include/hw/arm/virt.h | 1 +
> > > include/hw/core/cpu.h | 11 ++++
> > > include/hw/qdev-core.h | 22 +++++++
> > > include/monitor/hmp.h | 2 +
> > > include/monitor/qdev.h | 30 +++++++++
> > > include/system/system.h | 1 +
> > > qemu-options.hx | 51 +++++++++++++--
> > > system/qdev-monitor.c | 139 +++++++++++++++++++++++++++++++++++++++-
> > > system/vl.c | 39 +++++++++++
> > > 13 files changed, 440 insertions(+), 5 deletions(-)
> >
> > Clue: no update to the QAPI schema, i.e. the QMP command does not exist.
On that point...
No new pure HMP commands please. We consider implementation of the
QMP command to be the mandatory first step in any patch series. Any
HMP command must follow and must be implemented by calling the QMP
command handler.
> > > diff --git a/hmp-commands.hx b/hmp-commands.hx
> > > index d0e4f35a30..18056cf21d 100644
> > > --- a/hmp-commands.hx
> > > +++ b/hmp-commands.hx
> > > @@ -707,6 +707,36 @@ SRST
> > > or a QOM object path.
> > > ERST
> > >
> > > +{
> > > + .name = "device_set",
> > > + .args_type = "device:O",
> > > + .params = "driver[,prop=value][,...]",
> > > + .help = "set/unset existing device property",
> > > + .cmd = hmp_device_set,
> > > + .command_completion = device_set_completion,
> > > +},
> > > +
> > > +SRST
> > > +``device_set`` *driver[,prop=value][,...]*
> > > + Change the administrative power state of an existing device.
> > > +
> > > + This command enables or disables a known device (e.g., CPU) using the
> > > + "device_set" interface. It does not hotplug or add a new device.
> > > +
> > > + Depending on platform support (e.g., PSCI or ACPI), this may trigger
> > > + corresponding operational changes — such as powering down a CPU or
> > > + transitioning it to active use.
> > > +
> > > + Administrative state:
> > > + * *enabled* — Allows the guest to use the device (e.g., CPU_ON)
> > > + * *disabled* — Prevents guest use; device is powered off (e.g., CPU_OFF)
> > > +
> > > + Note: The device must already exist (be declared during machine creation).
> > > +
> > > + Example:
> > > + (qemu) device_set host-arm-cpu,core-id=3,admin-state=disabled
> > > +ERST
> >
> > How exactly is the device selected? You provide a clue above: 'can be
> > located by "id" or via driver+property match'.
> >
> > I assume by "id" is just like device_del, i.e. by qdev ID or QOM path.
> >
> > By "driver+property match" is not obvious. Which of the arguments are
> > for matching, and which are for setting?
> >
> > If "id" is specified, is there any matching?
> >
> > The matching feature complicates this interface quite a bit. I doubt
> > it's worth the complexity. If you think it is, please split it off into
> > a separate patch.
>
> It's likely /me who to blame for asking to invent generic
> device-set QMP command.
> I see another application (beside ARM CPU power-on/off) for it,
> PCI devices to simulate powering on/off them at runtime without
> actually removing device.
>
> wrt command,
> I'd use only 'id' with it to identify target device
> (i.e. no template matching nor QMP path either).
> To enforce rule, what user hasn't named explicitly by providing 'id'
> isn't meant to be accessed/manged by user later on.
>
> potentially we can invent specialized power_set/get command as
> an alternative if it makes design easier.
> But then we would be spawning similar commands for other things,
> where as device-set would cover it all. But then I might be
> over-complicating things by suggesting a generic approach.
The generic set/get design feels convenient because you don't
need to create new commands, but it has significant downsides
both for QEMU and the users of QEMU.
From a QEMU POV the main burden is that we loose understanding
of how users of QEMU are consuming our interface / functionality
at a conceptual level and at the low level. This in turns means
we either struggle to offer a stable API, or our hands are tied
behind our back for future changes.
Consumers of QEMU are similarly exposed to the raw low level
details which has many downsides
* If QEMU ever changes impl, but retains the conceptual
functionality, apps are broken.
* If a given feature is more complex than a single property,
apps will be invoking a whole set of commands to set many
props to achieve a given task.
* If certain sequences of prop changes are needed, apps
have no guidance on the ordering dependancies - which
might even change between QEMU versions
* If setting one prop fails, apps may need to manually
rollback previous prop changes they made
* The schema is unable to describe what functionality is
now available since device properties are invisible.
* If two devices expose the same functionality, but via
different properties, apps have inconsistent interfaces
I'm highly sceptical that exposing 'device_set' is a good
idea.
> > Next question. Is there a way for management applications to detect
> > whether a certain device supports device_set for a certain property?
>
> is there some kind of QMP command to check what does a device support,
> or at least what properties it supports? Can we piggy-back on that?
Note, querying whether a device supports a property is conceptually
quite different from querying whether QEMU supports a given operation,
because it requires apps to first connect the dots between the low
level property change, and the conceptual effect the want to produce.
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
© 2016 - 2025 Red Hat, Inc.