All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eduardo Habkost <ehabkost@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Kevin Wolf" <kwolf@redhat.com>,
	"Daniel P. Berrangé" <berrange@redhat.com>,
	"Markus Armbruster" <armbru@redhat.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"John Snow" <jsnow@redhat.com>
Subject: [PATCH 11/12] [RFC] qom: Property lock mechanism
Date: Fri,  9 Oct 2020 12:01:21 -0400	[thread overview]
Message-ID: <20201009160122.1662082-12-ehabkost@redhat.com> (raw)
In-Reply-To: <20201009160122.1662082-1-ehabkost@redhat.com>

Add a mechanism to allow QOM types to prevent writable instance
properties from being registered.  This will be used by types
that expose all QOM properties in user-visible interfaces like
object-add and device_add, to ensure our external interfaces are
not affected by dynamic QOM properties.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Daniel P. Berrangé" <berrange@redhat.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: qemu-devel@nongnu.org
---
 include/qom/object.h           | 17 +++++++++
 qom/object.c                   | 28 ++++++++++++++
 tests/test-qdev-global-props.c | 70 ++++++++++++++++++++++++++++++++++
 3 files changed, 115 insertions(+)

diff --git a/include/qom/object.h b/include/qom/object.h
index 1634294e4f..a124cf897d 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -137,6 +137,8 @@ struct ObjectClass
     ObjectUnparent *unparent;
 
     GHashTable *properties;
