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 |
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; > +}
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; > +}
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; >> +} > >
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 --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; +}
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(+)