diff mbox

[qemu,v4,2/2] qmp: Add qom-list-properties to list QOM object properties

Message ID 20180303002504.25142-3-aik@ozlabs.ru (mailing list archive)
State New, archived
Headers show

Commit Message

Alexey Kardashevskiy March 3, 2018, 12:25 a.m. UTC
There is already 'device-list-properties' which does most of the job,
however it does not handle everything returned by qom-list-types such
as machines as they inherit directly from TYPE_OBJECT and not TYPE_DEVICE.
It does not handle abstract classes either.

This adds a new qom-list-properties command which prints properties
of a specific class and its instance. It is pretty much a simplified copy
of the device-list-properties handler.

Since it creates an object instance, device properties should appear
in the output as they are copied to QOM properties at the instance_init
hook.

This adds a object_class_property_iter_init() helper to allow class
properties enumeration uses it in the new QMP command to allow properties
listing for abstract classes.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
---
Changes:
v3:
* Used ObjectPropertyInfo instead of QOMPropertyInfo

v2:
* added abstract classes support, now things like "pci-device" or
"spapr-machine" show properties, previously these would produce
an "abstract class" error

# Conflicts:
#	qapi-schema.json
---
 qapi-schema.json     | 15 +++++++++++++++
 include/qom/object.h | 16 ++++++++++++++++
 qmp.c                | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 qom/object.c         |  7 +++++++
 4 files changed, 87 insertions(+)

Comments

Markus Armbruster April 13, 2018, 2:16 p.m. UTC | #1
Alexey Kardashevskiy <aik@ozlabs.ru> writes:

> There is already 'device-list-properties' which does most of the job,
> however it does not handle everything returned by qom-list-types such
> as machines as they inherit directly from TYPE_OBJECT and not TYPE_DEVICE.
> It does not handle abstract classes either.
>
> This adds a new qom-list-properties command which prints properties
> of a specific class and its instance. It is pretty much a simplified copy
> of the device-list-properties handler.
>
> Since it creates an object instance, device properties should appear
> in the output as they are copied to QOM properties at the instance_init
> hook.
>
> This adds a object_class_property_iter_init() helper to allow class
> properties enumeration uses it in the new QMP command to allow properties
> listing for abstract classes.
>
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> Changes:
> v3:
> * Used ObjectPropertyInfo instead of QOMPropertyInfo
>
> v2:
> * added abstract classes support, now things like "pci-device" or
> "spapr-machine" show properties, previously these would produce
> an "abstract class" error
>
> # Conflicts:
> #	qapi-schema.json
> ---
>  qapi-schema.json     | 15 +++++++++++++++
>  include/qom/object.h | 16 ++++++++++++++++
>  qmp.c                | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
>  qom/object.c         |  7 +++++++
>  4 files changed, 87 insertions(+)
>
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 5cdf89a..3021e90 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -1442,6 +1442,21 @@
>    'returns': [ 'ObjectPropertyInfo' ] }
>  
>  ##
> +# @qom-list-properties:
> +#
> +# List properties associated with a QOM object.
> +#
> +# @typename: the type name of an object
> +#
> +# Returns: a list of ObjectPropertyInfo describing object properties

Quoting my review of the RFC PATCH,
Message-ID: <871si6vt8n.fsf@dusky.pond.sub.org>:

    qom-list-properties is like instantiate with default configuration
    and without realizing + qom-list + destroy.

    We need to instantiate because QOM properties are dynamic: they
    aren't specified by data (which qom-list-properties could simply
    read), they are created by (instantiation) code (which
    qom-list-properties has to run).

    Properties created only after instantiation (by realize, perhaps)
    aren't visible in qom-list-properties.  Do such properties exist?

    Properties created only in non-default configuration aren't visible
    either.  Such properties have to exist, or else dynamic property
    creation would be idiotic.

    Likewise for properties created differently (say with a different
    type) in non-default configuration.  We can hope that no such beasts
    exist.  Since properties get created by code, and code can do
    anything, we're reduced to hope.  Data is so much easier to reason
    about than code.

And Message-ID: <87r2q3n8oe.fsf@dusky.pond.sub.org>:

    Thus, qom-list-properties design limitation: the result need not
    reflect properties of instantiated objects.  It usually does, as
    most QOM properties behave as if they were static.  But when it
    doesn't, what then?  How are users of qom-list-properties supposed
    to deal with such inaccurate / incorrect information?  Do they just
    have to know which properties aren't visible in qom-list-properties,
    and which properties are, but cannot be trusted?

