aboutsummaryrefslogtreecommitdiff
path: root/qom/object.c
diff options
context:
space:
mode:
Diffstat (limited to 'qom/object.c')
-rw-r--r--qom/object.c131
1 files changed, 99 insertions, 32 deletions
diff --git a/qom/object.c b/qom/object.c
index a2a1ffa1b3..f4de619b7b 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1023,10 +1023,23 @@ out:
g_free(type);
}
+void object_property_allow_set_link(Object *obj, const char *name,
+ Object *val, Error **errp)
+{
+ /* Allow the link to be set, always */
+}
+
+typedef struct {
+ Object **child;
+ void (*check)(Object *, const char *, Object *, Error **);
+ ObjectPropertyLinkFlags flags;
+} LinkProperty;
+
static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
- Object **child = opaque;
+ LinkProperty *lprop = opaque;
+ Object **child = lprop->child;
gchar *path;
if (*child) {
@@ -1039,65 +1052,119 @@ static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
}
}
-static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
- const char *name, Error **errp)
+/*
+ * object_resolve_link:
+ *
+ * Lookup an object and ensure its type matches the link property type. This
+ * is similar to object_resolve_path() except type verification against the
+ * link property is performed.
+ *
+ * Returns: The matched object or NULL on path lookup failures.
+ */
+static Object *object_resolve_link(Object *obj, const char *name,
+ const char *path, Error **errp)
{
- Object **child = opaque;
- Object *old_target;
- bool ambiguous = false;
const char *type;
- char *path;
gchar *target_type;
+ bool ambiguous = false;
+ Object *target;
+ /* Go from link<FOO> to FOO. */
type = object_property_get_type(obj, name, NULL);
+ target_type = g_strndup(&type[5], strlen(type) - 6);
+ target = object_resolve_path_type(path, target_type, &ambiguous);
+
+ if (ambiguous) {
+ error_set(errp, QERR_AMBIGUOUS_PATH, path);
+ } else if (!target) {
+ target = object_resolve_path(path, &ambiguous);
+ if (target || ambiguous) {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
+ } else {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, path);
+ }
+ target = NULL;
+ }
+ g_free(target_type);
- visit_type_str(v, &path, name, errp);
-
- old_target = *child;
- *child = NULL;
+ return target;
+}
- if (strcmp(path, "") != 0) {
- Object *target;
+static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ Error *local_err = NULL;
+ LinkProperty *prop = opaque;
+ Object **child = prop->child;
+ Object *old_target = *child;
+ Object *new_target = NULL;
+ char *path = NULL;
- /* Go from link<FOO> to FOO. */
- target_type = g_strndup(&type[5], strlen(type) - 6);
- target = object_resolve_path_type(path, target_type, &ambiguous);
+ visit_type_str(v, &path, name, &local_err);
- if (ambiguous) {
- error_set(errp, QERR_AMBIGUOUS_PATH, path);
- } else if (target) {
- object_ref(target);
- *child = target;
- } else {
- target = object_resolve_path(path, &ambiguous);
- if (target || ambiguous) {
- error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
- } else {
- error_set(errp, QERR_DEVICE_NOT_FOUND, path);
- }
- }
- g_free(target_type);
+ if (!local_err && strcmp(path, "") != 0) {
+ new_target = object_resolve_link(obj, name, path, &local_err);
}
g_free(path);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ prop->check(obj, name, new_target, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ if (new_target) {
+ object_ref(new_target);
+ }
+ *child = new_target;
if (old_target != NULL) {
object_unref(old_target);
}
}
+static void object_release_link_property(Object *obj, const char *name,
+ void *opaque)
+{
+ LinkProperty *prop = opaque;
+
+ if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) {
+ object_unref(*prop->child);
+ }
+ g_free(prop);
+}
+
void object_property_add_link(Object *obj, const char *name,
const char *type, Object **child,
+ void (*check)(Object *, const char *,
+ Object *, Error **),
+ ObjectPropertyLinkFlags flags,
Error **errp)
{
+ Error *local_err = NULL;
+ LinkProperty *prop = g_malloc(sizeof(*prop));
gchar *full_type;
+ prop->child = child;
+ prop->check = check;
+ prop->flags = flags;
+
full_type = g_strdup_printf("link<%s>", type);
object_property_add(obj, name, full_type,
object_get_link_property,
- object_set_link_property,
- NULL, child, errp);
+ check ? object_set_link_property : NULL,
+ object_release_link_property,
+ prop,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ g_free(prop);
+ }
g_free(full_type);
}