diff mbox series

[v1,8/9] qom: add command to print initial properties

Message ID 20220328211539.90170-9-maxim.davydov@openvz.org
State New
Headers show
Series [v1,1/9] qmp: Add dump machine type compatible properties | expand

Commit Message

Maxim Davydov March 28, 2022, 9:15 p.m. UTC
The command "query-init-properties" is needed to get values of properties
after initialization (not only default value). It makes sense, for example,
when working with x86_64-cpu.
All machine types (and x-remote-object, because its init uses machime
type's infrastructure) should be skipped, because only the one instance can
be correctly initialized.

Signed-off-by: Maxim Davydov <maxim.davydov@openvz.org>
---
 qapi/qom.json      |  69 ++++++++++++++++++++++++++
 qom/qom-qmp-cmds.c | 121 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 190 insertions(+)

Comments

Vladimir Sementsov-Ogievskiy March 30, 2022, 3:17 p.m. UTC | #1
29.03.2022 00:15, Maxim Davydov wrote:
> The command "query-init-properties" is needed to get values of properties
> after initialization (not only default value). It makes sense, for example,
> when working with x86_64-cpu.
> All machine types (and x-remote-object, because its init uses machime
> type's infrastructure) should be skipped, because only the one instance can
> be correctly initialized.
> 
> Signed-off-by: Maxim Davydov <maxim.davydov@openvz.org>
> ---
>   qapi/qom.json      |  69 ++++++++++++++++++++++++++
>   qom/qom-qmp-cmds.c | 121 +++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 190 insertions(+)
> 
> diff --git a/qapi/qom.json b/qapi/qom.json
> index eeb5395ff3..1eedc441eb 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -949,3 +949,72 @@
>   ##
>   { 'command': 'object-del', 'data': {'id': 'str'},
>     'allow-preconfig': true }
> +
> +##
> +# @InitValue:
> +#
> +# Not all objects have default values but they have "initial" values.
> +#
> +# @name: property name
> +#
> +# @value: Current value (default or after initialization. It makes sence,
> +#         for example, for x86-cpus)
> +#
> +# Since: 7.0

7.1 (here and below)

> +#
> +##
> +{ 'struct': 'InitValue',
> +  'data': { 'name': 'str',
> +            '*value': 'any' } }
> +

[..]

> diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
> index 2d6f41ecc7..c1bb3f1f8b 100644
> --- a/qom/qom-qmp-cmds.c
> +++ b/qom/qom-qmp-cmds.c
> @@ -27,6 +27,7 @@
>   #include "qemu/cutils.h"
>   #include "qom/object_interfaces.h"
>   #include "qom/qom-qobject.h"
> +#include "hw/boards.h"
>   
>   ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
>   {
> @@ -235,3 +236,123 @@ void qmp_object_del(const char *id, Error **errp)
>   {
>       user_creatable_del(id, errp);
>   }
> +
> +static void query_object_prop(InitValueList **props_list, ObjectProperty *prop,
> +                              Object *obj, Error **errp)
> +{
> +    InitValue *prop_info = NULL;
> +
> +    /* Skip inconsiderable properties */
> +    if (strcmp(prop->name, "type") == 0 ||
> +        strcmp(prop->name, "realized") == 0 ||
> +        strcmp(prop->name, "hotpluggable") == 0 ||
> +        strcmp(prop->name, "hotplugged") == 0 ||
> +        strcmp(prop->name, "parent_bus") == 0) {
> +        return;
> +    }
> +
> +    prop_info = g_malloc0(sizeof(*prop_info));
> +    prop_info->name = g_strdup(prop->name);
> +    prop_info->value = NULL;
> +    if (prop->defval) {
> +        prop_info->value = qobject_ref(prop->defval);
> +    } else if (prop->get) {
> +        /*
> +         * crash-information in x86-cpu uses errp to return current state.
> +         * So, after requesting this property it returns  GenericError:
> +         * "No crash occured"
> +         */
> +        if (strcmp(prop->name, "crash-information") != 0) {
> +            prop_info->value = object_property_get_qobject(obj, prop->name,
> +                                                           errp);
> +        }
> +    }

Hmmm. Should we instead call prop->get() when is is available, and only if not use prep->defval?

> +    prop_info->has_value = !!prop_info->value;
> +
> +    QAPI_LIST_PREPEND(*props_list, prop_info);
> +}
> +
> +typedef struct QIPData {
> +    InitPropsList **dev_list;
> +    Error **errp;
> +} QIPData;
> +
> +static void query_init_properties_tramp(gpointer list_data, gpointer opaque)
> +{
> +    ObjectClass *k = list_data;
> +    Object *obj;
> +    ObjectClass *parent;
> +    GHashTableIter iter;
> +
> +    QIPData *data = opaque;
> +    ClassPropertiesList *class_props_list = NULL;
> +    InitProps *dev_info;
> +
> +    /* Only one machine can be initialized correctly (it's already happened) */
> +    if (object_class_dynamic_cast(k, TYPE_MACHINE)) {
> +        return;
> +    }
> +
> +    const char *klass_name = object_class_get_name(k);
> +    /*
> +     * Uses machine type infrastructure with notifiers. It causes immediate
> +     * notify and SEGSEGV during remote_object_machine_done
> +     */
> +    if (strcmp(klass_name, "x-remote-object") == 0) {
> +        return;
> +    }
> +
> +    dev_info = g_malloc0(sizeof(*dev_info));
> +    dev_info->name = g_strdup(klass_name);
> +
> +    obj = object_new_with_class(k);
> +
> +    /*
> +     * Part of ObjectPropertyIterator infrastructure, but we need more precise
> +     * control of current class to dump appropriate features
> +     * This part was taken out from loop because first initialization differ
> +     * from other reinitializations
> +     */
> +    parent = object_get_class(obj);

hmm.. obj = object_new_with_class(k); parent = object_get_class(obj);.. Looks for me like parent should be equal to k. Or object_ API is rather unobvious.

> +    g_hash_table_iter_init(&iter, obj->properties);
> +    const char *prop_owner_name = object_get_typename(obj);
> +    do {
> +        InitValueList *prop_list = NULL;
> +        ClassProperties *class_data;
> +
> +        gpointer key, val;
> +        while (g_hash_table_iter_next(&iter, &key, &val)) {
> +            query_object_prop(&prop_list, (ObjectProperty *)val, obj,
> +                              data->errp);
> +        }
> +        class_data = g_malloc0(sizeof(*class_data));
> +        class_data->classname = g_strdup(prop_owner_name);
> +        class_data->classprops = prop_list;
> +        class_data->has_classprops = !!prop_list;
> +
> +        QAPI_LIST_PREPEND(class_props_list, class_data);
> +
> +        if (!parent) {
> +            break;
> +        }
> +        g_hash_table_iter_init(&iter, parent->properties);
> +        prop_owner_name = object_class_get_name(parent);
> +        parent = object_class_get_parent(parent);
> +    } while (true);
> +    dev_info->props = class_props_list;
> +    object_unref(OBJECT(obj));
> +
> +    QAPI_LIST_PREPEND(*(data->dev_list), dev_info);
> +}
> +
> +InitPropsList *qmp_query_init_properties(Error **errp)
> +{
> +    GSList *typename_list = object_class_get_list(TYPE_OBJECT, false);
> +
> +    InitPropsList *dev_list = NULL;
> +    QIPData data = { &dev_list, errp };
> +    g_slist_foreach(typename_list, query_init_properties_tramp, &data);
> +    g_slist_free(typename_list);
> +
> +    return dev_list;
> +}
Igor Mammedov March 31, 2022, 11:55 a.m. UTC | #2
On Tue, 29 Mar 2022 00:15:38 +0300
Maxim Davydov <maxim.davydov@openvz.org> wrote:

> The command "query-init-properties" is needed to get values of properties
> after initialization (not only default value). It makes sense, for example,
> when working with x86_64-cpu.
> All machine types (and x-remote-object, because its init uses machime
> type's infrastructure) should be skipped, because only the one instance can
> be correctly initialized.

It might be obvious to you but I couldn't parse above commit message at all.
Pls rephrase and explain in more detail what you are trying to achieve.

> 
> Signed-off-by: Maxim Davydov <maxim.davydov@openvz.org>
> ---
>  qapi/qom.json      |  69 ++++++++++++++++++++++++++
>  qom/qom-qmp-cmds.c | 121 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 190 insertions(+)
> 
> diff --git a/qapi/qom.json b/qapi/qom.json
> index eeb5395ff3..1eedc441eb 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -949,3 +949,72 @@
>  ##
>  { 'command': 'object-del', 'data': {'id': 'str'},
>    'allow-preconfig': true }
> +
> +##
> +# @InitValue:
> +#
> +# Not all objects have default values but they have "initial" values.
> +#
> +# @name: property name
> +#
> +# @value: Current value (default or after initialization. It makes sence,
> +#         for example, for x86-cpus)
> +#
> +# Since: 7.0
> +#
> +##
> +{ 'struct': 'InitValue',
> +  'data': { 'name': 'str',
> +            '*value': 'any' } }
> +
> +##
> +# @ClassProperties:
> +#
> +# Initial values of properties that are owned by the class
> +#
> +# @classname: name of the class that owns appropriate properties
> +#
> +# @classprops: List of class properties
> +#
> +# Since: 7.0
> +#
> +##
> +{ 'struct': 'ClassProperties',
> +  'data': { 'classname': 'str',
> +            '*classprops': [ 'InitValue' ] } }
> +
> +##
> +# @InitProps:
> +#
> +# List of properties and their values that are available after class
> +# initialization. So it important to know default value of the property
> +# even if it doesn't have "QObject *defval"
> +#
> +# @name: Object name
> +#
> +# @props: List of properties
> +#
> +# Notes: a value in each property was defval if it's available
> +#        otherwise it's obtained via "(ObjectPropertyAccessor*) get"
> +#        immediately after initialization of device object.
> +#
> +# Since: 7.0
> +#
> +##
> +{ 'struct': 'InitProps',
> +  'data': { 'name': 'str',
> +            'props': [ 'ClassProperties' ] } }
> +
> +##
> +# @query-init-properties:
> +#
> +# Returns list of all objects (except all types related with machine type)
> +# with all properties and their "default" values that  will be available
> +# after initialization. The main purpose of this command is to be used to
> +# build table with all machine-type-specific properties
> +#
> +# Since: 7.0
> +#
> +##
> +{ 'command': 'query-init-properties',
> +  'returns': [ 'InitProps' ] }
> diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
> index 2d6f41ecc7..c1bb3f1f8b 100644
> --- a/qom/qom-qmp-cmds.c
> +++ b/qom/qom-qmp-cmds.c
> @@ -27,6 +27,7 @@
>  #include "qemu/cutils.h"
>  #include "qom/object_interfaces.h"
>  #include "qom/qom-qobject.h"
> +#include "hw/boards.h"
>  
>  ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
>  {
> @@ -235,3 +236,123 @@ void qmp_object_del(const char *id, Error **errp)
>  {
>      user_creatable_del(id, errp);
>  }
> +
> +static void query_object_prop(InitValueList **props_list, ObjectProperty *prop,
> +                              Object *obj, Error **errp)
> +{
> +    InitValue *prop_info = NULL;
> +
> +    /* Skip inconsiderable properties */
> +    if (strcmp(prop->name, "type") == 0 ||
> +        strcmp(prop->name, "realized") == 0 ||
> +        strcmp(prop->name, "hotpluggable") == 0 ||
> +        strcmp(prop->name, "hotplugged") == 0 ||
> +        strcmp(prop->name, "parent_bus") == 0) {
> +        return;
> +    }
> +
> +    prop_info = g_malloc0(sizeof(*prop_info));
> +    prop_info->name = g_strdup(prop->name);
> +    prop_info->value = NULL;
> +    if (prop->defval) {
> +        prop_info->value = qobject_ref(prop->defval);
> +    } else if (prop->get) {
> +        /*
> +         * crash-information in x86-cpu uses errp to return current state.
> +         * So, after requesting this property it returns  GenericError:
> +         * "No crash occured"
> +         */
> +        if (strcmp(prop->name, "crash-information") != 0) {
> +            prop_info->value = object_property_get_qobject(obj, prop->name,
> +                                                           errp);
> +        }
> +    }
> +    prop_info->has_value = !!prop_info->value;
> +
> +    QAPI_LIST_PREPEND(*props_list, prop_info);
> +}
> +
> +typedef struct QIPData {
> +    InitPropsList **dev_list;
> +    Error **errp;
> +} QIPData;
> +
> +static void query_init_properties_tramp(gpointer list_data, gpointer opaque)
> +{
> +    ObjectClass *k = list_data;
> +    Object *obj;
> +    ObjectClass *parent;
> +    GHashTableIter iter;
> +
> +    QIPData *data = opaque;
> +    ClassPropertiesList *class_props_list = NULL;
> +    InitProps *dev_info;
> +
> +    /* Only one machine can be initialized correctly (it's already happened) */
> +    if (object_class_dynamic_cast(k, TYPE_MACHINE)) {
> +        return;
> +    }
> +
> +    const char *klass_name = object_class_get_name(k);
> +    /*
> +     * Uses machine type infrastructure with notifiers. It causes immediate
> +     * notify and SEGSEGV during remote_object_machine_done
> +     */
> +    if (strcmp(klass_name, "x-remote-object") == 0) {
> +        return;
> +    }
> +
> +    dev_info = g_malloc0(sizeof(*dev_info));
> +    dev_info->name = g_strdup(klass_name);
> +
> +    obj = object_new_with_class(k);
> +
> +    /*
> +     * Part of ObjectPropertyIterator infrastructure, but we need more precise
> +     * control of current class to dump appropriate features
> +     * This part was taken out from loop because first initialization differ
> +     * from other reinitializations
> +     */
> +    parent = object_get_class(obj);
> +    g_hash_table_iter_init(&iter, obj->properties);
> +    const char *prop_owner_name = object_get_typename(obj);
> +    do {
> +        InitValueList *prop_list = NULL;
> +        ClassProperties *class_data;
> +
> +        gpointer key, val;
> +        while (g_hash_table_iter_next(&iter, &key, &val)) {
> +            query_object_prop(&prop_list, (ObjectProperty *)val, obj,
> +                              data->errp);
> +        }
> +        class_data = g_malloc0(sizeof(*class_data));
> +        class_data->classname = g_strdup(prop_owner_name);
> +        class_data->classprops = prop_list;
> +        class_data->has_classprops = !!prop_list;
> +
> +        QAPI_LIST_PREPEND(class_props_list, class_data);
> +
> +        if (!parent) {
> +            break;
> +        }
> +        g_hash_table_iter_init(&iter, parent->properties);
> +        prop_owner_name = object_class_get_name(parent);
> +        parent = object_class_get_parent(parent);
> +    } while (true);
> +    dev_info->props = class_props_list;
> +    object_unref(OBJECT(obj));
> +
> +    QAPI_LIST_PREPEND(*(data->dev_list), dev_info);
> +}
> +
> +InitPropsList *qmp_query_init_properties(Error **errp)
> +{
> +    GSList *typename_list = object_class_get_list(TYPE_OBJECT, false);
> +
> +    InitPropsList *dev_list = NULL;
> +    QIPData data = { &dev_list, errp };
> +    g_slist_foreach(typename_list, query_init_properties_tramp, &data);
> +    g_slist_free(typename_list);
> +
> +    return dev_list;
> +}
Maxim Davydov April 4, 2022, 3:33 p.m. UTC | #3
On 3/30/22 18:17, Vladimir Sementsov-Ogievskiy wrote:
> 29.03.2022 00:15, Maxim Davydov wrote:
>> The command "query-init-properties" is needed to get values of 
>> properties
>> after initialization (not only default value). It makes sense, for 
>> example,
>> when working with x86_64-cpu.
>> All machine types (and x-remote-object, because its init uses machime
>> type's infrastructure) should be skipped, because only the one 
>> instance can
>> be correctly initialized.
>>
>> Signed-off-by: Maxim Davydov <maxim.davydov@openvz.org>
>> ---
>>   qapi/qom.json      |  69 ++++++++++++++++++++++++++
>>   qom/qom-qmp-cmds.c | 121 +++++++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 190 insertions(+)
>>
>> diff --git a/qapi/qom.json b/qapi/qom.json
>> index eeb5395ff3..1eedc441eb 100644
>> --- a/qapi/qom.json
>> +++ b/qapi/qom.json
>> @@ -949,3 +949,72 @@
>>   ##
>>   { 'command': 'object-del', 'data': {'id': 'str'},
>>     'allow-preconfig': true }
>> +
>> +##
>> +# @InitValue:
>> +#
>> +# Not all objects have default values but they have "initial" values.
>> +#
>> +# @name: property name
>> +#
>> +# @value: Current value (default or after initialization. It makes 
>> sence,
>> +#         for example, for x86-cpus)
>> +#
>> +# Since: 7.0
>
> 7.1 (here and below)
>
>> +#
>> +##
>> +{ 'struct': 'InitValue',
>> +  'data': { 'name': 'str',
>> +            '*value': 'any' } }
>> +
>
> [..]
>
>> diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
>> index 2d6f41ecc7..c1bb3f1f8b 100644
>> --- a/qom/qom-qmp-cmds.c
>> +++ b/qom/qom-qmp-cmds.c
>> @@ -27,6 +27,7 @@
>>   #include "qemu/cutils.h"
>>   #include "qom/object_interfaces.h"
>>   #include "qom/qom-qobject.h"
>> +#include "hw/boards.h"
>>     ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
>>   {
>> @@ -235,3 +236,123 @@ void qmp_object_del(const char *id, Error **errp)
>>   {
>>       user_creatable_del(id, errp);
>>   }
>> +
>> +static void query_object_prop(InitValueList **props_list, 
>> ObjectProperty *prop,
>> +                              Object *obj, Error **errp)
>> +{
>> +    InitValue *prop_info = NULL;
>> +
>> +    /* Skip inconsiderable properties */
>> +    if (strcmp(prop->name, "type") == 0 ||
>> +        strcmp(prop->name, "realized") == 0 ||
>> +        strcmp(prop->name, "hotpluggable") == 0 ||
>> +        strcmp(prop->name, "hotplugged") == 0 ||
>> +        strcmp(prop->name, "parent_bus") == 0) {
>> +        return;
>> +    }
>> +
>> +    prop_info = g_malloc0(sizeof(*prop_info));
>> +    prop_info->name = g_strdup(prop->name);
>> +    prop_info->value = NULL;
>> +    if (prop->defval) {
>> +        prop_info->value = qobject_ref(prop->defval);
>> +    } else if (prop->get) {
>> +        /*
>> +         * crash-information in x86-cpu uses errp to return current 
>> state.
>> +         * So, after requesting this property it returns GenericError:
>> +         * "No crash occured"
>> +         */
>> +        if (strcmp(prop->name, "crash-information") != 0) {
>> +            prop_info->value = object_property_get_qobject(obj, 
>> prop->name,
>> + errp);
>> +        }
>> +    }
>
> Hmmm. Should we instead call prop->get() when is is available, and 
> only if not use prep->defval?
default properties more rare and sometimes can give more information (if 
the device developer thought that there should be a default value). And 
I think that if prop->get() isn't available, prop->defval() isn't too.
>
>> +    prop_info->has_value = !!prop_info->value;
>> +
>> +    QAPI_LIST_PREPEND(*props_list, prop_info);
>> +}
>> +
>> +typedef struct QIPData {
>> +    InitPropsList **dev_list;
>> +    Error **errp;
>> +} QIPData;
>> +
>> +static void query_init_properties_tramp(gpointer list_data, gpointer 
>> opaque)
>> +{
>> +    ObjectClass *k = list_data;
>> +    Object *obj;
>> +    ObjectClass *parent;
>> +    GHashTableIter iter;
>> +
>> +    QIPData *data = opaque;
>> +    ClassPropertiesList *class_props_list = NULL;
>> +    InitProps *dev_info;
>> +
>> +    /* Only one machine can be initialized correctly (it's already 
>> happened) */
>> +    if (object_class_dynamic_cast(k, TYPE_MACHINE)) {
>> +        return;
>> +    }
>> +
>> +    const char *klass_name = object_class_get_name(k);
>> +    /*
>> +     * Uses machine type infrastructure with notifiers. It causes 
>> immediate
>> +     * notify and SEGSEGV during remote_object_machine_done
>> +     */
>> +    if (strcmp(klass_name, "x-remote-object") == 0) {
>> +        return;
>> +    }
>> +
>> +    dev_info = g_malloc0(sizeof(*dev_info));
>> +    dev_info->name = g_strdup(klass_name);
>> +
>> +    obj = object_new_with_class(k);
>> +
>> +    /*
>> +     * Part of ObjectPropertyIterator infrastructure, but we need 
>> more precise
>> +     * control of current class to dump appropriate features
>> +     * This part was taken out from loop because first 
>> initialization differ
>> +     * from other reinitializations
>> +     */
>> +    parent = object_get_class(obj);
>
> hmm.. obj = object_new_with_class(k); parent = 
> object_get_class(obj);.. Looks for me like parent should be equal to 
> k. Or object_ API is rather unobvious.
I'll change it)
>
>> +    g_hash_table_iter_init(&iter, obj->properties);
>> +    const char *prop_owner_name = object_get_typename(obj);
>> +    do {
>> +        InitValueList *prop_list = NULL;
>> +        ClassProperties *class_data;
>> +
>> +        gpointer key, val;
>> +        while (g_hash_table_iter_next(&iter, &key, &val)) {
>> +            query_object_prop(&prop_list, (ObjectProperty *)val, obj,
>> +                              data->errp);
>> +        }
>> +        class_data = g_malloc0(sizeof(*class_data));
>> +        class_data->classname = g_strdup(prop_owner_name);
>> +        class_data->classprops = prop_list;
>> +        class_data->has_classprops = !!prop_list;
>> +
>> +        QAPI_LIST_PREPEND(class_props_list, class_data);
>> +
>> +        if (!parent) {
>> +            break;
>> +        }
>> +        g_hash_table_iter_init(&iter, parent->properties);
>> +        prop_owner_name = object_class_get_name(parent);
>> +        parent = object_class_get_parent(parent);
>> +    } while (true);
>> +    dev_info->props = class_props_list;
>> +    object_unref(OBJECT(obj));
>> +
>> +    QAPI_LIST_PREPEND(*(data->dev_list), dev_info);
>> +}
>> +
>> +InitPropsList *qmp_query_init_properties(Error **errp)
>> +{
>> +    GSList *typename_list = object_class_get_list(TYPE_OBJECT, false);
>> +
>> +    InitPropsList *dev_list = NULL;
>> +    QIPData data = { &dev_list, errp };
>> +    g_slist_foreach(typename_list, query_init_properties_tramp, &data);
>> +    g_slist_free(typename_list);
>> +
>> +    return dev_list;
>> +}
>
>
Maxim Davydov April 4, 2022, 4:08 p.m. UTC | #4
On 3/31/22 14:55, Igor Mammedov wrote:
> On Tue, 29 Mar 2022 00:15:38 +0300
> Maxim Davydov <maxim.davydov@openvz.org> wrote:
>
>> The command "query-init-properties" is needed to get values of properties
>> after initialization (not only default value). It makes sense, for example,
>> when working with x86_64-cpu.
>> All machine types (and x-remote-object, because its init uses machime
>> type's infrastructure) should be skipped, because only the one instance can
>> be correctly initialized.
> It might be obvious to you but I couldn't parse above commit message at all.
> Pls rephrase and explain in more detail what you are trying to achieve.
I want to dump all "default" object properties to compare it with 
compat_props of MachineState. It means that I need values from 
ObjectProperty even it doesn't have default value. For many devices it 
can give useless information. But, for example, x86_64-cpu sets "real" 
default values for specific model only during initialization. 
x86_cpu_properties[] can't give information about kvm default features.
>
>> Signed-off-by: Maxim Davydov <maxim.davydov@openvz.org>
>> ---
>>   qapi/qom.json      |  69 ++++++++++++++++++++++++++
>>   qom/qom-qmp-cmds.c | 121 +++++++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 190 insertions(+)
>>
>> diff --git a/qapi/qom.json b/qapi/qom.json
>> index eeb5395ff3..1eedc441eb 100644
>> --- a/qapi/qom.json
>> +++ b/qapi/qom.json
>> @@ -949,3 +949,72 @@
>>   ##
>>   { 'command': 'object-del', 'data': {'id': 'str'},
>>     'allow-preconfig': true }
>> +
>> +##
>> +# @InitValue:
>> +#
>> +# Not all objects have default values but they have "initial" values.
>> +#
>> +# @name: property name
>> +#
>> +# @value: Current value (default or after initialization. It makes sence,
>> +#         for example, for x86-cpus)
>> +#
>> +# Since: 7.0
>> +#
>> +##
>> +{ 'struct': 'InitValue',
>> +  'data': { 'name': 'str',
>> +            '*value': 'any' } }
>> +
>> +##
>> +# @ClassProperties:
>> +#
>> +# Initial values of properties that are owned by the class
>> +#
>> +# @classname: name of the class that owns appropriate properties
>> +#
>> +# @classprops: List of class properties
>> +#
>> +# Since: 7.0
>> +#
>> +##
>> +{ 'struct': 'ClassProperties',
>> +  'data': { 'classname': 'str',
>> +            '*classprops': [ 'InitValue' ] } }
>> +
>> +##
>> +# @InitProps:
>> +#
>> +# List of properties and their values that are available after class
>> +# initialization. So it important to know default value of the property
>> +# even if it doesn't have "QObject *defval"
>> +#
>> +# @name: Object name
>> +#
>> +# @props: List of properties
>> +#
>> +# Notes: a value in each property was defval if it's available
>> +#        otherwise it's obtained via "(ObjectPropertyAccessor*) get"
>> +#        immediately after initialization of device object.
>> +#
>> +# Since: 7.0
>> +#
>> +##
>> +{ 'struct': 'InitProps',
>> +  'data': { 'name': 'str',
>> +            'props': [ 'ClassProperties' ] } }
>> +
>> +##
>> +# @query-init-properties:
>> +#
>> +# Returns list of all objects (except all types related with machine type)
>> +# with all properties and their "default" values that  will be available
>> +# after initialization. The main purpose of this command is to be used to
>> +# build table with all machine-type-specific properties
>> +#
>> +# Since: 7.0
>> +#
>> +##
>> +{ 'command': 'query-init-properties',
>> +  'returns': [ 'InitProps' ] }
>> diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
>> index 2d6f41ecc7..c1bb3f1f8b 100644
>> --- a/qom/qom-qmp-cmds.c
>> +++ b/qom/qom-qmp-cmds.c
>> @@ -27,6 +27,7 @@
>>   #include "qemu/cutils.h"
>>   #include "qom/object_interfaces.h"
>>   #include "qom/qom-qobject.h"
>> +#include "hw/boards.h"
>>   
>>   ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
>>   {
>> @@ -235,3 +236,123 @@ void qmp_object_del(const char *id, Error **errp)
>>   {
>>       user_creatable_del(id, errp);
>>   }
>> +
>> +static void query_object_prop(InitValueList **props_list, ObjectProperty *prop,
>> +                              Object *obj, Error **errp)
>> +{
>> +    InitValue *prop_info = NULL;
>> +
>> +    /* Skip inconsiderable properties */
>> +    if (strcmp(prop->name, "type") == 0 ||
>> +        strcmp(prop->name, "realized") == 0 ||
>> +        strcmp(prop->name, "hotpluggable") == 0 ||
>> +        strcmp(prop->name, "hotplugged") == 0 ||
>> +        strcmp(prop->name, "parent_bus") == 0) {
>> +        return;
>> +    }
>> +
>> +    prop_info = g_malloc0(sizeof(*prop_info));
>> +    prop_info->name = g_strdup(prop->name);
>> +    prop_info->value = NULL;
>> +    if (prop->defval) {
>> +        prop_info->value = qobject_ref(prop->defval);
>> +    } else if (prop->get) {
>> +        /*
>> +         * crash-information in x86-cpu uses errp to return current state.
>> +         * So, after requesting this property it returns  GenericError:
>> +         * "No crash occured"
>> +         */
>> +        if (strcmp(prop->name, "crash-information") != 0) {
>> +            prop_info->value = object_property_get_qobject(obj, prop->name,
>> +                                                           errp);
>> +        }
>> +    }
>> +    prop_info->has_value = !!prop_info->value;
>> +
>> +    QAPI_LIST_PREPEND(*props_list, prop_info);
>> +}
>> +
>> +typedef struct QIPData {
>> +    InitPropsList **dev_list;
>> +    Error **errp;
>> +} QIPData;
>> +
>> +static void query_init_properties_tramp(gpointer list_data, gpointer opaque)
>> +{
>> +    ObjectClass *k = list_data;
>> +    Object *obj;
>> +    ObjectClass *parent;
>> +    GHashTableIter iter;
>> +
>> +    QIPData *data = opaque;
>> +    ClassPropertiesList *class_props_list = NULL;
>> +    InitProps *dev_info;
>> +
>> +    /* Only one machine can be initialized correctly (it's already happened) */
>> +    if (object_class_dynamic_cast(k, TYPE_MACHINE)) {
>> +        return;
>> +    }
>> +
>> +    const char *klass_name = object_class_get_name(k);
>> +    /*
>> +     * Uses machine type infrastructure with notifiers. It causes immediate
>> +     * notify and SEGSEGV during remote_object_machine_done
>> +     */
>> +    if (strcmp(klass_name, "x-remote-object") == 0) {
>> +        return;
>> +    }
>> +
>> +    dev_info = g_malloc0(sizeof(*dev_info));
>> +    dev_info->name = g_strdup(klass_name);
>> +
>> +    obj = object_new_with_class(k);
>> +
>> +    /*
>> +     * Part of ObjectPropertyIterator infrastructure, but we need more precise
>> +     * control of current class to dump appropriate features
>> +     * This part was taken out from loop because first initialization differ
>> +     * from other reinitializations
>> +     */
>> +    parent = object_get_class(obj);
>> +    g_hash_table_iter_init(&iter, obj->properties);
>> +    const char *prop_owner_name = object_get_typename(obj);
>> +    do {
>> +        InitValueList *prop_list = NULL;
>> +        ClassProperties *class_data;
>> +
>> +        gpointer key, val;
>> +        while (g_hash_table_iter_next(&iter, &key, &val)) {
>> +            query_object_prop(&prop_list, (ObjectProperty *)val, obj,
>> +                              data->errp);
>> +        }
>> +        class_data = g_malloc0(sizeof(*class_data));
>> +        class_data->classname = g_strdup(prop_owner_name);
>> +        class_data->classprops = prop_list;
>> +        class_data->has_classprops = !!prop_list;
>> +
>> +        QAPI_LIST_PREPEND(class_props_list, class_data);
>> +
>> +        if (!parent) {
>> +            break;
>> +        }
>> +        g_hash_table_iter_init(&iter, parent->properties);
>> +        prop_owner_name = object_class_get_name(parent);
>> +        parent = object_class_get_parent(parent);
>> +    } while (true);
>> +    dev_info->props = class_props_list;
>> +    object_unref(OBJECT(obj));
>> +
>> +    QAPI_LIST_PREPEND(*(data->dev_list), dev_info);
>> +}
>> +
>> +InitPropsList *qmp_query_init_properties(Error **errp)
>> +{
>> +    GSList *typename_list = object_class_get_list(TYPE_OBJECT, false);
>> +
>> +    InitPropsList *dev_list = NULL;
>> +    QIPData data = { &dev_list, errp };
>> +    g_slist_foreach(typename_list, query_init_properties_tramp, &data);
>> +    g_slist_free(typename_list);
>> +
>> +    return dev_list;
>> +}
diff mbox series

Patch

diff --git a/qapi/qom.json b/qapi/qom.json
index eeb5395ff3..1eedc441eb 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -949,3 +949,72 @@ 
 ##
 { 'command': 'object-del', 'data': {'id': 'str'},
   'allow-preconfig': true }
+
+##
+# @InitValue:
+#
+# Not all objects have default values but they have "initial" values.
+#
+# @name: property name
+#
+# @value: Current value (default or after initialization. It makes sence,
+#         for example, for x86-cpus)
+#
+# Since: 7.0
+#
+##
+{ 'struct': 'InitValue',
+  'data': { 'name': 'str',
+            '*value': 'any' } }
+
+##
+# @ClassProperties:
+#
+# Initial values of properties that are owned by the class
+#
+# @classname: name of the class that owns appropriate properties
+#
+# @classprops: List of class properties
+#
+# Since: 7.0
+#
+##
+{ 'struct': 'ClassProperties',
+  'data': { 'classname': 'str',
+            '*classprops': [ 'InitValue' ] } }
+
+##
+# @InitProps:
+#
+# List of properties and their values that are available after class
+# initialization. So it important to know default value of the property
+# even if it doesn't have "QObject *defval"
+#
+# @name: Object name
+#
+# @props: List of properties
+#
+# Notes: a value in each property was defval if it's available
+#        otherwise it's obtained via "(ObjectPropertyAccessor*) get"
+#        immediately after initialization of device object.
+#
+# Since: 7.0
+#
+##
+{ 'struct': 'InitProps',
+  'data': { 'name': 'str',
+            'props': [ 'ClassProperties' ] } }
+
+##
+# @query-init-properties:
+#
+# Returns list of all objects (except all types related with machine type)
+# with all properties and their "default" values that  will be available
+# after initialization. The main purpose of this command is to be used to
+# build table with all machine-type-specific properties
+#
+# Since: 7.0
+#
+##
+{ 'command': 'query-init-properties',
+  'returns': [ 'InitProps' ] }
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
index 2d6f41ecc7..c1bb3f1f8b 100644
--- a/qom/qom-qmp-cmds.c
+++ b/qom/qom-qmp-cmds.c
@@ -27,6 +27,7 @@ 
 #include "qemu/cutils.h"
 #include "qom/object_interfaces.h"
 #include "qom/qom-qobject.h"
+#include "hw/boards.h"
 
 ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
 {
@@ -235,3 +236,123 @@  void qmp_object_del(const char *id, Error **errp)
 {
     user_creatable_del(id, errp);
 }
+
+static void query_object_prop(InitValueList **props_list, ObjectProperty *prop,
+                              Object *obj, Error **errp)
+{
+    InitValue *prop_info = NULL;
+
+    /* Skip inconsiderable properties */
+    if (strcmp(prop->name, "type") == 0 ||
+        strcmp(prop->name, "realized") == 0 ||
+        strcmp(prop->name, "hotpluggable") == 0 ||
+        strcmp(prop->name, "hotplugged") == 0 ||
+        strcmp(prop->name, "parent_bus") == 0) {
+        return;
+    }
+
+    prop_info = g_malloc0(sizeof(*prop_info));
+    prop_info->name = g_strdup(prop->name);
+    prop_info->value = NULL;
+    if (prop->defval) {
+        prop_info->value = qobject_ref(prop->defval);
+    } else if (prop->get) {
+        /*
+         * crash-information in x86-cpu uses errp to return current state.
+         * So, after requesting this property it returns  GenericError:
+         * "No crash occured"
+         */
+        if (strcmp(prop->name, "crash-information") != 0) {
+            prop_info->value = object_property_get_qobject(obj, prop->name,
+                                                           errp);
+        }
+    }
+    prop_info->has_value = !!prop_info->value;
+
+    QAPI_LIST_PREPEND(*props_list, prop_info);
+}
+
+typedef struct QIPData {
+    InitPropsList **dev_list;
+    Error **errp;
+} QIPData;
+
+static void query_init_properties_tramp(gpointer list_data, gpointer opaque)
+{
+    ObjectClass *k = list_data;
+    Object *obj;
+    ObjectClass *parent;
+    GHashTableIter iter;
+
+    QIPData *data = opaque;
+    ClassPropertiesList *class_props_list = NULL;
+    InitProps *dev_info;
+
+    /* Only one machine can be initialized correctly (it's already happened) */
+    if (object_class_dynamic_cast(k, TYPE_MACHINE)) {
+        return;
+    }
+
+    const char *klass_name = object_class_get_name(k);
+    /*
+     * Uses machine type infrastructure with notifiers. It causes immediate
+     * notify and SEGSEGV during remote_object_machine_done
+     */
+    if (strcmp(klass_name, "x-remote-object") == 0) {
+        return;
+    }
+
+    dev_info = g_malloc0(sizeof(*dev_info));
+    dev_info->name = g_strdup(klass_name);
+
+    obj = object_new_with_class(k);
+
+    /*
+     * Part of ObjectPropertyIterator infrastructure, but we need more precise
+     * control of current class to dump appropriate features
+     * This part was taken out from loop because first initialization differ
+     * from other reinitializations
+     */
+    parent = object_get_class(obj);
+    g_hash_table_iter_init(&iter, obj->properties);
+    const char *prop_owner_name = object_get_typename(obj);
+    do {
+        InitValueList *prop_list = NULL;
+        ClassProperties *class_data;
+
+        gpointer key, val;
+        while (g_hash_table_iter_next(&iter, &key, &val)) {
+            query_object_prop(&prop_list, (ObjectProperty *)val, obj,
+                              data->errp);
+        }
+        class_data = g_malloc0(sizeof(*class_data));
+        class_data->classname = g_strdup(prop_owner_name);
+        class_data->classprops = prop_list;
+        class_data->has_classprops = !!prop_list;
+
+        QAPI_LIST_PREPEND(class_props_list, class_data);
+
+        if (!parent) {
+            break;
+        }
+        g_hash_table_iter_init(&iter, parent->properties);
+        prop_owner_name = object_class_get_name(parent);
+        parent = object_class_get_parent(parent);
+    } while (true);
+    dev_info->props = class_props_list;
+    object_unref(OBJECT(obj));
+
+    QAPI_LIST_PREPEND(*(data->dev_list), dev_info);
+}
+
+InitPropsList *qmp_query_init_properties(Error **errp)
+{
+    GSList *typename_list = object_class_get_list(TYPE_OBJECT, false);
+
+    InitPropsList *dev_list = NULL;
+    QIPData data = { &dev_list, errp };
+    g_slist_foreach(typename_list, query_init_properties_tramp, &data);
+    g_slist_free(typename_list);
+
+    return dev_list;
+}