Please document the design limitation in a followup patch.

> +#
> +# Since: 2.12
> +##
> +{ 'command': 'qom-list-properties',
> +  'data': { 'typename': 'str'},
> +  'returns': [ 'ObjectPropertyInfo' ] }
> +
> +##
>  # @xen-set-global-dirty-log:
>  #
>  # Enable or disable the global dirty log mode.
[...]
diff mbox

Patch

diff --git a/qapi-schema.json b/qapi-schema.json
index 5cdf89a..3021e90 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1442,6 +1442,21 @@ 
   'returns': [ 'ObjectPropertyInfo' ] }
 
 ##
+# @qom-list-properties:
+#
+# List properties associated with a QOM object.
+#
+# @typename: the type name of an object
+#
+# Returns: a list of ObjectPropertyInfo describing object properties
+#
+# Since: 2.12
+##
+{ 'command': 'qom-list-properties',
+  'data': { 'typename': 'str'},
+  'returns': [ 'ObjectPropertyInfo' ] }
+
+##
 # @xen-set-global-dirty-log:
 #
 # Enable or disable the global dirty log mode.
diff --git a/include/qom/object.h b/include/qom/object.h
index dc73d59..ef07d78 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -1017,6 +1017,22 @@  void object_property_iter_init(ObjectPropertyIterator *iter,
                                Object *obj);
 
 /**
+ * object_class_property_iter_init:
+ * @klass: the class
+ *
+ * Initializes an iterator for traversing all properties
+ * registered against an object class and all parent classes.
+ *
+ * It is forbidden to modify the property list while iterating,
+ * whether removing or adding properties.
+ *
+ * This can be used on abstract classes as it does not create a temporary
+ * instance.
+ */
+void object_class_property_iter_init(ObjectPropertyIterator *iter,
+                                     ObjectClass *klass);
+
+/**
  * object_property_iter_next:
  * @iter: the iterator instance
  *
diff --git a/qmp.c b/qmp.c
index 42b7862..acd9048 100644
--- a/qmp.c
+++ b/qmp.c
@@ -576,6 +576,55 @@  ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
     return prop_list;
 }
 
+ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
+                                             Error **errp)
+{
+    ObjectClass *klass;
+    Object *obj = NULL;
+    ObjectProperty *prop;
+    ObjectPropertyIterator iter;
+    ObjectPropertyInfoList *prop_list = NULL;
+
+    klass = object_class_by_name(typename);
+    if (klass == NULL) {
+        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+                  "Class '%s' not found", typename);
+        return NULL;
+    }
+
+    klass = object_class_dynamic_cast(klass, TYPE_OBJECT);
+    if (klass == NULL) {
+        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", TYPE_OBJECT);
+        return NULL;
+    }
+
+    if (object_class_is_abstract(klass)) {
+        object_class_property_iter_init(&iter, klass);
+    } else {
+        obj = object_new(typename);
+        object_property_iter_init(&iter, obj);
+    }
+    while ((prop = object_property_iter_next(&iter))) {
+        ObjectPropertyInfo *info;
+        ObjectPropertyInfoList *entry;
+
+        info = g_malloc0(sizeof(*info));
+        info->name = g_strdup(prop->name);
+        info->type = g_strdup(prop->type);
+        info->has_description = !!prop->description;
+        info->description = g_strdup(prop->description);
+
+        entry = g_malloc0(sizeof(*entry));
+        entry->value = info;
+        entry->next = prop_list;
+        prop_list = entry;
+    }
+
+    object_unref(obj);
+
+    return prop_list;
+}
+
 CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
 {
     return arch_query_cpu_definitions(errp);
diff --git a/qom/object.c b/qom/object.c
index 5dcee46..e7978bd 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1037,6 +1037,13 @@  ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter)
     return val;
 }
 
+void object_class_property_iter_init(ObjectPropertyIterator *iter,
+                                     ObjectClass *klass)
+{
+    g_hash_table_iter_init(&iter->iter, klass->properties);
+    iter->nextclass = klass;
+}
+
 ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name,
                                            Error **errp)
 {