[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 11/12] [RFC] qom: Property lock mechanism
From: |
Eduardo Habkost |
Subject: |
[PATCH 11/12] [RFC] qom: Property lock mechanism |
Date: |
Fri, 9 Oct 2020 12:01:21 -0400 |
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
- [PATCH 06/12] can_host: Use class properties, (continued)
- [PATCH 06/12] can_host: Use class properties, Eduardo Habkost, 2020/10/09
- [PATCH 05/12] rng: Use class properties, Eduardo Habkost, 2020/10/09
- [PATCH 07/12] colo: Use class properties, Eduardo Habkost, 2020/10/09
- [PATCH 09/12] netfilter: Use class properties, Eduardo Habkost, 2020/10/09
- [PATCH 10/12] input: Use class properties, Eduardo Habkost, 2020/10/09
- [PATCH 08/12] netfilter: Reorder functions, Eduardo Habkost, 2020/10/09
- [PATCH 12/12] [RFC] qom: Lock properties of all TYPE_USER_CREATABLE types, Eduardo Habkost, 2020/10/09
- [PATCH 11/12] [RFC] qom: Property lock mechanism,
Eduardo Habkost <=