+    /* instance properties locked.  See object_class_lock_properties() */
+    bool properties_locked;
 };
 
 /**
@@ -1867,6 +1869,21 @@ void object_property_set_description(Object *obj, const char *name,
 void object_class_property_set_description(ObjectClass *klass, const char *name,
                                            const char *description);
 
+/**
+ * object_class_lock_properties:
+ * @oc: the object class to have properties locked
+ *
+ * Prevent all subtypes of @oc from having writeable instance
+ * properties. If @oc is an interface type, this also affects all
+ * classes implementing the interface.
+ *
+ * This can be used by QOM types that have all QOM properties
+ * exposed to the external world (e.g. #TYPE_USER_CREATABLE) to
+ * ensure all user-writable properties are introspectable at the
+ * class level.
+ */
+void object_class_lock_properties(ObjectClass *oc);
+
 /**
  * object_child_foreach:
  * @obj: the object whose children will be navigated
diff --git a/qom/object.c b/qom/object.c
index bb32f5d3ad..73f27b8b7e 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -498,6 +498,27 @@ static void object_class_property_init_all(Object *obj)
     }
 }
 
+void object_class_lock_properties(ObjectClass *oc)
+{
+    oc->properties_locked = true;
+}
+
+static bool object_class_properties_locked(ObjectClass *oc)
+{
+    GSList *i = NULL;
+
+    if (oc->properties_locked) {
+        return true;
+    }
+    for (i = oc->interfaces; i; i = i->next) {
+        ObjectClass *ic = i->data;
+        if (ic->properties_locked) {
+            return true;
+        }
+    }
+    return false;
+}
+
 static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type)
 {
     type_initialize(type);
@@ -1192,8 +1213,15 @@ object_property_try_add(Object *obj, const char *name, const char *type,
                         void *opaque, Error **errp)
 {
     ObjectProperty *prop;
+    ObjectClass *oc = object_get_class(obj);
     size_t name_len = strlen(name);
 
+    if (set && object_class_properties_locked(oc)) {
+        error_setg(errp, "writable instance property not allowed for type %s",
+                   object_class_get_name(oc));
+        return NULL;
+    }
+
     if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) {
         int i;
         ObjectProperty *ret;
diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c
index c8862cac5f..590c916c4b 100644
--- a/tests/test-qdev-global-props.c
+++ b/tests/test-qdev-global-props.c
@@ -58,6 +58,9 @@ static void static_prop_class_init(ObjectClass *oc, void *data)
 
     dc->realize = NULL;
     device_class_set_props(dc, static_props);
+
+    /* test_proplist_lock() will check if property locking works */
+    object_class_lock_properties(oc);
 }
 
 static const TypeInfo static_prop_type = {
@@ -213,6 +216,69 @@ static const TypeInfo nondevice_type = {
     .parent = TYPE_OBJECT,
 };
 
+static void locked_interface_class_base_init(ObjectClass *klass, void *data)
+{
+    object_class_lock_properties(klass);
+}
+
+#define TYPE_LOCKED_INTERFACE "locked-interface"
+static const TypeInfo locked_interface_type = {
+    .name            = TYPE_LOCKED_INTERFACE,
+    .parent          = TYPE_INTERFACE,
+    .class_base_init = locked_interface_class_base_init,
+};
+
+#define TYPE_LOCKED_BY_INTERFACE "locked-by-interface"
+static const TypeInfo locked_by_interface_type = {
+    .name   = TYPE_LOCKED_BY_INTERFACE,
+    .parent = TYPE_OBJECT,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_LOCKED_INTERFACE },
+        { },
+    },
+};
+
+/* Make sure QOM property locking works as expected */
+static void test_proplist_lock(void)
+{
+    g_autoptr(Object) dynamic_obj = object_new(TYPE_DYNAMIC_PROPS);
+    g_autoptr(Object) static_obj = object_new(TYPE_STATIC_PROPS);
+    g_autoptr(Object) locked = object_new(TYPE_LOCKED_BY_INTERFACE);
+    Error *err = NULL;
+
+    /* read-only property: should always work */
+    object_property_try_add(dynamic_obj, "dynamic-prop-ro", "uint32",
+                            prop1_accessor, NULL,
+                            NULL, NULL, &error_abort);
+    object_property_try_add(static_obj, "dynamic-prop-ro", "uint32",
+                            prop1_accessor, NULL,
+                            NULL, NULL, &error_abort);
+    object_property_try_add(locked, "dynamic-prop-ro", "uint32",
+                            prop1_accessor, NULL,
+                            NULL, NULL, &error_abort);
+
+
+    /* read-write property: */
+
+    /* TYPE_DYNAMIC_PROPS is not locked */
+    object_property_try_add(dynamic_obj, "dynamic-prop-rw", "uint32",
+                            prop1_accessor, prop1_accessor,
+                            NULL, NULL, &error_abort);
+
+    /* TYPE_STATIC_PROPS is locked */
+    object_property_try_add(static_obj, "dynamic-prop-rw", "uint32",
+                            prop1_accessor, prop1_accessor,
+                            NULL, NULL, &err);
+    error_free_or_abort(&err);
+
+    /* TYPE_LOCKED_BY_INTERFACE is locked by interface type */
+    object_property_try_add(locked, "dynamic-prop-rw", "uint32",
+                            prop1_accessor, prop1_accessor,
+                            NULL, NULL, &err);
+    error_free_or_abort(&err);
+}
+
+
 /* Test setting of dynamic properties using global properties */
 static void test_dynamic_globalprop_subprocess(void)
 {
@@ -294,6 +360,10 @@ int main(int argc, char **argv)
     type_register_static(&hotplug_type);
     type_register_static(&nohotplug_type);
     type_register_static(&nondevice_type);
+    type_register_static(&locked_interface_type);
+    type_register_static(&locked_by_interface_type);
+
+    g_test_add_func("/qdev/properties/locking", test_proplist_lock);
 
     g_test_add_func("/qdev/properties/static/default/subprocess",
                     test_static_prop_subprocess);
-- 
2.26.2



  parent reply	other threads:[~2020-10-09 16:10 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-09 16:01 [PATCH 00/12] qom: Make all -object types use only class properties Eduardo Habkost
2020-10-09 16:01 ` [PATCH 01/12] qom: Helpers for pointer properties Eduardo Habkost
2020-10-09 16:01 ` [PATCH 02/12] qom: Introduce PointerProperty struct Eduardo Habkost
2020-10-09 16:01 ` [PATCH 03/12] qom: Make object_class_property_add_uint*_ptr() get offset Eduardo Habkost
2020-10-09 17:24   ` Eric Blake
2020-10-09 17:31     ` Eduardo Habkost
2020-10-21 12:24   ` Igor Mammedov
2020-10-21 13:30     ` Eduardo Habkost
2020-10-22  5:06       ` Markus Armbruster
2020-10-22 21:34         ` Eduardo Habkost
2020-10-23 15:33       ` Igor Mammedov
2020-10-27 22:18         ` Eduardo Habkost
2020-10-28 15:22         ` Paolo Bonzini
2020-10-28 15:53           ` Igor Mammedov
2020-10-29 12:56           ` Eduardo Habkost
2020-10-29 13:37             ` Igor Mammedov
2020-10-09 16:01 ` [PATCH 04/12] sev: Use class properties Eduardo Habkost
2020-10-09 16:01 ` [PATCH 05/12] rng: " Eduardo Habkost
2020-10-09 16:01 ` [PATCH 06/12] can_host: " Eduardo Habkost
2020-10-12 14:52   ` Pavel Pisa
2020-10-09 16:01 ` [PATCH 07/12] colo: " Eduardo Habkost
2020-10-09 16:01 ` [PATCH 08/12] netfilter: Reorder functions Eduardo Habkost
2020-10-09 16:01 ` [PATCH 09/12] netfilter: Use class properties Eduardo Habkost
2020-10-09 16:01 ` [PATCH 10/12] input: " Eduardo Habkost
2020-10-13 12:54   ` Gerd Hoffmann
2020-10-09 16:01 ` Eduardo Habkost [this message]
2020-10-09 16:01 ` [PATCH 12/12] [RFC] qom: Lock properties of all TYPE_USER_CREATABLE types Eduardo Habkost
2020-10-09 21:31   ` [PATCH] check-qom-proplist: Don't register instance props for user-creatable type Eduardo Habkost

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201009160122.1662082-12-ehabkost@redhat.com \
    --to=ehabkost@redhat.com \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=jsnow@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.