[PATCH v2 00/21] qom: introduce property flags to track external user input
Hi, This is the v2 trying to introduce property flags to detect user's property setting (from CLI/QMP/HMP). I dropped RFC tag since previous RFC v1 [1]. Though this work the follow-up of v2.6 & v2.7 machines' removal [2], now it is decoupled from [2] totally since v2 doesn't detect compat property and only focuses on external user setting, so this series is based on master branch at the commit 28a6ca268c2c ("Merge tag 'single- binary-20260203' of https://github.com/philmd/qemu into staging"). And you can also find the code here: https://gitlab.com/zhao.liu/qemu/-/tree/prop-flags-v2.3-02-08-2026 This series introduces 3 property flags: * USER_SET: Any external user property setting (from CLI/HMP/QMP) is marked as USER_SET. * DEPRECATED: Once a property is marked as DEPRECATED, any external user property setting will trigger a warning. * INTERNAL: Once a property is marked as INTERNAL, any external user property setting will cause an error. More details or document for these 3 flags, you can refer patch 7. Compared with RFC v1, v2 mainly: * introduce USER_SET property flag to identify all user's setting. - patch 7 for document. * construct DEPRECATED & INTERNAL flag on USER_SET. - patch 7 for document. * cover more comprehensive user set cases. - patch 8-13. * provide examples about new flags (USER_SET/DEPRECATED/INTELNAL). - patch 15/16/17 are examples for DEPRECATED flag. - patch 18 is the example for INTERNAL flag. - patch 20 is the example for USER_SET flag. I think v2 should now cover "nearly" all cases (patch 8-13) where users set properties: one approach is to trace the call chain of object_property_set(). Even if there are cases that were missed, they can be easily addressed based on this series: object_property_set(obj, ...); /* Insert this call after object_property_set(). */ object_property_set_flags(obj, ..., OBJ_PROP_FLAG_USER_SET, ...); [1]: RFC v1: https://lore.kernel.org/qemu-devel/20251202170502.3228625-1-zhao1.liu@intel.... [2]: hw/i386/pc: Remove deprecated 2.6 and 2.7 PC machines https://lore.kernel.org/qemu-devel/20260108033051.777361-1-zhao1.liu@intel.c... Thanks and Best Regards, Zhao --- Zhao Liu (21): qom/object: use BIT macro for ObjectPropertyFlags qom/object: cache ObjectPropertyFlags in ObjectProperty qom/object: factor out object_class_property_try_add() qom/object: add flags argument in object_{class_}property_try_add() qom/object: rename object_{class_}property_try_add() to object_{class_}property_add_full() qom/object: add helpers to set/get/clear property flags qom/object: introduce user interaction flags for properties qom/object: add from_user argument in object_property_parse() qom/object: mark global property set from CLI as USER_SET qom/qom-hmp-cmd: mark properties set from HMP (non-JSON) "qom-set" as USER_SET qom/qom-qmp-cmd: mark properties set from QMP/HMP (JSON) "qom-set" as USER_SET qom/object_interfaces: mark properties set from qdict & keyval as USER_SET system/vl: mark property set in object_parse_property_opt() as USER_SET hw/core/qdev-properties: allow qdev properties accept flags target/i386: deprecate fill-mtrr-mask property target/i386: deprecate cpuid-0xb property hw/intc/ioapic: deprecate version property target/i386: mark x-consistent-cache property as internal-only target/i386: remove redundant validation for lbr-fmt property target/i386: detect user provided lbr-fmt via property flag hw/core/qdev-properties: support valid default value for DEFINE_PROP_UINT64_CHECKMASK docs/about/deprecated.rst | 31 +++++ hw/core/qdev-properties.c | 29 ++-- hw/i386/sgx.c | 2 +- hw/intc/ioapic.c | 3 +- include/hw/core/qdev-properties.h | 38 +++--- include/qom/object.h | 215 +++++++++++++++++++++++++++--- qom/object.c | 177 ++++++++++++++++++++---- qom/object_interfaces.c | 5 + qom/qom-hmp-cmds.c | 2 +- qom/qom-qmp-cmds.c | 7 +- system/vl.c | 6 +- target/i386/cpu.c | 28 ++-- 12 files changed, 448 insertions(+), 95 deletions(-) -- 2.34.1
Standardize the definition of ObjectPropertyFlags by using the BIT() macro instead of manual bit shifts to improve readability. Suggested-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 26df6137b911..6226b88c1eda 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -16,6 +16,7 @@ #include "qapi/qapi-builtin-types.h" #include "qemu/module.h" +#include "qemu/bitops.h" struct TypeImpl; typedef struct TypeImpl *Type; @@ -1841,9 +1842,9 @@ ObjectProperty *object_class_property_add_tm(ObjectClass *klass, typedef enum { /* Automatically add a getter to the property */ - OBJ_PROP_FLAG_READ = 1 << 0, + OBJ_PROP_FLAG_READ = BIT(0), /* Automatically add a setter to the property */ - OBJ_PROP_FLAG_WRITE = 1 << 1, + OBJ_PROP_FLAG_WRITE = BIT(1), /* Automatically add a getter and a setter to the property */ OBJ_PROP_FLAG_READWRITE = (OBJ_PROP_FLAG_READ | OBJ_PROP_FLAG_WRITE), } ObjectPropertyFlags; -- 2.34.1
Introduce a 'flags' field in the ObjectProperty structure to store property-specific behavior modifiers. Currently, ObjectPropertyFlags (READ/WRITE) are only used for property creation (e.g., initialize accessors for pointer properties). By caching these flags directly in ObjectProperty, we can: 1. Preserve the initial access intent (read/write) of the property. * the READ/WRITE flags cached in ObjectProperty have no effect for now, but they may be useful for cases need write-once, if needed. 2. Reuse existing ObjectPropertyFlags and provide a foundation for future flags (e.g., to track if a property was explicitly set by external user). To avoid "incomplete type" error, move ObjectPropertyFlags before ObjectProperty definition, and polish the comment of ObjectPropertyFlags to clarify how READ/WRITE flags work for general properties. Suggested-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 34 +++++++++++++++++++++++++--------- qom/object.c | 16 +++++++++++++++- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 6226b88c1eda..05706d4d7e3a 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -87,6 +87,30 @@ typedef void (ObjectPropertyRelease)(Object *obj, */ typedef void (ObjectPropertyInit)(Object *obj, ObjectProperty *prop); +typedef enum { + /* + * The property is readable and has a getter. + * + * For pointer property, this flag (set in object_{class_}property_add_*_ptr()) + * will automatically add a getter to this property. + */ + OBJ_PROP_FLAG_READ = BIT(0), + /* + * The property is writable and has a setter. + * + * For pointer property, this flag (set in object_{class_}property_add_*_ptr()) + * will automatically add a setter to this property. + */ + OBJ_PROP_FLAG_WRITE = BIT(1), + /* + * The property is readable and writable, as well as has a getter and a setter. + * + * For pointer property, this flag (set in object_{class_}property_add_*_ptr()) + * will automatically add a getter and a setter to this property. + */ + OBJ_PROP_FLAG_READWRITE = (OBJ_PROP_FLAG_READ | OBJ_PROP_FLAG_WRITE), +} ObjectPropertyFlags; + struct ObjectProperty { char *name; @@ -99,6 +123,7 @@ struct ObjectProperty ObjectPropertyInit *init; void *opaque; QObject *defval; + ObjectPropertyFlags flags; }; /** @@ -1840,15 +1865,6 @@ ObjectProperty *object_class_property_add_tm(ObjectClass *klass, const char *name, void (*get)(Object *, struct tm *, Error **)); -typedef enum { - /* Automatically add a getter to the property */ - OBJ_PROP_FLAG_READ = BIT(0), - /* Automatically add a setter to the property */ - OBJ_PROP_FLAG_WRITE = BIT(1), - /* Automatically add a getter and a setter to the property */ - OBJ_PROP_FLAG_READWRITE = (OBJ_PROP_FLAG_READ | OBJ_PROP_FLAG_WRITE), -} ObjectPropertyFlags; - /** * object_property_add_uint8_ptr: * @obj: the object to add a property to diff --git a/qom/object.c b/qom/object.c index ff8ede8a328e..f5801f4624c8 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1233,6 +1233,19 @@ void object_unref(void *objptr) } } +static inline void object_property_flags_init(ObjectProperty *prop) +{ + uint8_t flags = 0; + + if (prop->set) { + flags |= OBJ_PROP_FLAG_WRITE; + } + if (prop->get) { + flags |= OBJ_PROP_FLAG_READ; + } + prop->flags |= flags; +} + ObjectProperty * object_property_try_add(Object *obj, const char *name, const char *type, ObjectPropertyAccessor *get, @@ -1279,6 +1292,7 @@ object_property_try_add(Object *obj, const char *name, const char *type, prop->set = set; prop->release = release; prop->opaque = opaque; + object_property_flags_init(prop); g_hash_table_insert(obj->properties, prop->name, prop); return prop; @@ -1317,9 +1331,9 @@ object_class_property_add(ObjectClass *klass, prop->set = set; prop->release = release; prop->opaque = opaque; + object_property_flags_init(prop); g_hash_table_insert(klass->properties, prop->name, prop); - return prop; } -- 2.34.1
Similar to object_property_try_add(), factor out object_class_property_try_add(). This allows adding more arguments to the core implementation without changing the signature of object_class_property_add(), avoiding the need to modify the extensive number of callers distributed throughout the code tree. While at it, add documentation for these functions. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 56 ++++++++++++++++++++++++++++++++++++++++++++ qom/object.c | 34 ++++++++++++++++++++------- 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 05706d4d7e3a..060db136988b 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1147,6 +1147,62 @@ ObjectProperty *object_property_add(Object *obj, const char *name, void object_property_del(Object *obj, const char *name); +/** + * object_class_property_try_add: + * @klass: the object class to add a property to + * @name: the name of the property. This can contain any character except for + * a forward slash. In general, you should use hyphens '-' instead of + * underscores '_' when naming properties. + * @type: the type name of the property. This namespace is pretty loosely + * defined. Sub namespaces are constructed by using a prefix and then + * to angle brackets. For instance, the type 'virtio-net-pci' in the + * 'link' namespace would be 'link<virtio-net-pci>'. + * @get: The getter to be called to read a property. If this is NULL, then + * the property cannot be read. + * @set: the setter to be called to write a property. If this is NULL, + * then the property cannot be written. + * @release: called when the property is removed from the object. This is + * meant to allow a property to free its opaque upon object + * destruction. This may be NULL. + * @opaque: an opaque pointer to pass to the callbacks for the property + * @errp: pointer to error object + * + * Returns: The #ObjectProperty; this can be used to set the @resolve + * callback for child and link properties. + */ +ObjectProperty *object_class_property_try_add(ObjectClass *klass, const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp); + + +/** + * object_class_property_add: + * Same as object_class_property_try_add() with @errp hardcoded to + * &error_abort. + * + * @klass: the object class to add a property to + * @name: the name of the property. This can contain any character except for + * a forward slash. In general, you should use hyphens '-' instead of + * underscores '_' when naming properties. + * @type: the type name of the property. This namespace is pretty loosely + * defined. Sub namespaces are constructed by using a prefix and then + * to angle brackets. For instance, the type 'virtio-net-pci' in the + * 'link' namespace would be 'link<virtio-net-pci>'. + * @get: The getter to be called to read a property. If this is NULL, then + * the property cannot be read. + * @set: the setter to be called to write a property. If this is NULL, + * then the property cannot be written. + * @release: called when the property is removed from the object. This is + * meant to allow a property to free its opaque upon object + * destruction. This may be NULL. + * @opaque: an opaque pointer to pass to the callbacks for the property + * + * Returns: The #ObjectProperty; this can be used to set the @resolve + * callback for child and link properties. + */ ObjectProperty *object_class_property_add(ObjectClass *klass, const char *name, const char *type, ObjectPropertyAccessor *get, diff --git a/qom/object.c b/qom/object.c index f5801f4624c8..f101b48154d1 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1310,17 +1310,22 @@ object_property_add(Object *obj, const char *name, const char *type, } ObjectProperty * -object_class_property_add(ObjectClass *klass, - const char *name, - const char *type, - ObjectPropertyAccessor *get, - ObjectPropertyAccessor *set, - ObjectPropertyRelease *release, - void *opaque) +object_class_property_try_add(ObjectClass *klass, + const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp) { ObjectProperty *prop; - assert(!object_class_property_find(klass, name)); + if (object_class_property_find(klass, name) != NULL) { + error_setg(errp, "attempt to add duplicate property '%s'" + " to object class (type '%s')", + name, object_class_get_name(klass)); + return NULL; + } prop = g_malloc0(sizeof(*prop)); @@ -1337,6 +1342,19 @@ object_class_property_add(ObjectClass *klass, return prop; } +ObjectProperty * +object_class_property_add(ObjectClass *klass, + const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque) +{ + return object_class_property_try_add(klass, name, type, get, set, release, + opaque, &error_abort); +} + ObjectProperty *object_property_find(Object *obj, const char *name) { ObjectProperty *prop; -- 2.34.1
On Tue, 10 Feb 2026, Zhao Liu wrote:
Similar to object_property_try_add(), factor out object_class_property_try_add().
This allows adding more arguments to the core implementation without changing the signature of object_class_property_add(), avoiding the need to modify the extensive number of callers distributed throughout the code tree.
While at it, add documentation for these functions.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 56 ++++++++++++++++++++++++++++++++++++++++++++ qom/object.c | 34 ++++++++++++++++++++------- 2 files changed, 82 insertions(+), 8 deletions(-)
diff --git a/include/qom/object.h b/include/qom/object.h index 05706d4d7e3a..060db136988b 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1147,6 +1147,62 @@ ObjectProperty *object_property_add(Object *obj, const char *name,
void object_property_del(Object *obj, const char *name);
+/** + * object_class_property_try_add:
This is renamed two patches later so maybe should be named like that here and drop the renaming patch. Regards, BALATON Zoltan
Add the flags argument in object_property_try_add() and object_class_property_try_add(), allowing callers to explicitly specify the property flags during creation. This will be helpful to extend qdev property definition to support marking as deprecated or internal-only. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 21 ++++++++++++++++----- qom/object.c | 19 ++++++++++--------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 060db136988b..7d8a7be1bad3 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1103,6 +1103,11 @@ void object_unref(void *obj); * @release: called when the property is removed from the object. This is * meant to allow a property to free its opaque upon object * destruction. This may be NULL. + * @flags: property flags used to control property uses. The + * OBJ_PROP_FLAG_READ and OBJ_PROP_FLAG_WRITE flags are automatically + * set based on the presence of the @get and @set callbacks. The value + * passed here is bitwise-ORed with those automatic flags. Pass 0 if no + * other flags are needed. * @opaque: an opaque pointer to pass to the callbacks for the property * @errp: pointer to error object * @@ -1114,12 +1119,13 @@ ObjectProperty *object_property_try_add(Object *obj, const char *name, ObjectPropertyAccessor *get, ObjectPropertyAccessor *set, ObjectPropertyRelease *release, + ObjectPropertyFlags flags, void *opaque, Error **errp); /** * object_property_add: - * Same as object_property_try_add() with @errp hardcoded to - * &error_abort. + * Same as object_property_try_add() with @flags hardcoded to 0 and @errp + * hardcoded to &error_abort. * * @obj: the object to add a property to * @name: the name of the property. This can contain any character except for @@ -1164,6 +1170,11 @@ void object_property_del(Object *obj, const char *name); * @release: called when the property is removed from the object. This is * meant to allow a property to free its opaque upon object * destruction. This may be NULL. + * @flags: property flags used to control property uses. The + * OBJ_PROP_FLAG_READ and OBJ_PROP_FLAG_WRITE flags are automatically + * set based on the presence of the @get and @set callbacks. The value + * passed here is bitwise-ORed with those automatic flags. Pass 0 if no + * other flags are needed. * @opaque: an opaque pointer to pass to the callbacks for the property * @errp: pointer to error object * @@ -1175,13 +1186,13 @@ ObjectProperty *object_class_property_try_add(ObjectClass *klass, const char *na ObjectPropertyAccessor *get, ObjectPropertyAccessor *set, ObjectPropertyRelease *release, + ObjectPropertyFlags flags, void *opaque, Error **errp); - /** * object_class_property_add: - * Same as object_class_property_try_add() with @errp hardcoded to - * &error_abort. + * Same as object_class_property_try_add() with @flags hardcoded to 0 and @errp + * hardcoded to &error_abort. * * @klass: the object class to add a property to * @name: the name of the property. This can contain any character except for diff --git a/qom/object.c b/qom/object.c index f101b48154d1..543e42cd6f16 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1233,10 +1233,9 @@ void object_unref(void *objptr) } } -static inline void object_property_flags_init(ObjectProperty *prop) +static inline void object_property_flags_init(ObjectProperty *prop, + ObjectPropertyFlags flags) { - uint8_t flags = 0; - if (prop->set) { flags |= OBJ_PROP_FLAG_WRITE; } @@ -1251,6 +1250,7 @@ object_property_try_add(Object *obj, const char *name, const char *type, ObjectPropertyAccessor *get, ObjectPropertyAccessor *set, ObjectPropertyRelease *release, + ObjectPropertyFlags flags, void *opaque, Error **errp) { ObjectProperty *prop; @@ -1266,7 +1266,7 @@ object_property_try_add(Object *obj, const char *name, const char *type, char *full_name = g_strdup_printf("%s[%d]", name_no_array, i); ret = object_property_try_add(obj, full_name, type, get, set, - release, opaque, NULL); + release, flags, opaque, NULL); g_free(full_name); if (ret) { break; @@ -1292,7 +1292,7 @@ object_property_try_add(Object *obj, const char *name, const char *type, prop->set = set; prop->release = release; prop->opaque = opaque; - object_property_flags_init(prop); + object_property_flags_init(prop, flags); g_hash_table_insert(obj->properties, prop->name, prop); return prop; @@ -1306,7 +1306,7 @@ object_property_add(Object *obj, const char *name, const char *type, void *opaque) { return object_property_try_add(obj, name, type, get, set, release, - opaque, &error_abort); + 0, opaque, &error_abort); } ObjectProperty * @@ -1316,6 +1316,7 @@ object_class_property_try_add(ObjectClass *klass, ObjectPropertyAccessor *get, ObjectPropertyAccessor *set, ObjectPropertyRelease *release, + ObjectPropertyFlags flags, void *opaque, Error **errp) { ObjectProperty *prop; @@ -1336,7 +1337,7 @@ object_class_property_try_add(ObjectClass *klass, prop->set = set; prop->release = release; prop->opaque = opaque; - object_property_flags_init(prop); + object_property_flags_init(prop, flags); g_hash_table_insert(klass->properties, prop->name, prop); return prop; @@ -1352,7 +1353,7 @@ object_class_property_add(ObjectClass *klass, void *opaque) { return object_class_property_try_add(klass, name, type, get, set, release, - opaque, &error_abort); + 0, opaque, &error_abort); } ObjectProperty *object_property_find(Object *obj, const char *name) @@ -1863,7 +1864,7 @@ object_property_try_add_child(Object *obj, const char *name, type = g_strdup_printf("child<%s>", object_get_typename(child)); op = object_property_try_add(obj, name, type, object_get_child_property, - NULL, object_finalize_child_property, + NULL, object_finalize_child_property, 0, child, errp); if (!op) { return NULL; -- 2.34.1
The suffixes "_try_add" and "_add" typically distinguish functions based solely on their error-handling behavior. However, the object_{class_}property_try_add() variants now support the additional 'flags' argument. Consequently, naming them based only on error handling no longer accurately reflects the distinction between the two interface variants. Rename object_{class_}property_try_add() to object_{class_}property_add_full() to indicate that these interfaces offer comprehensive argument support, including the new flags. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 38 ++++++++++++++++++------------------ qom/object.c | 46 ++++++++++++++++++++++---------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 7d8a7be1bad3..30c9f20b1d18 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1087,7 +1087,7 @@ Object *object_ref(void *obj); void object_unref(void *obj); /** - * object_property_try_add: + * object_property_add_full: * @obj: the object to add a property to * @name: the name of the property. This can contain any character except for * a forward slash. In general, you should use hyphens '-' instead of @@ -1114,17 +1114,17 @@ void object_unref(void *obj); * Returns: The #ObjectProperty; this can be used to set the @resolve * callback for child and link properties. */ -ObjectProperty *object_property_try_add(Object *obj, const char *name, - const char *type, - ObjectPropertyAccessor *get, - ObjectPropertyAccessor *set, - ObjectPropertyRelease *release, - ObjectPropertyFlags flags, - void *opaque, Error **errp); +ObjectProperty *object_property_add_full(Object *obj, const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + ObjectPropertyFlags flags, + void *opaque, Error **errp); /** * object_property_add: - * Same as object_property_try_add() with @flags hardcoded to 0 and @errp + * Same as object_property_add_full() with @flags hardcoded to 0 and @errp * hardcoded to &error_abort. * * @obj: the object to add a property to @@ -1154,7 +1154,7 @@ ObjectProperty *object_property_add(Object *obj, const char *name, void object_property_del(Object *obj, const char *name); /** - * object_class_property_try_add: + * object_class_property_add_full: * @klass: the object class to add a property to * @name: the name of the property. This can contain any character except for * a forward slash. In general, you should use hyphens '-' instead of @@ -1181,18 +1181,18 @@ void object_property_del(Object *obj, const char *name); * Returns: The #ObjectProperty; this can be used to set the @resolve * callback for child and link properties. */ -ObjectProperty *object_class_property_try_add(ObjectClass *klass, const char *name, - const char *type, - ObjectPropertyAccessor *get, - ObjectPropertyAccessor *set, - ObjectPropertyRelease *release, - ObjectPropertyFlags flags, - void *opaque, Error **errp); +ObjectProperty *object_class_property_add_full(ObjectClass *klass, const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + ObjectPropertyFlags flags, + void *opaque, Error **errp); /** * object_class_property_add: - * Same as object_class_property_try_add() with @flags hardcoded to 0 and @errp - * hardcoded to &error_abort. + * Same as object_class_property_add_full() with @flags hardcoded to 0 and + * @errp hardcoded to &error_abort. * * @klass: the object class to add a property to * @name: the name of the property. This can contain any character except for diff --git a/qom/object.c b/qom/object.c index 543e42cd6f16..c1a1e5ff3fbe 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1246,12 +1246,12 @@ static inline void object_property_flags_init(ObjectProperty *prop, } ObjectProperty * -object_property_try_add(Object *obj, const char *name, const char *type, - ObjectPropertyAccessor *get, - ObjectPropertyAccessor *set, - ObjectPropertyRelease *release, - ObjectPropertyFlags flags, - void *opaque, Error **errp) +object_property_add_full(Object *obj, const char *name, const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + ObjectPropertyFlags flags, + void *opaque, Error **errp) { ObjectProperty *prop; size_t name_len = strlen(name); @@ -1265,8 +1265,8 @@ object_property_try_add(Object *obj, const char *name, const char *type, for (i = 0; i < INT16_MAX; ++i) { char *full_name = g_strdup_printf("%s[%d]", name_no_array, i); - ret = object_property_try_add(obj, full_name, type, get, set, - release, flags, opaque, NULL); + ret = object_property_add_full(obj, full_name, type, get, set, + release, flags, opaque, NULL); g_free(full_name); if (ret) { break; @@ -1305,19 +1305,19 @@ object_property_add(Object *obj, const char *name, const char *type, ObjectPropertyRelease *release, void *opaque) { - return object_property_try_add(obj, name, type, get, set, release, - 0, opaque, &error_abort); + return object_property_add_full(obj, name, type, get, set, release, + 0, opaque, &error_abort); } ObjectProperty * -object_class_property_try_add(ObjectClass *klass, - const char *name, - const char *type, - ObjectPropertyAccessor *get, - ObjectPropertyAccessor *set, - ObjectPropertyRelease *release, - ObjectPropertyFlags flags, - void *opaque, Error **errp) +object_class_property_add_full(ObjectClass *klass, + const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + ObjectPropertyFlags flags, + void *opaque, Error **errp) { ObjectProperty *prop; @@ -1352,8 +1352,8 @@ object_class_property_add(ObjectClass *klass, ObjectPropertyRelease *release, void *opaque) { - return object_class_property_try_add(klass, name, type, get, set, release, - 0, opaque, &error_abort); + return object_class_property_add_full(klass, name, type, get, set, release, + 0, opaque, &error_abort); } ObjectProperty *object_property_find(Object *obj, const char *name) @@ -1863,9 +1863,9 @@ object_property_try_add_child(Object *obj, const char *name, type = g_strdup_printf("child<%s>", object_get_typename(child)); - op = object_property_try_add(obj, name, type, object_get_child_property, - NULL, object_finalize_child_property, 0, - child, errp); + op = object_property_add_full(obj, name, type, object_get_child_property, + NULL, object_finalize_child_property, 0, + child, errp); if (!op) { return NULL; } -- 2.34.1
Introduce four helper functions to operate object property flags: object_property_set_flags(), object_property_get_flags(), object_property_check_flags() and object_property_clear_flags(). Among them, object_property_check_flags() is a complement to object_property_get_flags(), because sometimes it's needed to check whether certain flags are set without returning all flags. This encapsulates and separates the flag management logic, avoiding direct access to ObjectProperty internals in call sites. Suggested-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 64 ++++++++++++++++++++++++++++++++++++++++++++ qom/object.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/include/qom/object.h b/include/qom/object.h index 30c9f20b1d18..856b12e7289c 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1086,6 +1086,70 @@ Object *object_ref(void *obj); */ void object_unref(void *obj); +/** + * object_property_set_flags: + * @obj: the object. + * @name: the name of the property. + * @flags: the flags to be set for the property. + * @errp: pointer to error object. + * + * Set the @flags to the property. Existing flags are preserved. + * + * Returns: %true on success, %false on failure. + */ +bool object_property_set_flags(Object *obj, const char *name, + ObjectPropertyFlags flags, + Error **errp); + +/** + * object_property_get_flags: + * @obj: the object. + * @name: the name of the property. + * @flags: pointer to a location to store the retrieved flags. Must not be + * NULL. + * @errp: pointer to error object. + * + * Get the current flags of the specified property. + * + * Returns: %true on success, %false on failure. + */ +bool object_property_get_flags(Object *obj, const char *name, + ObjectPropertyFlags *flags, + Error **errp); + +/** + * object_property_check_flags: + * @obj: the object. + * @name: the name of the property. + * @flags: the flags to check for on the property. + * @errp: pointer to error object. + * + * Check whether the specified property has all bits in @flags set. + * This is useful for detecting if a property has been explicitly set + * by the user (e.g. with %OBJ_PROP_FLAG_USER_SET). + * + * Returns: 1 if all @flags are set, 0 if not all @flags are set, + * or -1 on failure (property not found). + */ +int object_property_check_flags(Object *obj, const char *name, + ObjectPropertyFlags flags, + Error **errp); + +/** + * object_property_clear_flags: + * @obj: the object. + * @name: the name of the property. + * @flags: the flags to be removed from the property. + * @errp: pointer to error object + * + * Clear the @flags from the property. Other flags remain unchanged. + * + * Returns: %true on success, %false on failure. + */ +bool object_property_clear_flags(Object *obj, const char *name, + ObjectPropertyFlags flags, + Error **errp); + /** * object_property_add_full: * @obj: the object to add a property to diff --git a/qom/object.c b/qom/object.c index c1a1e5ff3fbe..49ef99a299b6 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1233,6 +1233,69 @@ void object_unref(void *objptr) } } +bool object_property_set_flags(Object *obj, const char *name, + ObjectPropertyFlags flags, + Error **errp) +{ + ObjectProperty *prop = object_property_find_err(obj, name, errp); + if (!prop) { + return false; + } + + prop->flags |= flags; + return true; +} + +bool object_property_get_flags(Object *obj, const char *name, + ObjectPropertyFlags *flags, + Error **errp) +{ + ObjectProperty *prop; + + if (!flags) { + error_setg(errp, "invalid argument: flags is NULL"); + return false; + } + + prop = object_property_find_err(obj, name, errp); + if (!prop) { + return false; + } + + *flags = prop->flags; + return true; +} + +int object_property_check_flags(Object *obj, const char *name, + ObjectPropertyFlags flags, + Error **errp) +{ + ObjectPropertyFlags prop_flags; + + if (!object_property_get_flags(obj, name, &prop_flags, errp)) { + return -1; + } + + if ((prop_flags & flags) == flags) { + return 1; + } + + return 0; +} + +bool object_property_clear_flags(Object *obj, const char *name, + ObjectPropertyFlags flags, + Error **errp) +{ + ObjectProperty *prop = object_property_find_err(obj, name, errp); + if (!prop) { + return false; + } + + prop->flags &= ~flags; + return true; +} + static inline void object_property_flags_init(ObjectProperty *prop, ObjectPropertyFlags flags) { -- 2.34.1
Introduce three new flags to `ObjectPropertyFlags` to better manage property interactions with external users (CLI, QMP, HMP): 1. OBJ_PROP_FLAG_USER_SET: Marks a property as having been modified by an external user. This flag is designed to be "sticky": once set, it persists even if the property value is subsequently overwritten by internal logic. It allows the QEMU system to distinguish user intent. The advantage of this design is that it is not needed to manually clear the USER_SET flag on every internal write. This simplifies the logic and decouples flag management from the current property setting path (object_property_set()). This is chosen over a strict "current origin" approach (where internal writes would clear the flag) for a practical reason: QEMU code often modifies underlying struct fields (which are defined as properties) directly, bypassing the property API entirely. This makes it impossible to "accurately" track whether the *current* value truly comes from the user. Therefore, a sticky "user touched this" flag is the only meaningful and robust solution. 2. OBJ_PROP_FLAG_DEPRECATED: Marks a property as deprecated. 3. OBJ_PROP_FLAG_INTERNAL: Marks a property as internal-only, disallowing external user access. Additionally, update object_property_set_flags() to implement the enforcement logic. When a property is flagged with OBJ_PROP_FLAG_USER_SET: - If the property is also marked OBJ_PROP_FLAG_DEPRECATED, report a warning. - If the property is also marked OBJ_PROP_FLAG_INTERNAL, raise an error and stop the operation. Suggested-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 24 ++++++++++++++++++++++++ qom/object.c | 15 +++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/qom/object.h b/include/qom/object.h index 856b12e7289c..1b77429aa28b 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -109,6 +109,30 @@ typedef enum { * will automatically add a getter and a setter to this property. */ OBJ_PROP_FLAG_READWRITE = (OBJ_PROP_FLAG_READ | OBJ_PROP_FLAG_WRITE), + /* + * The property was explicitly set by an external user. + * + * This flag is set whenever the property is modified via external interfaces + * (CLI, QMP, HMP). It allows internal code to distinguish whether the + * property has been modified by the user. + * + * Once set, this flag persists even if the property value is subsequently + * overwritten by internal logic. It is NOT automatically cleared and must + * be explicitly cleared using object_property_clear_flags(). + */ + OBJ_PROP_FLAG_USER_SET = BIT(2), + /* + * The property is deprecated and will be removed in the future version. + * + * Any setting to this property by the user will raise a deprecation warning. + */ + OBJ_PROP_FLAG_DEPRECATED = BIT(3), + /* + * The property is internal only and cannot be set by the user. + * + * Any setting to this property by the user will raise an error. + */ + OBJ_PROP_FLAG_INTERNAL = BIT(4), } ObjectPropertyFlags; struct ObjectProperty diff --git a/qom/object.c b/qom/object.c index 49ef99a299b6..75a1fe7ea1d3 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1242,6 +1242,21 @@ bool object_property_set_flags(Object *obj, const char *name, return false; } + if ((flags & OBJ_PROP_FLAG_USER_SET)) { + if (prop->flags & OBJ_PROP_FLAG_DEPRECATED) { + warn_report("Property '%s.%s' has been deprecated. " + "Please do not use it.", + object_get_typename(obj), name); + } + + if (prop->flags & OBJ_PROP_FLAG_INTERNAL) { + error_setg(errp, "Property '%s.%s' is internal only. " + "It can't be set by external user", + object_get_typename(obj), name); + return false; + } + } + prop->flags |= flags; return true; } -- 2.34.1
On Tue, Feb 10, 2026 at 11:23:34AM +0800, Zhao Liu wrote:
Introduce three new flags to `ObjectPropertyFlags` to better manage property interactions with external users (CLI, QMP, HMP):
1. OBJ_PROP_FLAG_USER_SET: Marks a property as having been modified by an external user.
This flag is designed to be "sticky": once set, it persists even if the property value is subsequently overwritten by internal logic. It allows the QEMU system to distinguish user intent.
The advantage of this design is that it is not needed to manually clear the USER_SET flag on every internal write. This simplifies the logic and decouples flag management from the current property setting path (object_property_set()).
This is chosen over a strict "current origin" approach (where internal writes would clear the flag) for a practical reason: QEMU code often modifies underlying struct fields (which are defined as properties) directly, bypassing the property API entirely. This makes it impossible to "accurately" track whether the *current* value truly comes from the user. Therefore, a sticky "user touched this" flag is the only meaningful and robust solution.
2. OBJ_PROP_FLAG_DEPRECATED: Marks a property as deprecated.
3. OBJ_PROP_FLAG_INTERNAL: Marks a property as internal-only, disallowing external user access.
Additionally, update object_property_set_flags() to implement the enforcement logic. When a property is flagged with OBJ_PROP_FLAG_USER_SET: - If the property is also marked OBJ_PROP_FLAG_DEPRECATED, report a warning. - If the property is also marked OBJ_PROP_FLAG_INTERNAL, raise an error and stop the operation.
Suggested-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 24 ++++++++++++++++++++++++ qom/object.c | 15 +++++++++++++++ 2 files changed, 39 insertions(+)
diff --git a/include/qom/object.h b/include/qom/object.h index 856b12e7289c..1b77429aa28b 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -109,6 +109,30 @@ typedef enum { * will automatically add a getter and a setter to this property. */ OBJ_PROP_FLAG_READWRITE = (OBJ_PROP_FLAG_READ | OBJ_PROP_FLAG_WRITE), + /* + * The property was explicitly set by an external user. + * + * This flag is set whenever the property is modified via external interfaces + * (CLI, QMP, HMP). It allows internal code to distinguish whether the + * property has been modified by the user. + * + * Once set, this flag persists even if the property value is subsequently + * overwritten by internal logic. It is NOT automatically cleared and must + * be explicitly cleared using object_property_clear_flags(). + */ + OBJ_PROP_FLAG_USER_SET = BIT(2), + /* + * The property is deprecated and will be removed in the future version. + * + * Any setting to this property by the user will raise a deprecation warning. + */ + OBJ_PROP_FLAG_DEPRECATED = BIT(3), + /* + * The property is internal only and cannot be set by the user. + * + * Any setting to this property by the user will raise an error. + */ + OBJ_PROP_FLAG_INTERNAL = BIT(4), } ObjectPropertyFlags;
I don't think this single enum design is very desirable, as it is mixing up pieces of information with three distinct lifetimes / scopes. The OBJ_PROP_FLAD_{READ,WRITE,READWRITE} values are scoped to the execution of the property adder methods. The OBJ_PROP_FLAG_{DEPRECATED,INTERNAL} values are scoped to the lifetime of the class. The OBJ_PROP_FLAG_USER_SET value is scoped to the lifetime of the instance. 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 :|
On Tue, Feb 10, 2026 at 09:49:40AM +0000, Daniel P. Berrangé wrote:
On Tue, Feb 10, 2026 at 11:23:34AM +0800, Zhao Liu wrote:
Introduce three new flags to `ObjectPropertyFlags` to better manage property interactions with external users (CLI, QMP, HMP):
1. OBJ_PROP_FLAG_USER_SET: Marks a property as having been modified by an external user.
This flag is designed to be "sticky": once set, it persists even if the property value is subsequently overwritten by internal logic. It allows the QEMU system to distinguish user intent.
The advantage of this design is that it is not needed to manually clear the USER_SET flag on every internal write. This simplifies the logic and decouples flag management from the current property setting path (object_property_set()).
This is chosen over a strict "current origin" approach (where internal writes would clear the flag) for a practical reason: QEMU code often modifies underlying struct fields (which are defined as properties) directly, bypassing the property API entirely. This makes it impossible to "accurately" track whether the *current* value truly comes from the user. Therefore, a sticky "user touched this" flag is the only meaningful and robust solution.
2. OBJ_PROP_FLAG_DEPRECATED: Marks a property as deprecated.
3. OBJ_PROP_FLAG_INTERNAL: Marks a property as internal-only, disallowing external user access.
Additionally, update object_property_set_flags() to implement the enforcement logic. When a property is flagged with OBJ_PROP_FLAG_USER_SET: - If the property is also marked OBJ_PROP_FLAG_DEPRECATED, report a warning. - If the property is also marked OBJ_PROP_FLAG_INTERNAL, raise an error and stop the operation.
Suggested-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 24 ++++++++++++++++++++++++ qom/object.c | 15 +++++++++++++++ 2 files changed, 39 insertions(+)
diff --git a/include/qom/object.h b/include/qom/object.h index 856b12e7289c..1b77429aa28b 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -109,6 +109,30 @@ typedef enum { * will automatically add a getter and a setter to this property. */ OBJ_PROP_FLAG_READWRITE = (OBJ_PROP_FLAG_READ | OBJ_PROP_FLAG_WRITE), + /* + * The property was explicitly set by an external user. + * + * This flag is set whenever the property is modified via external interfaces + * (CLI, QMP, HMP). It allows internal code to distinguish whether the + * property has been modified by the user. + * + * Once set, this flag persists even if the property value is subsequently + * overwritten by internal logic. It is NOT automatically cleared and must + * be explicitly cleared using object_property_clear_flags(). + */ + OBJ_PROP_FLAG_USER_SET = BIT(2), + /* + * The property is deprecated and will be removed in the future version. + * + * Any setting to this property by the user will raise a deprecation warning. + */ + OBJ_PROP_FLAG_DEPRECATED = BIT(3), + /* + * The property is internal only and cannot be set by the user. + * + * Any setting to this property by the user will raise an error. + */ + OBJ_PROP_FLAG_INTERNAL = BIT(4), } ObjectPropertyFlags;
I don't think this single enum design is very desirable, as it is mixing up pieces of information with three distinct lifetimes / scopes.
The OBJ_PROP_FLAD_{READ,WRITE,READWRITE} values are scoped to the execution of the property adder methods.
The OBJ_PROP_FLAG_{DEPRECATED,INTERNAL} values are scoped to the lifetime of the class.
The OBJ_PROP_FLAG_USER_SET value is scoped to the lifetime of the instance.
In fact, with my comment on the later patch, OBJ_PROP_FLAG_DEPRECATED should not be modelled as a boolean flag at all. We need to record a const char* deprecation_note internally, so that warn_report can provide useful info to the user. We can turn that into a "bool deprecated" flag in the QAPI command response for querying properties. 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 :|
On Tue, 10 Feb 2026, Zhao Liu wrote:
Introduce three new flags to `ObjectPropertyFlags` to better manage property interactions with external users (CLI, QMP, HMP):
1. OBJ_PROP_FLAG_USER_SET: Marks a property as having been modified by an external user.
This flag is designed to be "sticky": once set, it persists even if the property value is subsequently overwritten by internal logic. It allows the QEMU system to distinguish user intent.
The advantage of this design is that it is not needed to manually clear the USER_SET flag on every internal write. This simplifies the logic and decouples flag management from the current property setting path (object_property_set()).
This is chosen over a strict "current origin" approach (where internal writes would clear the flag) for a practical reason: QEMU code often modifies underlying struct fields (which are defined as properties) directly, bypassing the property API entirely. This makes it impossible to "accurately" track whether the *current* value truly comes from the user. Therefore, a sticky "user touched this" flag is the only meaningful and robust solution.
2. OBJ_PROP_FLAG_DEPRECATED: Marks a property as deprecated.
3. OBJ_PROP_FLAG_INTERNAL: Marks a property as internal-only, disallowing external user access.
Additionally, update object_property_set_flags() to implement the enforcement logic. When a property is flagged with OBJ_PROP_FLAG_USER_SET: - If the property is also marked OBJ_PROP_FLAG_DEPRECATED, report a warning. - If the property is also marked OBJ_PROP_FLAG_INTERNAL, raise an error and stop the operation.
Suggested-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 24 ++++++++++++++++++++++++ qom/object.c | 15 +++++++++++++++ 2 files changed, 39 insertions(+)
diff --git a/include/qom/object.h b/include/qom/object.h index 856b12e7289c..1b77429aa28b 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -109,6 +109,30 @@ typedef enum { * will automatically add a getter and a setter to this property. */ OBJ_PROP_FLAG_READWRITE = (OBJ_PROP_FLAG_READ | OBJ_PROP_FLAG_WRITE), + /* + * The property was explicitly set by an external user. + * + * This flag is set whenever the property is modified via external interfaces + * (CLI, QMP, HMP). It allows internal code to distinguish whether the + * property has been modified by the user. + * + * Once set, this flag persists even if the property value is subsequently + * overwritten by internal logic. It is NOT automatically cleared and must + * be explicitly cleared using object_property_clear_flags(). + */ + OBJ_PROP_FLAG_USER_SET = BIT(2),
As this isn't strictly for user set maybe jusr call it OBJ_PROP_FLAG_EXTERNAL? (Can be set by external management application or global compat prop in later patches so user set is not quite right name,)
There are now two major categories of global properties: One category consists of true global properties collected in global_props(), sourced from CLI options like `-global` and CPU features like `-cpu`. The other category comprises compat properties derived from object_compat_props[]. Within this, object_compat_props[0] and object_compat_props[1] represent compat properties for accelerators and machines, respectively. Meanwhile, object_compat_props[2] collects sugar properties from the CLI. Although sugar properties are also applied for legacy machine options (MachineClass::default_machine_opts), considerring those hardcoded defaults simulate CLI arguments, so treating them as USER_SET is acceptable as they emulate user behavior. Therefore, among all global properties, only those in global_props() and object_compat_props[2] originate from external users. Consequently, when applying global properties via object_apply_global_props(), these two categories of user-provided properties are marked as USER_SET by passing "from_user=true" to object_property_parse(). Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- hw/core/qdev-properties.c | 2 +- include/qom/object.h | 2 +- qom/object.c | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index c96ccfb26353..696dc5f201d6 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -1017,7 +1017,7 @@ int qdev_prop_check_globals(void) void qdev_prop_set_globals(DeviceState *dev) { - object_apply_global_props(OBJECT(dev), global_props(), + object_apply_global_props(OBJECT(dev), global_props(), true, dev->hotplugged ? NULL : &error_fatal); } diff --git a/include/qom/object.h b/include/qom/object.h index c78e1c03a106..b621803f61bb 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -751,7 +751,7 @@ Object *object_new_with_propv(const char *typename, va_list vargs); bool object_apply_global_props(Object *obj, const GPtrArray *props, - Error **errp); + bool from_user, Error **errp); void object_set_machine_compat_props(GPtrArray *compat_props); void object_set_accelerator_compat_props(GPtrArray *compat_props); void object_register_sugar_prop(const char *driver, const char *prop, diff --git a/qom/object.c b/qom/object.c index 7140e3f629aa..4ead0befb351 100644 --- a/qom/object.c +++ b/qom/object.c @@ -441,7 +441,7 @@ static void object_post_init_with_type(Object *obj, TypeImpl *ti) } bool object_apply_global_props(Object *obj, const GPtrArray *props, - Error **errp) + bool from_user, Error **errp) { int i; @@ -460,7 +460,8 @@ bool object_apply_global_props(Object *obj, const GPtrArray *props, continue; } p->used = true; - if (!object_property_parse(obj, p->property, p->value, false, &err)) { + if (!object_property_parse(obj, p->property, p->value, + from_user, &err)) { error_prepend(&err, "can't apply global %s.%s=%s: ", p->driver, p->property, p->value); /* @@ -536,6 +537,7 @@ void object_apply_compat_props(Object *obj) for (i = 0; i < ARRAY_SIZE(object_compat_props); i++) { object_apply_global_props(obj, object_compat_props[i], + i == 2 ? true : false, i == 2 ? &error_fatal : &error_abort); } } -- 2.34.1
Currently, object_property_parse() is used for both internal property settings and external user configurations (e.g., via HMP or global properties). To properly manage property flags (specifically OBJ_PROP_FLAG_USER_SET), it is necessary to identify the source of the property setting. Update object_property_parse() to accept a 'from_user' argument and set the USER_SET flag for the property if 'from_user=true'. As a first step, all existing callers are updated to have 'from_user= false'. Next the cases set by specific external user will be identified (like HMP and global properties) and will update 'from_user' argument to 'true'. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- hw/i386/sgx.c | 2 +- include/qom/object.h | 5 +++-- qom/object.c | 20 +++++++++++++++----- qom/qom-hmp-cmds.c | 2 +- system/vl.c | 2 +- target/i386/cpu.c | 4 ++-- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c index 5e792e8e6e96..8cb71be689ff 100644 --- a/hw/i386/sgx.c +++ b/hw/i386/sgx.c @@ -316,7 +316,7 @@ void pc_machine_init_sgx_epc(PCMachineState *pcms) /* set the memdev link with memory backend */ object_property_parse(OBJECT(dev), SGX_EPC_MEMDEV_PROP, - list->value->memdev, &error_fatal); + list->value->memdev, false, &error_fatal); /* set the numa node property for sgx epc object */ object_property_set_uint(OBJECT(dev), SGX_EPC_NUMA_NODE_PROP, list->value->node, &error_fatal); diff --git a/include/qom/object.h b/include/qom/object.h index 1b77429aa28b..c78e1c03a106 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1655,14 +1655,15 @@ bool object_property_set(Object *obj, const char *name, Visitor *v, * @obj: the object * @name: the name of the property * @string: the string that will be used to parse the property value. + * @from_user: whether the property is being set by a external user. * @errp: returns an error if this function fails * * Parses a string and writes the result into a property of an object. * * Returns: %true on success, %false on failure. */ -bool object_property_parse(Object *obj, const char *name, - const char *string, Error **errp); +bool object_property_parse(Object *obj, const char *name, const char *string, + bool from_user, Error **errp); /** * object_property_print: diff --git a/qom/object.c b/qom/object.c index 75a1fe7ea1d3..7140e3f629aa 100644 --- a/qom/object.c +++ b/qom/object.c @@ -460,7 +460,7 @@ bool object_apply_global_props(Object *obj, const GPtrArray *props, continue; } p->used = true; - if (!object_property_parse(obj, p->property, p->value, &err)) { + if (!object_property_parse(obj, p->property, p->value, false, &err)) { error_prepend(&err, "can't apply global %s.%s=%s: ", p->driver, p->property, p->value); /* @@ -882,7 +882,7 @@ bool object_set_propv(Object *obj, const char *value = va_arg(vargs, char *); g_assert(value != NULL); - if (!object_property_parse(obj, propname, value, errp)) { + if (!object_property_parse(obj, propname, value, false, errp)) { return false; } propname = va_arg(vargs, char *); @@ -1802,13 +1802,23 @@ int object_property_get_enum(Object *obj, const char *name, return ret; } -bool object_property_parse(Object *obj, const char *name, - const char *string, Error **errp) +bool object_property_parse(Object *obj, const char *name, const char *string, + bool from_user, Error **errp) { Visitor *v = string_input_visitor_new(string); - bool ok = object_property_set(obj, name, v, errp); + bool ok; + ok = object_property_set(obj, name, v, errp); visit_free(v); + + if (!ok) { + return false; + } + + if (from_user) { + ok = object_property_set_flags(obj, name, + OBJ_PROP_FLAG_USER_SET, errp); + } return ok; } diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index 32e40630c96a..6bdb241e54bd 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -58,7 +58,7 @@ void hmp_qom_set(Monitor *mon, const QDict *qdict) error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found", path); } else { - object_property_parse(obj, property, value, &err); + object_property_parse(obj, property, value, false, &err); } } else { QObject *obj = qobject_from_json(value, &err); diff --git a/system/vl.c b/system/vl.c index aa9a15504174..6d8167a50006 100644 --- a/system/vl.c +++ b/system/vl.c @@ -1708,7 +1708,7 @@ static int object_parse_property_opt(Object *obj, return 0; } - if (!object_property_parse(obj, name, value, errp)) { + if (!object_property_parse(obj, name, value, false, errp)) { return -1; } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 0a7b884528ea..94a9dcde1eb1 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -8089,7 +8089,7 @@ void x86_cpu_apply_props(X86CPU *cpu, PropValue *props) continue; } object_property_parse(OBJECT(cpu), pv->prop, pv->value, - &error_abort); + false, &error_abort); } } @@ -8112,7 +8112,7 @@ static void x86_cpu_apply_version_props(X86CPU *cpu, const X86CPUModel *model) for (p = vdef->props; p && p->prop; p++) { object_property_parse(OBJECT(cpu), p->prop, p->value, - &error_abort); + false, &error_abort); } if (vdef->version == version) { -- 2.34.1
The HMP command - "qom-set" is be used to set object property by external users, and object_property_parse() is used to parse and handle property setting for non-JSON case. Since the property setting is from user, pass "from_user=true" to object_property_parse() and mark properties set in this case as USER_SET. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- qom/qom-hmp-cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index 6bdb241e54bd..175091694f5f 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -58,7 +58,7 @@ void hmp_qom_set(Monitor *mon, const QDict *qdict) error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found", path); } else { - object_property_parse(obj, property, value, false, &err); + object_property_parse(obj, property, value, true, &err); } } else { QObject *obj = qobject_from_json(value, &err); -- 2.34.1
The QMP/HMP (JSON) command - "qom-set" is be used to set object property by external users, so it's from user and should be marked as USER_SET. Semantically, object_property_set_qobject() is used to convert a QObject into a property value, rather than directly parsing user input. Therefore, it is not suitable for adding a "from_user" argument like object_property_parse() does. Instead, use object_property_set_flags() to set USER_SET flag immediately after object_property_set_qobject(). Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- qom/qom-qmp-cmds.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c index 48b38d2b7f73..5a98ea276da2 100644 --- a/qom/qom-qmp-cmds.c +++ b/qom/qom-qmp-cmds.c @@ -134,7 +134,12 @@ void qmp_qom_set(const char *path, const char *property, QObject *value, return; } - object_property_set_qobject(obj, property, value, errp); + if (!object_property_set_qobject(obj, property, value, errp)) { + return; + } + + object_property_set_flags(obj, property, + OBJ_PROP_FLAG_USER_SET, errp); } QObject *qmp_qom_get(const char *path, const char *property, Error **errp) -- 2.34.1
object_set_properties_from_qdict() serves as the common entry point for parsing and setting properties from qdict (and keyval). This function is primarily utilized for external user configuration: 1. User Creatable Objects (via user_creatable_add_type()): - QMP: object-add - HMP: object_add - CLI: -object (qemu), --object (qemu-img * / qemu-io / qemu-nbd / qemu-storage-daemon) - Authz list files ("authz-list-file") 2. Device and Machine creation (keyval-based): - CLI: -machine / -device - QMP/HMP: device_add - Failover devices: virtio_net parses user's "qdict" in failover_add_primary(). 3. Built-in default machine options (MachineClass::default_machine_opts): - These hardcoded defaults simulate CLI arguments and are parsed via sugar property way or keyval. Treating them as USER_SET is acceptable as they emulate user behavior. There are a few internal corner cases where devices are created using an internal qdict: - Xen USB (usbback_portid_add()) - Intel HDA (intel_hda_and_codec_init()) Creating devices via internal qdict should be considered as legacy technical debt and this should be refactored in future work. For these cases, applying the USER_SET flag is a temporary and acceptable side effect. Therefor, update object_set_properties_from_qdict() to explicitly mark properties as USER_SET. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- qom/object_interfaces.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 415cbee8c5cf..f0d5f9d84300 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -56,6 +56,11 @@ static void object_set_properties_from_qdict(Object *obj, const QDict *qdict, if (!object_property_set(obj, e->key, v, errp)) { goto out; } + + if (!object_property_set_flags(obj, e->key, + OBJ_PROP_FLAG_USER_SET, errp)) { + goto out; + } } visit_check_struct(v, errp); out: -- 2.34.1
At present, object_parse_property_opt() is only used for -accel, which handles user configurations from CLI. So, mark the property as USER_SET in object_property_parse(). Also, add a comment to the function to clarify this specific usage context, and it can serve as a reminder to future callers that utilizing this function implies the property setting originates from the external user. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- system/vl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/system/vl.c b/system/vl.c index 6d8167a50006..ef1d4e5d96af 100644 --- a/system/vl.c +++ b/system/vl.c @@ -1700,6 +1700,10 @@ static MachineClass *select_machine(QDict *qdict, Error **errp) return machine_class; } +/* + * object_parse_property_opt() is only used for -accel, so mark the + * property as USER_SET in object_property_parse(). + */ static int object_parse_property_opt(Object *obj, const char *name, const char *value, const char *skip, Error **errp) @@ -1708,7 +1712,7 @@ static int object_parse_property_opt(Object *obj, return 0; } - if (!object_property_parse(obj, name, value, false, errp)) { + if (!object_property_parse(obj, name, value, true, errp)) { return -1; } -- 2.34.1
Update qdev property interfaces (qdev_property_add_static() and qdev_class_add_property()) to accept and pass 'ObjectPropertyFlags'. This enables marking qdev properties with flags such as DEPRECATED or INTERNAL. To facilitate this at the definition level, extend the boolean and uint8_t property macros (as the examples) to accept variable arguments (VA_ARGS). This allows callers to optionally specify flags in the property definition. Example: DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF, .flags = OBJECT_PROPERTY_DEPRECATED), Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- hw/core/qdev-properties.c | 26 +++++++++++++++----------- include/hw/core/qdev-properties.h | 24 ++++++++++++++---------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 696dc5f201d6..91c4010e7dc9 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -1071,11 +1071,13 @@ void qdev_property_add_static(DeviceState *dev, const Property *prop) assert(!prop->info->create); - op = object_property_add(obj, prop->name, prop->info->type, - field_prop_getter(prop->info), - field_prop_setter(prop->info), - prop->info->release, - (Property *)prop); + op = object_property_add_full(obj, prop->name, prop->info->type, + field_prop_getter(prop->info), + field_prop_setter(prop->info), + prop->info->release, + prop->flags, + (Property *)prop, + &error_abort); object_property_set_description(obj, prop->name, prop->info->description); @@ -1097,12 +1099,14 @@ static void qdev_class_add_property(DeviceClass *klass, const char *name, if (prop->info->create) { op = prop->info->create(oc, name, prop); } else { - op = object_class_property_add(oc, - name, prop->info->type, - field_prop_getter(prop->info), - field_prop_setter(prop->info), - prop->info->release, - (Property *)prop); + op = object_class_property_add_full(oc, + name, prop->info->type, + field_prop_getter(prop->info), + field_prop_setter(prop->info), + prop->info->release, + prop->flags, + (Property *)prop, + &error_abort); } if (prop->set_default) { prop->info->set_default_value(op, prop); diff --git a/include/hw/core/qdev-properties.h b/include/hw/core/qdev-properties.h index d8745d4c65f1..c06de37b1e9d 100644 --- a/include/hw/core/qdev-properties.h +++ b/include/hw/core/qdev-properties.h @@ -11,6 +11,7 @@ * and the field retains whatever value it was given by instance_init). * @defval: default value for the property. This is used only if @set_default * is true. + * @flags: property flags to control uses. */ struct Property { const char *name; @@ -27,6 +28,7 @@ struct Property { int arrayfieldsize; uint8_t bitnr; bool set_default; + uint8_t flags; }; struct PropertyInfo { @@ -97,10 +99,11 @@ extern const PropertyInfo qdev_prop_link; .set_default = true, \ .defval.u = (bool)_defval) -#define DEFINE_PROP_UNSIGNED(_name, _state, _field, _defval, _prop, _type) \ - DEFINE_PROP(_name, _state, _field, _prop, _type, \ - .set_default = true, \ - .defval.u = (_type)_defval) +#define DEFINE_PROP_UNSIGNED(_name, _state, _field, _defval, _prop, _type, ...) \ + DEFINE_PROP(_name, _state, _field, _prop, _type, \ + .set_default = true, \ + .defval.u = (_type)_defval, \ + ##__VA_ARGS__) #define DEFINE_PROP_UNSIGNED_NODEFAULT(_name, _state, _field, _prop, _type) \ DEFINE_PROP(_name, _state, _field, _prop, _type) @@ -118,10 +121,11 @@ extern const PropertyInfo qdev_prop_link; .set_default = true, \ .defval.i = (OnOffAuto)_defval) -#define DEFINE_PROP_BOOL(_name, _state, _field, _defval) \ - DEFINE_PROP(_name, _state, _field, qdev_prop_bool, bool, \ - .set_default = true, \ - .defval.u = (bool)_defval) +#define DEFINE_PROP_BOOL(_name, _state, _field, _defval, ...) \ + DEFINE_PROP(_name, _state, _field, qdev_prop_bool, bool, \ + .set_default = true, \ + .defval.u = (bool)_defval, \ + ##__VA_ARGS__) /** * The DEFINE_PROP_UINT64_CHECKMASK macro checks a user-supplied value @@ -168,8 +172,8 @@ extern const PropertyInfo qdev_prop_link; DEFINE_PROP(_name, _state, _field, qdev_prop_link, _ptr_type, \ .link_type = _type) -#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \ - DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_uint8, uint8_t) +#define DEFINE_PROP_UINT8(_n, _s, _f, _d, ...) \ + DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_uint8, uint8_t, ##__VA_ARGS__) #define DEFINE_PROP_UINT16(_n, _s, _f, _d) \ DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_uint16, uint16_t) #define DEFINE_PROP_UINT32(_n, _s, _f, _d) \ -- 2.34.1
On Tue, Feb 10, 2026 at 11:23:41 +0800, Zhao Liu wrote:
Update qdev property interfaces (qdev_property_add_static() and qdev_class_add_property()) to accept and pass 'ObjectPropertyFlags'. This enables marking qdev properties with flags such as DEPRECATED or INTERNAL.
To facilitate this at the definition level, extend the boolean and uint8_t property macros (as the examples) to accept variable arguments (VA_ARGS). This allows callers to optionally specify flags in the property definition.
Example:
DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF, .flags = OBJECT_PROPERTY_DEPRECATED),
Is there a plan to expose at least the _DEPRECATED property to be introspectable (e.g. via qom-list-properties or device-list-properties) ? In libvirt we try to stay proactive about adapting to deprecations and this would allow our test-suite to detect deprecations programmaticaly similarly to how we detect deprecations via query-qmp-schema. Although with the current patchset there doesn't seem to be anything that libvirt would need to adapt to.
On Tue, Feb 10, 2026 at 11:23:41AM +0800, Zhao Liu wrote:
Update qdev property interfaces (qdev_property_add_static() and qdev_class_add_property()) to accept and pass 'ObjectPropertyFlags'. This enables marking qdev properties with flags such as DEPRECATED or INTERNAL.
To facilitate this at the definition level, extend the boolean and uint8_t property macros (as the examples) to accept variable arguments (VA_ARGS). This allows callers to optionally specify flags in the property definition.
Example:
DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF, .flags = OBJECT_PROPERTY_DEPRECATED),
In other places where we track deprecation in QEMU, we have not used a boolean flag. Instead we have used a "const char *deprecation_note" internally, which lets us provide a user facing message, to be printed out in the warn_report, informing them what to do instead (either the feature is entirely removed, or there is a better alternative). IMHO we should be following the same pattern for properties, as it is much more user friendly than just printing a totally generic message "XXXX is deprecated, stop using it" 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 :|
"fill-mtee-mask" was previously disabled only on PC-Q35-2.6 and PC-I440FX-2.6 machines, but PC v2.6 machines have been deprecated and will be removed. Considerring it may have external use, so deprecate it before removal. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- docs/about/deprecated.rst | 8 ++++++++ target/i386/cpu.c | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 1d5c4f3707cb..0e8a25e37414 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -448,6 +448,14 @@ Backend ``memory`` (since 9.0) CPU device properties ''''''''''''''''''''' +``fill-mtrr-mask`` on x86 (since 11.0) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``fill-mtrr-mask=true`` fill the bits between 51..number-of-physical-address +-bits in the MTRR_PHYSMASKn variable range mtrr masks. It was previously set to +false only on PC-Q35-2.6 and PC-I440FX-2.6 machines, but PC v2.6 machines have +been removed. Deprecate this property to stop external use. + ``pmu-num=n`` on RISC-V CPUs (since 8.2) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 94a9dcde1eb1..13ccb1702d32 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -10510,7 +10510,8 @@ static const Property x86_cpu_properties[] = { DEFINE_PROP_UINT32("guest-phys-bits", X86CPU, guest_phys_bits, -1), DEFINE_PROP_BOOL("host-phys-bits", X86CPU, host_phys_bits, false), DEFINE_PROP_UINT8("host-phys-bits-limit", X86CPU, host_phys_bits_limit, 0), - DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true), + DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true, + .flags = OBJ_PROP_FLAG_DEPRECATED), DEFINE_PROP_UINT32("level-func7", X86CPU, env.cpuid_level_func7, UINT32_MAX), DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, UINT32_MAX), -- 2.34.1
"cpuid-0xb" was previously disabled only on PC-Q35-2.6 and PC-I440FX-2.6 machines, but PC v2.6 machines have been deprecated and will be removed. Considerring it may have external use, so deprecate it before removal. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- docs/about/deprecated.rst | 10 ++++++++++ target/i386/cpu.c | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 0e8a25e37414..fed939b7f042 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -456,6 +456,16 @@ The ``fill-mtrr-mask=true`` fill the bits between 51..number-of-physical-address false only on PC-Q35-2.6 and PC-I440FX-2.6 machines, but PC v2.6 machines have been removed. Deprecate this property to stop external use. +``cpuid-0xb`` on x86 (since 11.0) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``cpuid-0xb`` is used to control whether to encode CPUID 0xB leaf or not. +Only legacy x86 CPUs didn't have 0xB leaf, and the ```level``` property can +control whether CPUID exposes the 0xB leaf and emulate legacy CPUs. This +property was previously set to false only on PC-Q35-2.6 and PC-I440FX-2.6 +machines, but PC v2.6 machines have been removed. Deprecate this property to +stop external use. + ``pmu-num=n`` on RISC-V CPUs (since 8.2) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 13ccb1702d32..3766d453157b 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -10523,7 +10523,8 @@ static const Property x86_cpu_properties[] = { DEFINE_PROP_UINT64("ucode-rev", X86CPU, ucode_rev, 0), DEFINE_PROP_BOOL("full-cpuid-auto-level", X86CPU, full_cpuid_auto_level, true), DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor), - DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true), + DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true, + .flags = OBJ_PROP_FLAG_DEPRECATED), DEFINE_PROP_BOOL("x-vendor-cpuid-only", X86CPU, vendor_cpuid_only, true), DEFINE_PROP_BOOL("x-vendor-cpuid-only-v2", X86CPU, vendor_cpuid_only_v2, true), DEFINE_PROP_BOOL("x-amd-topoext-features-only", X86CPU, amd_topoext_features_only, true), -- 2.34.1
"version" was previously set to "0x11" for v2.7 x86 machines, but v2.7 machines have been deprecated and will be removed. And since v2.8, all x86 machines are using IOAPIC with "0x20" version. So it should be not needed to configure the version back to "0x11" again. Considerring it may have external use, so deprecate it before removal. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- docs/about/deprecated.rst | 13 +++++++++++++ hw/intc/ioapic.c | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index fed939b7f042..dac1940636a6 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -483,6 +483,19 @@ It was implemented as a no-op instruction in TCG up to QEMU 9.0, but only with ``-cpu max`` (which does not guarantee migration compatibility across versions). + +Global options +-------------- + +``-global ioapic.version=version_id`` (since 11.0) +'''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``version`` configures IOAPIC version for x86 machines. It was previously +set to ``0x11`` for v2.7 machines, and since v2.8, the default version is +bumped up to ``0x20``. The v2.7 machines have been removed, and ``0x11`` +version should be not needed. Deprecate this property to stop external use. + + Backwards compatibility ----------------------- diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 98de6ca8108f..3bf21f421a71 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -483,7 +483,8 @@ static void ioapic_unrealize(DeviceState *dev) } static const Property ioapic_properties[] = { - DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF), + DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF, + .flags = OBJ_PROP_FLAG_DEPRECATED), }; static void ioapic_class_init(ObjectClass *klass, const void *data) -- 2.34.1
x-consistent-cache property is a compatibility option that defaults to "true". For old machines, it is set to "false" to maintain the (legacy) inconsistent cache model for Intel CPUs. In fact, such wrong and inconsistent cache model should be treated as buggy "hardware", so that there is no valid use case for users to manually disable this property. Therefore, mark it as internal-only via OBJ_PROP_FLAG_INTERNAL flag, and prohibit all external settings. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- target/i386/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 3766d453157b..c2f99b98014a 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -10541,7 +10541,8 @@ static const Property x86_cpu_properties[] = { * own cache information (see x86_cpu_load_def()). */ DEFINE_PROP_BOOL("legacy-cache", X86CPU, legacy_cache, true), - DEFINE_PROP_BOOL("x-consistent-cache", X86CPU, consistent_cache, true), + DEFINE_PROP_BOOL("x-consistent-cache", X86CPU, consistent_cache, true, + .flags = OBJ_PROP_FLAG_INTERNAL), DEFINE_PROP_BOOL("legacy-multi-node", X86CPU, legacy_multi_node, false), DEFINE_PROP_BOOL("xen-vapic", X86CPU, xen_vapic, false), -- 2.34.1
The 'lbr-fmt' property is defined via DEFINE_PROP_UINT64_CHECKMASK, utilizing PERF_CAP_LBR_FMT as the validation mask. This mechanism ensures that the property setter rejects any value attempting to set bits outside this mask. So cpu->lbr_fmt is guaranteed to be valid by the time x86_cpu_realizefn() executes. The manual validation inside the realize function is therefore redundant. Remove the unnecessary check. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- target/i386/cpu.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index c2f99b98014a..a594747f0030 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -9816,10 +9816,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) * with user-provided setting. */ if (cpu->lbr_fmt != ~PERF_CAP_LBR_FMT) { - if ((cpu->lbr_fmt & PERF_CAP_LBR_FMT) != cpu->lbr_fmt) { - error_setg(errp, "invalid lbr-fmt"); - return; - } env->features[FEAT_PERF_CAPABILITIES] &= ~PERF_CAP_LBR_FMT; env->features[FEAT_PERF_CAPABILITIES] |= cpu->lbr_fmt; } -- 2.34.1
At present, QEMU determines if the user has set the "lbr-fmt" property by checking if its value differs from a special value, `~PERF_CAP_LBR_FMT` (`~0x3f`). Relying on such a magic number to distinguish user input from the default state is implicit and fragile. It also prevents the helper macro `DEFINE_PROP_UINT64_CHECKMASK` from supporting a *valid* default value, as initializing the property with a valid default would make it impossible to distinguish from a user-provided value. With the introduction of `OBJ_PROP_FLAG_USER_SET`, it's possible to directly check this flag to determine whether the user has modified the property, which can help get rid of invalid "sentinel" value. Therefore, detect user-provided value by checking the USER_SET property flag in x86_cpu_realizefn(). The invalid initialization value will be dropped in subsequent work. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- target/i386/cpu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index a594747f0030..a6d943c53a3f 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -9779,6 +9779,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) CPUX86State *env = &cpu->env; Error *local_err = NULL; unsigned requested_lbr_fmt; + int lbr_fmt_set; #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) /* Use pc-relative instructions in system-mode */ @@ -9815,7 +9816,11 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) * Override env->features[FEAT_PERF_CAPABILITIES].LBR_FMT * with user-provided setting. */ - if (cpu->lbr_fmt != ~PERF_CAP_LBR_FMT) { + lbr_fmt_set = object_property_check_flags(OBJECT(dev), "lbr-fmt", + OBJ_PROP_FLAG_USER_SET, errp); + if (lbr_fmt_set < 0) { + return; + } else if (lbr_fmt_set > 0) { env->features[FEAT_PERF_CAPABILITIES] &= ~PERF_CAP_LBR_FMT; env->features[FEAT_PERF_CAPABILITIES] |= cpu->lbr_fmt; } -- 2.34.1
DEFINE_PROP_UINT64_CHECKMASK is designed to detect and check user's property setting: * checking: check property value against a bitmask. * detection: ask caller to provide an invalid value as the initial "sentinel" value, which is impossible to be set by users. However, this detection is not strict, since the property could be also set internally. The entire mechanism is not easy to use. Now there's USER_SET flag in place (and the current unique use case "lbr-fmt" has been converted to checking USER_SET way), manual setting of invalid initial values is no longer required. Thus, extend DEFINE_PROP_UINT64_CHECKMASK to support *valid* default value, and for "lbr-fmt" case, replace the invalid initialization value `~PERF_CAP_LBR_FMT` with a valid value `0`. In addition, considering DEFINE_PROP_UINT64_CHECKMASK itself actually doesn't identify whether the property is set by the user or not, remove "user-supplied" related description in its document. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- hw/core/qdev-properties.c | 1 + include/hw/core/qdev-properties.h | 14 +++++++------- target/i386/cpu.c | 4 +--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 91c4010e7dc9..b84214e60f19 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -507,6 +507,7 @@ const PropertyInfo qdev_prop_uint64_checkmask = { .type = "uint64", .get = get_uint64, .set = set_uint64_checkmask, + .set_default_value = qdev_propinfo_set_default_value_uint, }; /* --- pointer-size integer --- */ diff --git a/include/hw/core/qdev-properties.h b/include/hw/core/qdev-properties.h index c06de37b1e9d..2ac784bb5e9c 100644 --- a/include/hw/core/qdev-properties.h +++ b/include/hw/core/qdev-properties.h @@ -128,14 +128,14 @@ extern const PropertyInfo qdev_prop_link; ##__VA_ARGS__) /** - * The DEFINE_PROP_UINT64_CHECKMASK macro checks a user-supplied value - * against corresponding bitmask, rejects the value if it violates. - * The default value is set in instance_init(). + * The DEFINE_PROP_UINT64_CHECKMASK macro checks a value against corresponding + * bitmask, rejects the value if it violates. */ -#define DEFINE_PROP_UINT64_CHECKMASK(_name, _state, _field, _bitmask) \ - DEFINE_PROP(_name, _state, _field, qdev_prop_uint64_checkmask, uint64_t, \ - .bitmask = (_bitmask), \ - .set_default = false) +#define DEFINE_PROP_UINT64_CHECKMASK(_name, _state, _field, _bitmask, _defval) \ + DEFINE_PROP(_name, _state, _field, qdev_prop_uint64_checkmask, uint64_t, \ + .bitmask = (_bitmask), \ + .set_default = true, \ + .defval.u = (_defval)) /** * DEFINE_PROP_ARRAY: diff --git a/target/i386/cpu.c b/target/i386/cpu.c index a6d943c53a3f..56735570d66c 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -10265,9 +10265,7 @@ static void x86_cpu_initfn(Object *obj) object_property_add_alias(obj, "pause_filter", obj, "pause-filter"); object_property_add_alias(obj, "sse4_1", obj, "sse4.1"); object_property_add_alias(obj, "sse4_2", obj, "sse4.2"); - object_property_add_alias(obj, "hv-apicv", obj, "hv-avic"); - cpu->lbr_fmt = ~PERF_CAP_LBR_FMT; object_property_add_alias(obj, "lbr_fmt", obj, "lbr-fmt"); if (xcc->model) { @@ -10439,7 +10437,7 @@ static const Property x86_cpu_properties[] = { #endif DEFINE_PROP_INT32("node-id", X86CPU, node_id, CPU_UNSET_NUMA_NODE_ID), DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false), - DEFINE_PROP_UINT64_CHECKMASK("lbr-fmt", X86CPU, lbr_fmt, PERF_CAP_LBR_FMT), + DEFINE_PROP_UINT64_CHECKMASK("lbr-fmt", X86CPU, lbr_fmt, PERF_CAP_LBR_FMT, 0), DEFINE_PROP_UINT32("hv-spinlocks", X86CPU, hyperv_spinlock_attempts, HYPERV_SPINLOCK_NEVER_NOTIFY), -- 2.34.1
On Tue, Feb 10, 2026 at 11:23:27AM +0800, Zhao Liu wrote:
Hi,
This is the v2 trying to introduce property flags to detect user's property setting (from CLI/QMP/HMP). I dropped RFC tag since previous RFC v1 [1].
This says what the series is proposing, but IMHO what is more important here is explaining why this either desirable or appropriate to add as general facility in QOM. The idea that code should take different action for a given fixed value, based on whether the value was set by the user, or left on the default, makes me very uncomfortable. There have been a number of situations where something that was initially a boolean flag, actually needed to be a tri-state instead, to provide semantics like "On", "Off", "Auto". This "user set" flag could support such behaviour indirectly, but since "user set" is an internal concept we'd still be only exposing a boolean externally, while using a tri-state internally. That does not give the full flexibility of a tri-state, because internally if we wanted to have the default to be "yes", it offers no way for the mgmt app to put it back to "auto". For properties that are not booleans, it is much less obvious to me whether we actually need a distinct "not set" concept at all. So overall, at a conceptual level, I don't think that QOM should care about /how/ a value came to be set. It should have no direct awareness of the "user input", rather it just represents the configuration of the system at a given point in time, however that came to pass. 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 :|
On Tue, Feb 10, 2026 at 10:12:38AM +0000, Daniel P. Berrangé wrote:
On Tue, Feb 10, 2026 at 11:23:27AM +0800, Zhao Liu wrote:
Hi,
This is the v2 trying to introduce property flags to detect user's property setting (from CLI/QMP/HMP). I dropped RFC tag since previous RFC v1 [1].
This says what the series is proposing, but IMHO what is more important here is explaining why this either desirable or appropriate to add as general facility in QOM.
The idea that code should take different action for a given fixed value, based on whether the value was set by the user, or left on the default, makes me very uncomfortable.
There have been a number of situations where something that was initially a boolean flag, actually needed to be a tri-state instead, to provide semantics like "On", "Off", "Auto".
But "auto" is exactly a property specific way to work around this. With this, we could allow "auto" for any property (except strings I guess) without per property code.
This "user set" flag could support such behaviour indirectly, but since "user set" is an internal concept we'd still be only exposing a boolean externally, while using a tri-state internally. That does not give the full flexibility of a tri-state, because internally if we wanted to have the default to be "yes", it offers no way for the mgmt app to put it back to "auto".
I do not get it. Of course user set is an external concept. It is user controllable!
For properties that are not booleans, it is much less obvious to me whether we actually need a distinct "not set" concept at all.
So overall, at a conceptual level, I don't think that QOM should care about /how/ a value came to be set. It should have no direct awareness of the "user input", rather it just represents the configuration of the system at a given point in time, however that came to pass.
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 :|
On Tue, Feb 10, 2026 at 05:44:50AM -0500, Michael S. Tsirkin wrote:
On Tue, Feb 10, 2026 at 10:12:38AM +0000, Daniel P. Berrangé wrote:
On Tue, Feb 10, 2026 at 11:23:27AM +0800, Zhao Liu wrote:
Hi,
This is the v2 trying to introduce property flags to detect user's property setting (from CLI/QMP/HMP). I dropped RFC tag since previous RFC v1 [1].
This says what the series is proposing, but IMHO what is more important here is explaining why this either desirable or appropriate to add as general facility in QOM.
The idea that code should take different action for a given fixed value, based on whether the value was set by the user, or left on the default, makes me very uncomfortable.
There have been a number of situations where something that was initially a boolean flag, actually needed to be a tri-state instead, to provide semantics like "On", "Off", "Auto".
But "auto" is exactly a property specific way to work around this. With this, we could allow "auto" for any property (except strings I guess) without per property code.
This "user set" flag could support such behaviour indirectly, but since "user set" is an internal concept we'd still be only exposing a boolean externally, while using a tri-state internally. That does not give the full flexibility of a tri-state, because internally if we wanted to have the default to be "yes", it offers no way for the mgmt app to put it back to "auto".
I do not get it. Of course user set is an external concept. It is user controllable!
If a property is modelled as a tri-state today the user can explicitly request any of the three values -object foo,prop=on -object foo,prop=off -object foo,prop=auto If a property is modelled as a boolean, and we have this new internal "user set" flag to represent the "auto" scenario, the user can only do -object foo,prop=on -object foo,prop=off we're missing the ability to explicitly request the "auto" value, which could be needed if we decide the internal default should be either "on" or "off". This "user default" flag concept is special casing support for tri-states in a way that is worse than what we can already do in QAPI. That feels like a mistake / bad path to go down to me. 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 :|
On Tue, 10 Feb 2026, Daniel P. Berrangé wrote:
On Tue, Feb 10, 2026 at 05:44:50AM -0500, Michael S. Tsirkin wrote:
On Tue, Feb 10, 2026 at 10:12:38AM +0000, Daniel P. Berrangé wrote:
On Tue, Feb 10, 2026 at 11:23:27AM +0800, Zhao Liu wrote:
Hi,
This is the v2 trying to introduce property flags to detect user's property setting (from CLI/QMP/HMP). I dropped RFC tag since previous RFC v1 [1].
This says what the series is proposing, but IMHO what is more important here is explaining why this either desirable or appropriate to add as general facility in QOM.
The idea that code should take different action for a given fixed value, based on whether the value was set by the user, or left on the default, makes me very uncomfortable.
There have been a number of situations where something that was initially a boolean flag, actually needed to be a tri-state instead, to provide semantics like "On", "Off", "Auto".
But "auto" is exactly a property specific way to work around this. With this, we could allow "auto" for any property (except strings I guess) without per property code.
This "user set" flag could support such behaviour indirectly, but since "user set" is an internal concept we'd still be only exposing a boolean externally, while using a tri-state internally. That does not give the full flexibility of a tri-state, because internally if we wanted to have the default to be "yes", it offers no way for the mgmt app to put it back to "auto".
I do not get it. Of course user set is an external concept. It is user controllable!
If a property is modelled as a tri-state today the user can explicitly request any of the three values
-object foo,prop=on -object foo,prop=off -object foo,prop=auto
If a property is modelled as a boolean, and we have this new internal "user set" flag to represent the "auto" scenario, the user can only do
-object foo,prop=on -object foo,prop=off
we're missing the ability to explicitly request the "auto" value, which could be needed if we decide the internal default should be either "on" or "off".
In this case the auto setting would be not setting the property at all to any value by the user.
This "user default" flag concept is special casing support for tri-states in a way that is worse than what we can already do in QAPI. That feels like a mistake / bad path to go down to me.
I also don't really like the USER_SET name so commented to rename to EXTERNAL but thinking more do we need both EXTERNAL/USER_SET and INTERNAL? One of the two would be the default behaviour for untagged properties so maybe we only need to flag INTERNAL to omit them from introspection and user setting but don't need to touch normal user settable properties (apart from adding deprecarion_message that also replaces DEPRECATED flag. But I don't have clear idea or opinion on this so these are more questions than suggestions. Regards, BALATON Zoltan
participants (5)
-
BALATON Zoltan -
Daniel P. Berrangé -
Michael S. Tsirkin -
Peter Krempa -
Zhao Liu