Property itself is a well defined interface to either support smooth
conversions to Object's properties, or supports global properties. However
currently it's tied to DeviceClass, aka, qdev. So non-qdev cannot use
Property list.
My current observation shows Property is almost ready to be used as a
separated exported interface, except two small things that may need touch
up internally:
qdev_prop_allow_set
qdev_prop_check_globals
The 1st one currently checks against realize state (which is part of qdev
attributes only). The 2nd one checks for all global property being used in
all non-pluggable qdevs.
We can loose the check in both spots, keep the check if the driver is a
qdev, otherwise we can safely whitelist non-qdev use cases of Property.
Signed-off-by: Peter Xu <peterx@redhat.com>
---
hw/core/qdev-properties.c | 24 ++++++++++++++++++++----
tests/unit/test-qdev-global-props.c | 6 +++++-
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 34d7b26a73..8f870c85fc 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -31,8 +31,14 @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
static bool qdev_prop_allow_set(Object *obj, const char *name,
const PropertyInfo *info, Error **errp)
{
- DeviceState *dev = DEVICE(obj);
+ DeviceState *dev;
+
+ if (!object_dynamic_cast(obj, TYPE_DEVICE)) {
+ /* Currently, non-qdev can always set Property anytime */
+ return true;
+ }
+ dev = DEVICE(obj);
if (dev->realized && !info->realized_set_allowed) {
qdev_prop_set_after_realize(dev, name, errp);
return false;
@@ -997,6 +1003,7 @@ int qdev_prop_check_globals(void)
for (i = 0; i < global_props()->len; i++) {
GlobalProperty *prop;
+ bool hotpluggable;
ObjectClass *oc;
DeviceClass *dc;
@@ -1005,15 +1012,24 @@ int qdev_prop_check_globals(void)
continue;
}
oc = object_class_by_name(prop->driver);
- oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
if (!oc) {
warn_report("global %s.%s has invalid class name",
prop->driver, prop->property);
ret = 1;
continue;
}
- dc = DEVICE_CLASS(oc);
- if (!dc->hotpluggable && !prop->used) {
+ oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
+ if (oc) {
+ dc = DEVICE_CLASS(oc);
+ hotpluggable = dc->hotpluggable;
+ } else {
+ /*
+ * Currently, to be strict to assume all non-qdev are not
+ * hotpluggable (whoever will use -global).
+ */
+ hotpluggable = false;
+ }
+ if (!hotpluggable && !prop->used) {
warn_report("global %s.%s=%s not used",
prop->driver, prop->property, prop->value);
ret = 1;
diff --git a/tests/unit/test-qdev-global-props.c b/tests/unit/test-qdev-global-props.c
index 8ea362cbb9..86bb1458d9 100644
--- a/tests/unit/test-qdev-global-props.c
+++ b/tests/unit/test-qdev-global-props.c
@@ -275,8 +275,12 @@ static void test_dynamic_globalprop(void)
g_test_trap_assert_stderr_unmatched("*prop4*");
g_test_trap_assert_stderr(
"*warning: global nohotplug-type.prop5=105 not used*");
+ /*
+ * TYPE_OBJECT can opt-in for global properties, so the error is "not
+ * used" too for nondevice-type.
+ */
g_test_trap_assert_stderr(
- "*warning: global nondevice-type.prop6 has invalid class name*");
+ "*warning: global nondevice-type.prop6=106 not used*");
g_test_trap_assert_stdout("");
}
--
2.53.0
Peter Xu <peterx@redhat.com> writes:
> Property itself is a well defined interface to either support smooth
> conversions to Object's properties, or supports global properties. However
> currently it's tied to DeviceClass, aka, qdev. So non-qdev cannot use
> Property list.
>
> My current observation shows Property is almost ready to be used as a
> separated exported interface, except two small things that may need touch
> up internally:
>
> qdev_prop_allow_set
Just a thought, we could use something like this to block update of
migration parameters during migration runtime.
> qdev_prop_check_globals
>
> The 1st one currently checks against realize state (which is part of qdev
> attributes only). The 2nd one checks for all global property being used in
> all non-pluggable qdevs.
>
> We can loose the check in both spots, keep the check if the driver is a
> qdev, otherwise we can safely whitelist non-qdev use cases of Property.
>
> Signed-off-by: Peter Xu <peterx@redhat.com>
> ---
> hw/core/qdev-properties.c | 24 ++++++++++++++++++++----
> tests/unit/test-qdev-global-props.c | 6 +++++-
> 2 files changed, 25 insertions(+), 5 deletions(-)
>
> diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
> index 34d7b26a73..8f870c85fc 100644
> --- a/hw/core/qdev-properties.c
> +++ b/hw/core/qdev-properties.c
> @@ -31,8 +31,14 @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
> static bool qdev_prop_allow_set(Object *obj, const char *name,
> const PropertyInfo *info, Error **errp)
> {
> - DeviceState *dev = DEVICE(obj);
> + DeviceState *dev;
> +
> + if (!object_dynamic_cast(obj, TYPE_DEVICE)) {
> + /* Currently, non-qdev can always set Property anytime */
> + return true;
> + }
>
> + dev = DEVICE(obj);
> if (dev->realized && !info->realized_set_allowed) {
> qdev_prop_set_after_realize(dev, name, errp);
> return false;
> @@ -997,6 +1003,7 @@ int qdev_prop_check_globals(void)
>
> for (i = 0; i < global_props()->len; i++) {
> GlobalProperty *prop;
> + bool hotpluggable;
> ObjectClass *oc;
> DeviceClass *dc;
>
> @@ -1005,15 +1012,24 @@ int qdev_prop_check_globals(void)
> continue;
> }
> oc = object_class_by_name(prop->driver);
> - oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
> if (!oc) {
> warn_report("global %s.%s has invalid class name",
> prop->driver, prop->property);
> ret = 1;
> continue;
> }
> - dc = DEVICE_CLASS(oc);
> - if (!dc->hotpluggable && !prop->used) {
> + oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
> + if (oc) {
> + dc = DEVICE_CLASS(oc);
> + hotpluggable = dc->hotpluggable;
> + } else {
> + /*
> + * Currently, to be strict to assume all non-qdev are not
> + * hotpluggable (whoever will use -global).
> + */
> + hotpluggable = false;
> + }
> + if (!hotpluggable && !prop->used) {
> warn_report("global %s.%s=%s not used",
> prop->driver, prop->property, prop->value);
> ret = 1;
> diff --git a/tests/unit/test-qdev-global-props.c b/tests/unit/test-qdev-global-props.c
> index 8ea362cbb9..86bb1458d9 100644
> --- a/tests/unit/test-qdev-global-props.c
> +++ b/tests/unit/test-qdev-global-props.c
> @@ -275,8 +275,12 @@ static void test_dynamic_globalprop(void)
> g_test_trap_assert_stderr_unmatched("*prop4*");
> g_test_trap_assert_stderr(
> "*warning: global nohotplug-type.prop5=105 not used*");
> + /*
> + * TYPE_OBJECT can opt-in for global properties, so the error is "not
> + * used" too for nondevice-type.
> + */
> g_test_trap_assert_stderr(
> - "*warning: global nondevice-type.prop6 has invalid class name*");
> + "*warning: global nondevice-type.prop6=106 not used*");
> g_test_trap_assert_stdout("");
> }
On Fri, Jun 05, 2026 at 11:39:26AM -0300, Fabiano Rosas wrote: > Peter Xu <peterx@redhat.com> writes: > > > Property itself is a well defined interface to either support smooth > > conversions to Object's properties, or supports global properties. However > > currently it's tied to DeviceClass, aka, qdev. So non-qdev cannot use > > Property list. > > > > My current observation shows Property is almost ready to be used as a > > separated exported interface, except two small things that may need touch > > up internally: > > > > qdev_prop_allow_set > > Just a thought, we could use something like this to block update of > migration parameters during migration runtime. Currently it may not achieve it (with qdev property or object property that I'm trying), it's because qmp set parameters currently bypasses qom properties. We need to switch QMP set parameters to use qom set to achieve it, but yes, that sounds like something good to consider in the future to merge the two paths somehow. If we use helpers like object_property_add_uint64_ptr() we save lines but lose control over setter() blocking updates during live migration. If we use raw object_property_add() we get control but adds boilerplate lines. Anyway, sounds like something for the future.. -- Peter Xu
On 05/06/2026 00:11, Peter Xu wrote:
> Property itself is a well defined interface to either support smooth
> conversions to Object's properties, or supports global properties. However
> currently it's tied to DeviceClass, aka, qdev. So non-qdev cannot use
> Property list.
That's indeed because Property is a qdev-only concept.
> My current observation shows Property is almost ready to be used as a
> separated exported interface, except two small things that may need touch
> up internally:
>
> qdev_prop_allow_set
> qdev_prop_check_globals
>
> The 1st one currently checks against realize state (which is part of qdev
> attributes only). The 2nd one checks for all global property being used in
> all non-pluggable qdevs.
>
> We can loose the check in both spots, keep the check if the driver is a
> qdev, otherwise we can safely whitelist non-qdev use cases of Property.
I'm really not sure this is the right approach: surely you would want to
flip this on its head so that -global makes use of the underlying QOM
APIs instead of qdev APIs?
> Signed-off-by: Peter Xu <peterx@redhat.com>
> ---
> hw/core/qdev-properties.c | 24 ++++++++++++++++++++----
> tests/unit/test-qdev-global-props.c | 6 +++++-
> 2 files changed, 25 insertions(+), 5 deletions(-)
>
> diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
> index 34d7b26a73..8f870c85fc 100644
> --- a/hw/core/qdev-properties.c
> +++ b/hw/core/qdev-properties.c
> @@ -31,8 +31,14 @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
> static bool qdev_prop_allow_set(Object *obj, const char *name,
> const PropertyInfo *info, Error **errp)
> {
> - DeviceState *dev = DEVICE(obj);
> + DeviceState *dev;
> +
> + if (!object_dynamic_cast(obj, TYPE_DEVICE)) {
> + /* Currently, non-qdev can always set Property anytime */
> + return true;
> + }
>
> + dev = DEVICE(obj);
> if (dev->realized && !info->realized_set_allowed) {
> qdev_prop_set_after_realize(dev, name, errp);
> return false;
> @@ -997,6 +1003,7 @@ int qdev_prop_check_globals(void)
>
> for (i = 0; i < global_props()->len; i++) {
> GlobalProperty *prop;
> + bool hotpluggable;
> ObjectClass *oc;
> DeviceClass *dc;
>
> @@ -1005,15 +1012,24 @@ int qdev_prop_check_globals(void)
> continue;
> }
> oc = object_class_by_name(prop->driver);
> - oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
> if (!oc) {
> warn_report("global %s.%s has invalid class name",
> prop->driver, prop->property);
> ret = 1;
> continue;
> }
> - dc = DEVICE_CLASS(oc);
> - if (!dc->hotpluggable && !prop->used) {
> + oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
> + if (oc) {
> + dc = DEVICE_CLASS(oc);
> + hotpluggable = dc->hotpluggable;
> + } else {
> + /*
> + * Currently, to be strict to assume all non-qdev are not
> + * hotpluggable (whoever will use -global).
> + */
> + hotpluggable = false;
> + }
> + if (!hotpluggable && !prop->used) {
> warn_report("global %s.%s=%s not used",
> prop->driver, prop->property, prop->value);
> ret = 1;
> diff --git a/tests/unit/test-qdev-global-props.c b/tests/unit/test-qdev-global-props.c
> index 8ea362cbb9..86bb1458d9 100644
> --- a/tests/unit/test-qdev-global-props.c
> +++ b/tests/unit/test-qdev-global-props.c
> @@ -275,8 +275,12 @@ static void test_dynamic_globalprop(void)
> g_test_trap_assert_stderr_unmatched("*prop4*");
> g_test_trap_assert_stderr(
> "*warning: global nohotplug-type.prop5=105 not used*");
> + /*
> + * TYPE_OBJECT can opt-in for global properties, so the error is "not
> + * used" too for nondevice-type.
> + */
> g_test_trap_assert_stderr(
> - "*warning: global nondevice-type.prop6 has invalid class name*");
> + "*warning: global nondevice-type.prop6=106 not used*");
> g_test_trap_assert_stdout("");
> }
ATB,
Mark.
Mark Cave-Ayland <mark.caveayland@nutanix.com> writes:
> On 05/06/2026 00:11, Peter Xu wrote:
>
>> Property itself is a well defined interface to either support smooth
>> conversions to Object's properties, or supports global properties. However
>> currently it's tied to DeviceClass, aka, qdev. So non-qdev cannot use
>> Property list.
>
> That's indeed because Property is a qdev-only concept.
>
>> My current observation shows Property is almost ready to be used as a
>> separated exported interface, except two small things that may need touch
>> up internally:
>>
>> qdev_prop_allow_set
>> qdev_prop_check_globals
>>
>> The 1st one currently checks against realize state (which is part of qdev
>> attributes only). The 2nd one checks for all global property being used in
>> all non-pluggable qdevs.
>>
>> We can loose the check in both spots, keep the check if the driver is a
>> qdev, otherwise we can safely whitelist non-qdev use cases of Property.
>
> I'm really not sure this is the right approach: surely you would want to
> flip this on its head so that -global makes use of the underlying QOM
> APIs instead of qdev APIs?
>
That's a good point. It seems we could do the same as qdev does without
having to use the Property directly. It creates some awkwardness with
the setting of defaults, but it's probably quite doable.
>> Signed-off-by: Peter Xu <peterx@redhat.com>
>> ---
>> hw/core/qdev-properties.c | 24 ++++++++++++++++++++----
>> tests/unit/test-qdev-global-props.c | 6 +++++-
>> 2 files changed, 25 insertions(+), 5 deletions(-)
>>
>> diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
>> index 34d7b26a73..8f870c85fc 100644
>> --- a/hw/core/qdev-properties.c
>> +++ b/hw/core/qdev-properties.c
>> @@ -31,8 +31,14 @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
>> static bool qdev_prop_allow_set(Object *obj, const char *name,
>> const PropertyInfo *info, Error **errp)
>> {
>> - DeviceState *dev = DEVICE(obj);
>> + DeviceState *dev;
>> +
>> + if (!object_dynamic_cast(obj, TYPE_DEVICE)) {
>> + /* Currently, non-qdev can always set Property anytime */
>> + return true;
>> + }
>>
>> + dev = DEVICE(obj);
>> if (dev->realized && !info->realized_set_allowed) {
>> qdev_prop_set_after_realize(dev, name, errp);
>> return false;
>> @@ -997,6 +1003,7 @@ int qdev_prop_check_globals(void)
>>
>> for (i = 0; i < global_props()->len; i++) {
>> GlobalProperty *prop;
>> + bool hotpluggable;
>> ObjectClass *oc;
>> DeviceClass *dc;
>>
>> @@ -1005,15 +1012,24 @@ int qdev_prop_check_globals(void)
>> continue;
>> }
>> oc = object_class_by_name(prop->driver);
>> - oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
>> if (!oc) {
>> warn_report("global %s.%s has invalid class name",
>> prop->driver, prop->property);
>> ret = 1;
>> continue;
>> }
>> - dc = DEVICE_CLASS(oc);
>> - if (!dc->hotpluggable && !prop->used) {
>> + oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
>> + if (oc) {
>> + dc = DEVICE_CLASS(oc);
>> + hotpluggable = dc->hotpluggable;
>> + } else {
>> + /*
>> + * Currently, to be strict to assume all non-qdev are not
>> + * hotpluggable (whoever will use -global).
>> + */
>> + hotpluggable = false;
>> + }
>> + if (!hotpluggable && !prop->used) {
>> warn_report("global %s.%s=%s not used",
>> prop->driver, prop->property, prop->value);
>> ret = 1;
>> diff --git a/tests/unit/test-qdev-global-props.c b/tests/unit/test-qdev-global-props.c
>> index 8ea362cbb9..86bb1458d9 100644
>> --- a/tests/unit/test-qdev-global-props.c
>> +++ b/tests/unit/test-qdev-global-props.c
>> @@ -275,8 +275,12 @@ static void test_dynamic_globalprop(void)
>> g_test_trap_assert_stderr_unmatched("*prop4*");
>> g_test_trap_assert_stderr(
>> "*warning: global nohotplug-type.prop5=105 not used*");
>> + /*
>> + * TYPE_OBJECT can opt-in for global properties, so the error is "not
>> + * used" too for nondevice-type.
>> + */
>> g_test_trap_assert_stderr(
>> - "*warning: global nondevice-type.prop6 has invalid class name*");
>> + "*warning: global nondevice-type.prop6=106 not used*");
>> g_test_trap_assert_stdout("");
>> }
>
>
> ATB,
>
> Mark.
© 2016 - 2026 Red Hat, Inc.