[RFC 00/10] qom: Support marking object properties as deprecated
Hi, This RFC is the follow-up work of v2.6 & v2.7 machines' removal [*], and tries to introduce a general way to provide deprecation hint for external user. Its core idea is to detect external property settings (as well as specific internal property settings, such as the compat property). I think deprecated properties and internal-only properties are quite similar, as both require consideration of external property usage. But the former only triggers a warning, while the latter stops all external access attempts. For simplicity, this RFC series only considers deprecated properties. Brief Introduction ================== Now the common (but a bit fragmented) way to mark a property deprecated is to add the warning in its accssors, or just document the deprecation in docs/about/deprecated.rst without any hint when someone touches that property. Ideally, it's better to provide some hints to external user when he tries to set the property via command line or HMP. But this is pretty inconvenient (even impossible) for such qdev properties, which are defined via DEFINE_PROP_* macros in the Property array. For qdev properties, their accessors are provided by pre-defined PropertyInfo, so that it's possible to modify PropertyInfo for a single "deprecated" property. Then it's necessary to introduce property flags to mark some properties as deprecated, and to check the property flags when set the property, thereby to print a deprecation warning. This not only benefits traditional qdev properties but also helps the deprecation of generic objects. Note, internal attempt (except the compat case) should not trigger the deprecation warning but external user should see the deprecation information. I think the most complex part is identifying the paths for property settings (both external command-line options and internal specific configurations). This series currently covers the following scenarios (which I consider to be particularly important): External cases: 1) External global properties: * -global command line option. * -cpu command line features. * suger properties from object_compat_props[2] 2) External ("TYPE_USER_CREATABLE") object: * -object command line used for external ("TYPE_USER_CREATABLE") object. 3) External device: * -device command line - parsed based on keyval or json. 4) External machine options: * -machine command line - parsed based on keyval. 5) External accelerator options: * -accel command line. 6) HMP command: * "qom-set" command. Internal cases: 1) internal global properties: * compat properties from object_compat_props[0,1]. 2) Internal machine options: * Builtin default machine options string: MachineClass::default_machine_opts - parsed based on keyval, too. In fact, there are still some special device command lines that haven't been considered yet. But I believe the remaining cases can be gradually expanded? If this approach is feasible, it's possible to further introduce an "internal" flag to prevent external access to compat property. [*]: hw/i386/pc: Remove deprecated 2.6 and 2.7 PC machines https://lore.kernel.org/qemu-devel/20251202162835.3227894-1-zhao1.liu@intel.... Thanks and Best Regards, Zhao --- Zhao Liu (10): qom: Rename ObjectPropertyFlags to ObjectPropertyAccessorFlags qom: Add basic object property deprecation hint support qom: Check property deprecation flag for global property qom: Check property deprecation flag for properities from qdict system/vl: Check property deprecation flag for properities of accelerator qom/qom-hmp-cmd: Check property deprecation flag for "qom-set" command hw/core/qdev-properties: Allow to mark qdev property as deprecated target/i386: Deprecate fill-mtrr-mask property target/i386: Deprecate cpuid-0xb property hw/intc/ioapic: Deprecate version property docs/about/deprecated.rst | 31 +++++++++ hw/core/qdev-properties.c | 24 +++---- hw/intc/ioapic.c | 3 +- include/hw/qdev-properties.h | 18 ++++++ include/qom/object.h | 120 +++++++++++++++++++++++++++++++---- qom/object.c | 101 ++++++++++++++++++++++------- qom/object_interfaces.c | 2 +- qom/qom-hmp-cmds.c | 2 +- system/vl.c | 2 +- target/i386/cpu.c | 4 +- 10 files changed, 253 insertions(+), 54 deletions(-) -- 2.34.1
At present, ObjectPropertyFlags is used to select accessors and such flags won't be stored in ObjectProperty itself. So it's not proper to extend this ObjectPropertyFlags for "deprecated" or "internal" flags. Therefore, rename ObjectPropertyFlags to ObjectPropertyAccessorFlags, and then the original name ObjectPropertyFlags can be used for other cases. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 28 ++++++++++++++-------------- qom/object.c | 16 ++++++++-------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 26df6137b911..3f807a03f5aa 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1846,14 +1846,14 @@ typedef enum { OBJ_PROP_FLAG_WRITE = 1 << 1, /* Automatically add a getter and a setter to the property */ OBJ_PROP_FLAG_READWRITE = (OBJ_PROP_FLAG_READ | OBJ_PROP_FLAG_WRITE), -} ObjectPropertyFlags; +} ObjectPropertyAccessorFlags; /** * object_property_add_uint8_ptr: * @obj: the object to add a property to * @name: the name of the property * @v: pointer to value - * @flags: bitwise-or'd ObjectPropertyFlags + * @flags: bitwise-or'd ObjectPropertyAccessorFlags * * Add an integer property in memory. This function will add a * property of type 'uint8'. @@ -1861,20 +1861,20 @@ typedef enum { * Returns: The newly added property on success, or %NULL on failure. */ ObjectProperty *object_property_add_uint8_ptr(Object *obj, const char *name, - const uint8_t *v, - ObjectPropertyFlags flags); + const uint8_t *v, + ObjectPropertyAccessorFlags flags); ObjectProperty *object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, const uint8_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags); /** * object_property_add_uint16_ptr: * @obj: the object to add a property to * @name: the name of the property * @v: pointer to value - * @flags: bitwise-or'd ObjectPropertyFlags + * @flags: bitwise-or'd ObjectPropertyAccessorFlags * * Add an integer property in memory. This function will add a * property of type 'uint16'. @@ -1883,19 +1883,19 @@ ObjectProperty *object_class_property_add_uint8_ptr(ObjectClass *klass, */ ObjectProperty *object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags); ObjectProperty *object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, const uint16_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags); /** * object_property_add_uint32_ptr: * @obj: the object to add a property to * @name: the name of the property * @v: pointer to value - * @flags: bitwise-or'd ObjectPropertyFlags + * @flags: bitwise-or'd ObjectPropertyAccessorFlags * * Add an integer property in memory. This function will add a * property of type 'uint32'. @@ -1904,19 +1904,19 @@ ObjectProperty *object_class_property_add_uint16_ptr(ObjectClass *klass, */ ObjectProperty *object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags); ObjectProperty *object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, const uint32_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags); /** * object_property_add_uint64_ptr: * @obj: the object to add a property to * @name: the name of the property * @v: pointer to value - * @flags: bitwise-or'd ObjectPropertyFlags + * @flags: bitwise-or'd ObjectPropertyAccessorFlags * * Add an integer property in memory. This function will add a * property of type 'uint64'. @@ -1925,12 +1925,12 @@ ObjectProperty *object_class_property_add_uint32_ptr(ObjectClass *klass, */ ObjectProperty *object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags); ObjectProperty *object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, const uint64_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags); /** * object_property_add_alias: diff --git a/qom/object.c b/qom/object.c index 4f32c1aba7d7..85d31bb64b36 100644 --- a/qom/object.c +++ b/qom/object.c @@ -2636,7 +2636,7 @@ static void property_set_uint64_ptr(Object *obj, Visitor *v, const char *name, ObjectProperty * object_property_add_uint8_ptr(Object *obj, const char *name, const uint8_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2656,7 +2656,7 @@ object_property_add_uint8_ptr(Object *obj, const char *name, ObjectProperty * object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, const uint8_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2676,7 +2676,7 @@ object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, ObjectProperty * object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2696,7 +2696,7 @@ object_property_add_uint16_ptr(Object *obj, const char *name, ObjectProperty * object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, const uint16_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2716,7 +2716,7 @@ object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, ObjectProperty * object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2736,7 +2736,7 @@ object_property_add_uint32_ptr(Object *obj, const char *name, ObjectProperty * object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, const uint32_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2756,7 +2756,7 @@ object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, ObjectProperty * object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2776,7 +2776,7 @@ object_property_add_uint64_ptr(Object *obj, const char *name, ObjectProperty * object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, const uint64_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; -- 2.34.1
On Wed, 3 Dec 2025 01:04:53 +0800 Zhao Liu <zhao1.liu@intel.com> wrote:
At present, ObjectPropertyFlags is used to select accessors and such flags won't be stored in ObjectProperty itself.
So it's not proper to extend this ObjectPropertyFlags for "deprecated" or "internal" flags.
Therefore, rename ObjectPropertyFlags to ObjectPropertyAccessorFlags, and then the original name ObjectPropertyFlags can be used for other cases.
I wonder if we can just make existing ObjectPropertyFlags per object as you are planing and still continue using it for accessor flags. That basically will lets you use new flags everywhere without rewriting call sites everywhere.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 28 ++++++++++++++-------------- qom/object.c | 16 ++++++++-------- 2 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/include/qom/object.h b/include/qom/object.h index 26df6137b911..3f807a03f5aa 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1846,14 +1846,14 @@ typedef enum { OBJ_PROP_FLAG_WRITE = 1 << 1, /* Automatically add a getter and a setter to the property */ OBJ_PROP_FLAG_READWRITE = (OBJ_PROP_FLAG_READ | OBJ_PROP_FLAG_WRITE), -} ObjectPropertyFlags; +} ObjectPropertyAccessorFlags;
/** * object_property_add_uint8_ptr: * @obj: the object to add a property to * @name: the name of the property * @v: pointer to value - * @flags: bitwise-or'd ObjectPropertyFlags + * @flags: bitwise-or'd ObjectPropertyAccessorFlags * * Add an integer property in memory. This function will add a * property of type 'uint8'. @@ -1861,20 +1861,20 @@ typedef enum { * Returns: The newly added property on success, or %NULL on failure. */ ObjectProperty *object_property_add_uint8_ptr(Object *obj, const char *name, - const uint8_t *v, - ObjectPropertyFlags flags); + const uint8_t *v, + ObjectPropertyAccessorFlags flags);
ObjectProperty *object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, const uint8_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags);
/** * object_property_add_uint16_ptr: * @obj: the object to add a property to * @name: the name of the property * @v: pointer to value - * @flags: bitwise-or'd ObjectPropertyFlags + * @flags: bitwise-or'd ObjectPropertyAccessorFlags * * Add an integer property in memory. This function will add a * property of type 'uint16'. @@ -1883,19 +1883,19 @@ ObjectProperty *object_class_property_add_uint8_ptr(ObjectClass *klass, */ ObjectProperty *object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags);
ObjectProperty *object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, const uint16_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags);
/** * object_property_add_uint32_ptr: * @obj: the object to add a property to * @name: the name of the property * @v: pointer to value - * @flags: bitwise-or'd ObjectPropertyFlags + * @flags: bitwise-or'd ObjectPropertyAccessorFlags * * Add an integer property in memory. This function will add a * property of type 'uint32'. @@ -1904,19 +1904,19 @@ ObjectProperty *object_class_property_add_uint16_ptr(ObjectClass *klass, */ ObjectProperty *object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags);
ObjectProperty *object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, const uint32_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags);
/** * object_property_add_uint64_ptr: * @obj: the object to add a property to * @name: the name of the property * @v: pointer to value - * @flags: bitwise-or'd ObjectPropertyFlags + * @flags: bitwise-or'd ObjectPropertyAccessorFlags * * Add an integer property in memory. This function will add a * property of type 'uint64'. @@ -1925,12 +1925,12 @@ ObjectProperty *object_class_property_add_uint32_ptr(ObjectClass *klass, */ ObjectProperty *object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags);
ObjectProperty *object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, const uint64_t *v, - ObjectPropertyFlags flags); + ObjectPropertyAccessorFlags flags);
/** * object_property_add_alias: diff --git a/qom/object.c b/qom/object.c index 4f32c1aba7d7..85d31bb64b36 100644 --- a/qom/object.c +++ b/qom/object.c @@ -2636,7 +2636,7 @@ static void property_set_uint64_ptr(Object *obj, Visitor *v, const char *name, ObjectProperty * object_property_add_uint8_ptr(Object *obj, const char *name, const uint8_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2656,7 +2656,7 @@ object_property_add_uint8_ptr(Object *obj, const char *name, ObjectProperty * object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, const uint8_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2676,7 +2676,7 @@ object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, ObjectProperty * object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2696,7 +2696,7 @@ object_property_add_uint16_ptr(Object *obj, const char *name, ObjectProperty * object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, const uint16_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2716,7 +2716,7 @@ object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, ObjectProperty * object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2736,7 +2736,7 @@ object_property_add_uint32_ptr(Object *obj, const char *name, ObjectProperty * object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, const uint32_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2756,7 +2756,7 @@ object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, ObjectProperty * object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2776,7 +2776,7 @@ object_property_add_uint64_ptr(Object *obj, const char *name, ObjectProperty * object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, const uint64_t *v, - ObjectPropertyFlags flags) + ObjectPropertyAccessorFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL;
Thanks for looking at this!
Therefore, rename ObjectPropertyFlags to ObjectPropertyAccessorFlags, and then the original name ObjectPropertyFlags can be used for other cases.
I wonder if we can just make existing ObjectPropertyFlags per object as you are planing and still continue using it for accessor flags.
That basically will lets you use new flags everywhere without rewriting call sites everywhere.
I'm not sure about this. Currently, these read/write flags are actually specific to pointer properties (as showed by the changes in this patch, which all involve object_property_add_*_ptr() / object_class_property_add_*_ptr()). Other property types doesn't yet support flag parameters, so additional interface modifications are still needed. And for now other property types either need to explicitly specify get/set accessors (e.g., object_property_add_bool()) or directly use the default get/set methods (e.g., object_property_add_link()). If we extend read/write flags to other property types, such as adding "flags" argument to object_property_add_bool(), we must ensure the OBJ_PROP_FLAG_READ flag align with "get" argument and OBJ_PROP_FLAG_WRITE flag align with "set" parameters. This would introduces additional complexity. Thanks, Zhao
On Mon, 5 Jan 2026 15:54:32 +0800 Zhao Liu <zhao1.liu@intel.com> wrote:
Thanks for looking at this!
Therefore, rename ObjectPropertyFlags to ObjectPropertyAccessorFlags, and then the original name ObjectPropertyFlags can be used for other cases.
I wonder if we can just make existing ObjectPropertyFlags per object as you are planing and still continue using it for accessor flags.
That basically will lets you use new flags everywhere without rewriting call sites everywhere.
I'm not sure about this. Currently, these read/write flags are actually specific to pointer properties (as showed by the changes in this patch, which all involve object_property_add_*_ptr() / object_class_property_add_*_ptr()).
Other property types doesn't yet support flag parameters, so additional interface modifications are still needed.
And for now other property types either need to explicitly specify get/set accessors (e.g., object_property_add_bool()) or directly use the default get/set methods (e.g., object_property_add_link()).
If we extend read/write flags to other property types, such as adding "flags" argument to object_property_add_bool(), we must ensure the OBJ_PROP_FLAG_READ flag align with "get" argument and OBJ_PROP_FLAG_WRITE flag align with "set" parameters.
Ain't thouse accessors callbacks? /I mean to you still can check flags inside of generic object property code without touching setter/getter./
This would introduces additional complexity.
it still might be woth considering to compare this series with alternative approach.
Thanks, Zhao
I'm not sure about this. Currently, these read/write flags are actually specific to pointer properties (as showed by the changes in this patch, which all involve object_property_add_*_ptr() / object_class_property_add_*_ptr()).
Other property types doesn't yet support flag parameters, so additional interface modifications are still needed.
And for now other property types either need to explicitly specify get/set accessors (e.g., object_property_add_bool()) or directly use the default get/set methods (e.g., object_property_add_link()).
If we extend read/write flags to other property types, such as adding "flags" argument to object_property_add_bool(), we must ensure the OBJ_PROP_FLAG_READ flag align with "get" argument and OBJ_PROP_FLAG_WRITE flag align with "set" parameters.
Ain't thouse accessors callbacks? /I mean to you still can check flags inside of generic object property code without touching setter/getter./
Ah, I see, the default flags is OBJ_PROP_FLAG_READWRITE and I can check them before calling setter/getter.
This would introduces additional complexity.
it still might be woth considering to compare this series with alternative approach.
Yes, will try to reuse current ObjectPropertyFlags. Thanks, Zhao
Now the common (but a bit fragmented) way to mark a property deprecated is to add the warning in its accssors. But this is pretty inconvenient for such qdev properties, which are defined via DEFINE_PROP_* macros in the Property array. For qdev properties, their accessors are provided by pre-defined PropertyInfo, so that it's possible to modify PropertyInfo for a single "deprecated" property. Then it's necessary to introduce property flags to mark some properties as deprecated, and to check the property flags when set the property, thereby to print a deprecation warning. This not only benefits traditional qdev properties but also helps the deprecation of generic objects. Note, internal attempt (except the compat case) should not trigger the deprecation warning but external user should see the deprecation information. Whether to perform deprecation checks based on property flags is controlled by the newly added "check" argument in object_property_try_add_full(). In subsequent work, the "check" option will be enabled for specific external property setting paths. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 72 ++++++++++++++++++++++++++++++++++++++++++++ qom/object.c | 72 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 130 insertions(+), 14 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 3f807a03f5aa..8f4c2f44d835 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -86,6 +86,12 @@ typedef void (ObjectPropertyRelease)(Object *obj, */ typedef void (ObjectPropertyInit)(Object *obj, ObjectProperty *prop); +typedef enum ObjectPropertyFlags { + OBJECT_PROPERTY_NO_FLAGS = 0, + OBJECT_PROPERTY_DEPRECATED = 1 << 0, + OBJECT_PROPERTY_FULL_FLAGS = OBJECT_PROPERTY_DEPRECATED, +} ObjectPropertyFlags; + struct ObjectProperty { char *name; @@ -98,6 +104,7 @@ struct ObjectProperty ObjectPropertyInit *init; void *opaque; QObject *defval; + uint8_t flags; }; /** @@ -1090,6 +1097,41 @@ ObjectProperty *object_property_try_add(Object *obj, const char *name, ObjectPropertyRelease *release, void *opaque, Error **errp); +/** + * object_property_try_add_full: + * + * Same as object_property_try_add() with more arguments (@flags). + * + * @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 + * 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. + * @flags: the flags to control property uses. + * @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_property_try_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 @errp hardcoded to @@ -1128,6 +1170,15 @@ ObjectProperty *object_class_property_add(ObjectClass *klass, const char *name, ObjectPropertyRelease *release, void *opaque); +ObjectProperty *object_class_property_add_full(ObjectClass *klass, + const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + ObjectPropertyFlags flags, + void *opaque); + /** * object_property_set_default_bool: * @prop: the property to set @@ -1469,6 +1520,27 @@ int object_property_get_enum(Object *obj, const char *name, bool object_property_set(Object *obj, const char *name, Visitor *v, Error **errp); +/** + * object_property_set_full: + * + * Same as object_property_set() with extra check over property flags + * (ObjectPropertyFlags) if @check is true. + * + * @obj: the object + * @name: the name of the property + * @v: the visitor that will be used to write the property value. This should + * be an Input visitor and the data will be first read with @name as the + * name and then written as the property value. + * @check: whether to check if the property can be set over property flags. + * @errp: returns an error if this function fails + * + * Writes a property to a object. + * + * Returns: %true on success, %false on failure. + */ +bool object_property_set_full(Object *obj, const char *name, + Visitor *v, bool check, Error **errp); + /** * object_property_parse: * @obj: the object diff --git a/qom/object.c b/qom/object.c index 85d31bb64b36..184afc6730dd 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1234,15 +1234,17 @@ void object_unref(void *objptr) } ObjectProperty * -object_property_try_add(Object *obj, const char *name, const char *type, - ObjectPropertyAccessor *get, - ObjectPropertyAccessor *set, - ObjectPropertyRelease *release, - void *opaque, Error **errp) +object_property_try_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); + assert(!flags || !(flags & ~(OBJECT_PROPERTY_FULL_FLAGS))); + if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) { int i; ObjectProperty *ret = NULL; @@ -1279,11 +1281,24 @@ object_property_try_add(Object *obj, const char *name, const char *type, prop->set = set; prop->release = release; prop->opaque = opaque; + prop->flags = flags; g_hash_table_insert(obj->properties, prop->name, prop); return prop; } +ObjectProperty * +object_property_try_add(Object *obj, const char *name, const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp) +{ + return object_property_try_add_full(obj, name, type, get, set, release, + OBJECT_PROPERTY_NO_FLAGS, opaque, + errp); +} + ObjectProperty * object_property_add(Object *obj, const char *name, const char *type, ObjectPropertyAccessor *get, @@ -1296,17 +1311,19 @@ 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_add_full(ObjectClass *klass, + const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + ObjectPropertyFlags flags, + void *opaque) { ObjectProperty *prop; assert(!object_class_property_find(klass, name)); + assert(!flags || !(flags & ~(OBJECT_PROPERTY_FULL_FLAGS))); prop = g_malloc0(sizeof(*prop)); @@ -1317,12 +1334,27 @@ object_class_property_add(ObjectClass *klass, prop->set = set; prop->release = release; prop->opaque = opaque; + prop->flags = flags; g_hash_table_insert(klass->properties, prop->name, prop); 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_add_full(klass, name, type, get, set, + release, OBJECT_PROPERTY_NO_FLAGS, + opaque); +} + ObjectProperty *object_property_find(Object *obj, const char *name) { ObjectProperty *prop; @@ -1432,8 +1464,8 @@ bool object_property_get(Object *obj, const char *name, Visitor *v, return !err; } -bool object_property_set(Object *obj, const char *name, Visitor *v, - Error **errp) +bool object_property_set_full(Object *obj, const char *name, + Visitor *v, bool check, Error **errp) { ERRP_GUARD(); ObjectProperty *prop = object_property_find_err(obj, name, errp); @@ -1447,10 +1479,22 @@ bool object_property_set(Object *obj, const char *name, Visitor *v, object_get_typename(obj), name); return false; } + + if (check && prop->flags & OBJECT_PROPERTY_DEPRECATED) { + warn_report("Property '%s.%s' has been deprecated. " + "Please do not use it.", object_get_typename(obj), name); + } + prop->set(obj, v, name, prop->opaque, errp); return !*errp; } +bool object_property_set(Object *obj, const char *name, Visitor *v, + Error **errp) +{ + return object_property_set_full(obj, name, v, false, errp); +} + bool object_property_set_str(Object *obj, const char *name, const char *value, Error **errp) { -- 2.34.1
On Wed, 3 Dec 2025 01:04:54 +0800 Zhao Liu <zhao1.liu@intel.com> wrote:
Now the common (but a bit fragmented) way to mark a property deprecated is to add the warning in its accssors.
But this is pretty inconvenient for such qdev properties, which are defined via DEFINE_PROP_* macros in the Property array. For qdev properties, their accessors are provided by pre-defined PropertyInfo, so that it's possible to modify PropertyInfo for a single "deprecated" property.
Then it's necessary to introduce property flags to mark some properties as deprecated, and to check the property flags when set the property, thereby to print a deprecation warning.
This not only benefits traditional qdev properties but also helps the deprecation of generic objects.
Note, internal attempt (except the compat case) should not trigger the deprecation warning but external user should see the deprecation information. Whether to perform deprecation checks based on property flags is controlled by the newly added "check" argument in object_property_try_add_full().
I'd split deprecation warning out for this patch, i.e. make this one "add per object instance flags", and take care of deprecation stuff on top, Also, API likely would need set/get/clear calls to operate on object flags.
In subsequent work, the "check" option will be enabled for specific external property setting paths.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 72 ++++++++++++++++++++++++++++++++++++++++++++ qom/object.c | 72 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 130 insertions(+), 14 deletions(-)
diff --git a/include/qom/object.h b/include/qom/object.h index 3f807a03f5aa..8f4c2f44d835 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -86,6 +86,12 @@ typedef void (ObjectPropertyRelease)(Object *obj, */ typedef void (ObjectPropertyInit)(Object *obj, ObjectProperty *prop);
+typedef enum ObjectPropertyFlags { + OBJECT_PROPERTY_NO_FLAGS = 0, + OBJECT_PROPERTY_DEPRECATED = 1 << 0,
maybe use BIT() instead of manual shift? addidtionally given you are going to distinguish external vs internal, perhaps add flags 'default' and 'user set', I think the both could be used to cleanup cpu flags handling where we rely on setting/checking magic numbers to figure out where value comes from.
+ OBJECT_PROPERTY_FULL_FLAGS = OBJECT_PROPERTY_DEPRECATED, +} ObjectPropertyFlags; + struct ObjectProperty { char *name; @@ -98,6 +104,7 @@ struct ObjectProperty ObjectPropertyInit *init; void *opaque; QObject *defval; + uint8_t flags; };
/** @@ -1090,6 +1097,41 @@ ObjectProperty *object_property_try_add(Object *obj, const char *name, ObjectPropertyRelease *release, void *opaque, Error **errp);
+/** + * object_property_try_add_full:
what's the reason for adding _full flavour over just modifying existing API?
+ * + * Same as object_property_try_add() with more arguments (@flags). + * + * @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 + * 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. + * @flags: the flags to control property uses. + * @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_property_try_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 @errp hardcoded to @@ -1128,6 +1170,15 @@ ObjectProperty *object_class_property_add(ObjectClass *klass, const char *name, ObjectPropertyRelease *release, void *opaque);
+ObjectProperty *object_class_property_add_full(ObjectClass *klass, + const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + ObjectPropertyFlags flags, + void *opaque); + /** * object_property_set_default_bool: * @prop: the property to set @@ -1469,6 +1520,27 @@ int object_property_get_enum(Object *obj, const char *name, bool object_property_set(Object *obj, const char *name, Visitor *v, Error **errp);
+/** + * object_property_set_full: + * + * Same as object_property_set() with extra check over property flags + * (ObjectPropertyFlags) if @check is true. + * + * @obj: the object + * @name: the name of the property + * @v: the visitor that will be used to write the property value. This should + * be an Input visitor and the data will be first read with @name as the + * name and then written as the property value. + * @check: whether to check if the property can be set over property flags. + * @errp: returns an error if this function fails + * + * Writes a property to a object. + * + * Returns: %true on success, %false on failure. + */ +bool object_property_set_full(Object *obj, const char *name, + Visitor *v, bool check, Error **errp); + /** * object_property_parse: * @obj: the object diff --git a/qom/object.c b/qom/object.c index 85d31bb64b36..184afc6730dd 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1234,15 +1234,17 @@ void object_unref(void *objptr) }
ObjectProperty * -object_property_try_add(Object *obj, const char *name, const char *type, - ObjectPropertyAccessor *get, - ObjectPropertyAccessor *set, - ObjectPropertyRelease *release, - void *opaque, Error **errp) +object_property_try_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);
+ assert(!flags || !(flags & ~(OBJECT_PROPERTY_FULL_FLAGS))); + if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) { int i; ObjectProperty *ret = NULL; @@ -1279,11 +1281,24 @@ object_property_try_add(Object *obj, const char *name, const char *type, prop->set = set; prop->release = release; prop->opaque = opaque; + prop->flags = flags;
g_hash_table_insert(obj->properties, prop->name, prop); return prop; }
+ObjectProperty * +object_property_try_add(Object *obj, const char *name, const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp) +{ + return object_property_try_add_full(obj, name, type, get, set, release, + OBJECT_PROPERTY_NO_FLAGS, opaque, + errp); +} + ObjectProperty * object_property_add(Object *obj, const char *name, const char *type, ObjectPropertyAccessor *get, @@ -1296,17 +1311,19 @@ 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_add_full(ObjectClass *klass, + const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + ObjectPropertyFlags flags, + void *opaque) { ObjectProperty *prop;
assert(!object_class_property_find(klass, name)); + assert(!flags || !(flags & ~(OBJECT_PROPERTY_FULL_FLAGS)));
prop = g_malloc0(sizeof(*prop));
@@ -1317,12 +1334,27 @@ object_class_property_add(ObjectClass *klass, prop->set = set; prop->release = release; prop->opaque = opaque; + prop->flags = flags;
g_hash_table_insert(klass->properties, prop->name, prop);
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_add_full(klass, name, type, get, set, + release, OBJECT_PROPERTY_NO_FLAGS, + opaque); +} + ObjectProperty *object_property_find(Object *obj, const char *name) { ObjectProperty *prop; @@ -1432,8 +1464,8 @@ bool object_property_get(Object *obj, const char *name, Visitor *v, return !err; }
-bool object_property_set(Object *obj, const char *name, Visitor *v, - Error **errp) +bool object_property_set_full(Object *obj, const char *name, + Visitor *v, bool check, Error **errp) { ERRP_GUARD(); ObjectProperty *prop = object_property_find_err(obj, name, errp); @@ -1447,10 +1479,22 @@ bool object_property_set(Object *obj, const char *name, Visitor *v, object_get_typename(obj), name); return false; } + + if (check && prop->flags & OBJECT_PROPERTY_DEPRECATED) { + warn_report("Property '%s.%s' has been deprecated. " + "Please do not use it.", object_get_typename(obj), name); + } + prop->set(obj, v, name, prop->opaque, errp); return !*errp; }
+bool object_property_set(Object *obj, const char *name, Visitor *v, + Error **errp) +{ + return object_property_set_full(obj, name, v, false, errp); +} + bool object_property_set_str(Object *obj, const char *name, const char *value, Error **errp) {
On Fri, Jan 02, 2026 at 01:06:01PM +0100, Igor Mammedov wrote:
Date: Fri, 2 Jan 2026 13:06:01 +0100 From: Igor Mammedov <imammedo@redhat.com> Subject: Re: [RFC 02/10] qom: Add basic object property deprecation hint support X-Mailer: Claws Mail 3.11.1-67-g0d58c6-dirty (GTK+ 2.24.21; x86_64-apple-darwin14.0.0)
On Wed, 3 Dec 2025 01:04:54 +0800 Zhao Liu <zhao1.liu@intel.com> wrote:
Now the common (but a bit fragmented) way to mark a property deprecated is to add the warning in its accssors.
But this is pretty inconvenient for such qdev properties, which are defined via DEFINE_PROP_* macros in the Property array. For qdev properties, their accessors are provided by pre-defined PropertyInfo, so that it's possible to modify PropertyInfo for a single "deprecated" property.
Then it's necessary to introduce property flags to mark some properties as deprecated, and to check the property flags when set the property, thereby to print a deprecation warning.
This not only benefits traditional qdev properties but also helps the deprecation of generic objects.
Note, internal attempt (except the compat case) should not trigger the deprecation warning but external user should see the deprecation information. Whether to perform deprecation checks based on property flags is controlled by the newly added "check" argument in object_property_try_add_full().
I'd split deprecation warning out for this patch, i.e. make this one "add per object instance flags", and take care of deprecation stuff on top,
Yeah, will do.
Also, API likely would need set/get/clear calls to operate on object flags.
I see, for dynamic flags ("user set" - you mentioned), these APIs are necessary. Will add something like object_property_[set|get|clear]_flags.
In subsequent work, the "check" option will be enabled for specific external property setting paths.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 72 ++++++++++++++++++++++++++++++++++++++++++++ qom/object.c | 72 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 130 insertions(+), 14 deletions(-)
diff --git a/include/qom/object.h b/include/qom/object.h index 3f807a03f5aa..8f4c2f44d835 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -86,6 +86,12 @@ typedef void (ObjectPropertyRelease)(Object *obj, */ typedef void (ObjectPropertyInit)(Object *obj, ObjectProperty *prop);
+typedef enum ObjectPropertyFlags { + OBJECT_PROPERTY_NO_FLAGS = 0, + OBJECT_PROPERTY_DEPRECATED = 1 << 0,
maybe use BIT() instead of manual shift?
Sure, will do.
addidtionally given you are going to distinguish external vs internal, perhaps add flags 'default' and 'user set', I think the both could be used to cleanup cpu flags handling where we rely on setting/checking magic numbers to figure out where value comes from.
Good idea. I think a "user set" flag is enough. Considerring a property may be set multiple timers. In object_property_set_full(), we could add the "user set" flag for external setting and clear that flag for internal setting, then property's set accessor could know whether the value is from user or not.
+ OBJECT_PROPERTY_FULL_FLAGS = OBJECT_PROPERTY_DEPRECATED, +} ObjectPropertyFlags; + struct ObjectProperty { char *name; @@ -98,6 +104,7 @@ struct ObjectProperty ObjectPropertyInit *init; void *opaque; QObject *defval; + uint8_t flags; };
/** @@ -1090,6 +1097,41 @@ ObjectProperty *object_property_try_add(Object *obj, const char *name, ObjectPropertyRelease *release, void *opaque, Error **errp);
+/** + * object_property_try_add_full:
what's the reason for adding _full flavour over just modifying existing API?
I was previously concerned about making too many changes to other parts, but after re-checking, directly extending the current object_property_try_add() is better — there's not too many changes. Thanks for the reminder. Regards, Zhao
Global properties can be set up in these cases: 1) external global properties: * -global command line option. * -cpu command line features. * suger properties from object_compat_props[2] 2) internal global properties: * compat properties from object_compat_props[0,1]. In principle, when a compat property is marked as deprecated, it should not be added to any object_compat_props[] as a compat "fix". Therefore, internal compat "global" property use cases should also be considered. All of these global cases are using object_property_parse() to parse and set propertyies, ao add a object_property_parse_with_check() to enable deprecation checks for global properties. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- include/qom/object.h | 20 ++++++++++++++++++++ qom/object.c | 13 ++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/include/qom/object.h b/include/qom/object.h index 8f4c2f44d835..bdeba113f40f 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1555,6 +1555,26 @@ bool object_property_set_full(Object *obj, const char *name, bool object_property_parse(Object *obj, const char *name, const char *string, Error **errp); +/** + * object_property_parse_with_check: + * + * Same as object_property_parse() with extra check over property flags + * (ObjectPropertyFlags). This interface should be used to handle + * property settings for external users or internal legacy or compatibility + * cases. + * + * @obj: the object + * @name: the name of the property + * @string: the string that will be used to parse the property value. + * @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_with_check(Object *obj, const char *name, + const char *string, Error **errp); + /** * object_property_print: * @obj: the object diff --git a/qom/object.c b/qom/object.c index 184afc6730dd..2973d8876555 100644 --- a/qom/object.c +++ b/qom/object.c @@ -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, &err)) { + if (!object_property_parse_with_check(obj, p->property, + p->value, &err)) { error_prepend(&err, "can't apply global %s.%s=%s: ", p->driver, p->property, p->value); /* @@ -1745,6 +1746,16 @@ bool object_property_parse(Object *obj, const char *name, return ok; } +bool object_property_parse_with_check(Object *obj, const char *name, + const char *string, Error **errp) +{ + Visitor *v = string_input_visitor_new(string); + bool ok = object_property_set_full(obj, name, v, true, errp); + + visit_free(v); + return ok; +} + char *object_property_print(Object *obj, const char *name, bool human, Error **errp) { -- 2.34.1
The sources of properities parsed into qdict include: 1) External ("TYPE_USER_CREATABLE") object: * -object command line used for external ("TYPE_USER_CREATABLE") object. 2) External device: * -device command line - parsed based on keyval or json. 3) External machine options: * -machine command line - parsed based on keyval. 4) Internal machine options: * Builtin default machine options string: MachineClass::default_machine_opts - parsed based on keyval, too. All of these cases are using object_set_properties_from_qdict() to set properties. It's necessary to detect and report deprecated properities for these cases. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- qom/object_interfaces.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 415cbee8c5cf..b58a24c27ce7 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -53,7 +53,7 @@ static void object_set_properties_from_qdict(Object *obj, const QDict *qdict, return; } for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) { - if (!object_property_set(obj, e->key, v, errp)) { + if (!object_property_set_full(obj, e->key, v, true, errp)) { goto out; } } -- 2.34.1
Now, object_parse_property_opt() is only used for -accel, which would also have the need to deprecate properties. So, use object_property_parse_with_check() for -accel. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- system/vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/vl.c b/system/vl.c index 5091fe52d925..e1bcd4d713d7 100644 --- a/system/vl.c +++ b/system/vl.c @@ -1709,7 +1709,7 @@ static int object_parse_property_opt(Object *obj, return 0; } - if (!object_property_parse(obj, name, value, errp)) { + if (!object_property_parse_with_check(obj, name, value, errp)) { return -1; } -- 2.34.1
"qom-set" can be used to set object property by external users, so it's necessary to enable deprecation check for this case. 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 a00a564b1e22..1bfef0837e30 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_with_check(obj, property, value, &err); } } else { QObject *obj = qobject_from_json(value, &err); -- 2.34.1
With deprecation flag, make qdev property interfaces to accept ObjectPropertyFlags, and provide the boolean and uint8_t macro variants to help on deprecation as examples. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- hw/core/qdev-properties.c | 24 +++++++++++++----------- include/hw/qdev-properties.h | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 422a486969c8..2cd7de5cec2d 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -1069,11 +1069,12 @@ 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_try_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); @@ -1095,12 +1096,13 @@ 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); } if (prop->set_default) { prop->info->set_default_value(op, prop); diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 60b81330097d..383f3f54f0ab 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/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 { @@ -102,6 +104,13 @@ extern const PropertyInfo qdev_prop_link; .set_default = true, \ .defval.u = (_type)_defval) +#define DEFINE_PROP_UNSIGNED_DEPRECATED(_name, _state, _field, \ + _defval, _prop, _type) \ + DEFINE_PROP(_name, _state, _field, _prop, _type, \ + .set_default = true, \ + .defval.u = (_type)_defval, \ + .flags = OBJECT_PROPERTY_DEPRECATED) + #define DEFINE_PROP_UNSIGNED_NODEFAULT(_name, _state, _field, _prop, _type) \ DEFINE_PROP(_name, _state, _field, _prop, _type) @@ -123,6 +132,12 @@ extern const PropertyInfo qdev_prop_link; .set_default = true, \ .defval.u = (bool)_defval) +#define DEFINE_PROP_BOOL_DEPRECATED(_name, _state, _field, _defval) \ + DEFINE_PROP(_name, _state, _field, qdev_prop_bool, bool, \ + .set_default = true, \ + .defval.u = (bool)_defval, \ + .flags = OBJECT_PROPERTY_DEPRECATED) + /** * The DEFINE_PROP_UINT64_CHECKMASK macro checks a user-supplied value * against corresponding bitmask, rejects the value if it violates. @@ -189,6 +204,9 @@ extern const PropertyInfo qdev_prop_link; #define DEFINE_PROP_SIZE32(_n, _s, _f, _d) \ DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_size32, uint32_t) +#define DEFINE_PROP_UINT8_DEPRECATED(_n, _s, _f, _d) \ + DEFINE_PROP_UNSIGNED_DEPRECATED(_n, _s, _f, _d, qdev_prop_uint8, uint8_t) + /* * Set properties between creation and realization. * -- 2.34.1
On Wed, 3 Dec 2025 01:04:59 +0800 Zhao Liu <zhao1.liu@intel.com> wrote:
With deprecation flag, make qdev property interfaces to accept ObjectPropertyFlags, and provide the boolean and uint8_t macro variants to help on deprecation as examples.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- hw/core/qdev-properties.c | 24 +++++++++++++----------- include/hw/qdev-properties.h | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 422a486969c8..2cd7de5cec2d 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -1069,11 +1069,12 @@ 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_try_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); @@ -1095,12 +1096,13 @@ 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); } if (prop->set_default) { prop->info->set_default_value(op, prop); diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 60b81330097d..383f3f54f0ab 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/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 { @@ -102,6 +104,13 @@ extern const PropertyInfo qdev_prop_link; .set_default = true, \ .defval.u = (_type)_defval)
+#define DEFINE_PROP_UNSIGNED_DEPRECATED(_name, _state, _field, \ + _defval, _prop, _type) \ + DEFINE_PROP(_name, _state, _field, _prop, _type, \ + .set_default = true, \ + .defval.u = (_type)_defval, \ + .flags = OBJECT_PROPERTY_DEPRECATED) + #define DEFINE_PROP_UNSIGNED_NODEFAULT(_name, _state, _field, _prop, _type) \
adding flags to the end of the names, basicaly spawns a lot of vartions of the same macro, perhaps it's time to just add flags field and consoladate existing 'flag named' variants, the one won't need to introduce DEFINE_PROP_UNSIGNED_DEPRECATED at all, just use appropriate flag(s) when decaring property.
DEFINE_PROP(_name, _state, _field, _prop, _type)
@@ -123,6 +132,12 @@ extern const PropertyInfo qdev_prop_link; .set_default = true, \ .defval.u = (bool)_defval)
+#define DEFINE_PROP_BOOL_DEPRECATED(_name, _state, _field, _defval) \ + DEFINE_PROP(_name, _state, _field, qdev_prop_bool, bool, \ + .set_default = true, \ + .defval.u = (bool)_defval, \ + .flags = OBJECT_PROPERTY_DEPRECATED) + /** * The DEFINE_PROP_UINT64_CHECKMASK macro checks a user-supplied value * against corresponding bitmask, rejects the value if it violates. @@ -189,6 +204,9 @@ extern const PropertyInfo qdev_prop_link; #define DEFINE_PROP_SIZE32(_n, _s, _f, _d) \ DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_size32, uint32_t)
+#define DEFINE_PROP_UINT8_DEPRECATED(_n, _s, _f, _d) \ + DEFINE_PROP_UNSIGNED_DEPRECATED(_n, _s, _f, _d, qdev_prop_uint8, uint8_t) + /* * Set properties between creation and realization. *
+#define DEFINE_PROP_UNSIGNED_DEPRECATED(_name, _state, _field, \ + _defval, _prop, _type) \ + DEFINE_PROP(_name, _state, _field, _prop, _type, \ + .set_default = true, \ + .defval.u = (_type)_defval, \ + .flags = OBJECT_PROPERTY_DEPRECATED) + #define DEFINE_PROP_UNSIGNED_NODEFAULT(_name, _state, _field, _prop, _type) \
adding flags to the end of the names, basicaly spawns a lot of vartions of the same macro,
perhaps it's time to just add flags field and consoladate existing 'flag named' variants, the one won't need to introduce DEFINE_PROP_UNSIGNED_DEPRECATED at all, just use appropriate flag(s) when decaring property.
Good idea, what about this? -#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_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__) Then we can mark a property as deprecated by: DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF, .flags = OBJECT_PROPERTY_DEPRECATED), Regards, Zhao
"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 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 | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 9386cffba26d..c60924b4f313 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -487,6 +487,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 72c69ba81c1b..1f0a8cb6cec1 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -9997,7 +9997,7 @@ 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_DEPRECATED("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true), 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 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 | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index c60924b4f313..741c1a71728b 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -495,6 +495,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 1f0a8cb6cec1..ef1ffc4d3d4f 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -10009,7 +10009,7 @@ static const Property x86_cpu_properties[] = { DEFINE_PROP_UINT8("avx10-version", X86CPU, env.avx10_version, 0), DEFINE_PROP_UINT64("ucode-rev", X86CPU, ucode_rev, 0), DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor), - DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true), + DEFINE_PROP_BOOL_DEPRECATED("cpuid-0xb", X86CPU, enable_cpuid_0xb, true), 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 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 741c1a71728b..076940ad0826 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -522,6 +522,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 +-------------- + +``-device -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 38e438464861..45fdfb56636b 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_DEPRECATED("version", IOAPICCommonState, + version, IOAPIC_VER_DEF), }; static void ioapic_class_init(ObjectClass *klass, const void *data) -- 2.34.1
participants (2)
-
Igor Mammedov -
Zhao Liu