Skip to content

Commit

Permalink
qom: add helpers for UserCreatable object types
Browse files Browse the repository at this point in the history
The QMP monitor code has two helper methods object_add
and qmp_object_del that are called from several places
in the code (QMP, HMP and main emulator startup).

The HMP and main emulator startup code also share
further logic that extracts the qom-type & id
values from a qdict.

We soon need to use this logic from qemu-img, qemu-io
and qemu-nbd too, but don't want those to depend on
the monitor, nor do we want to duplicate the code.

To avoid this, move some code out of qmp.c and hmp.c
adding new methods to qom/object_interfaces.c

 - user_creatable_add - takes a QDict holding a full
   object definition & instantiates it
 - user_creatable_add_type - takes an ID, type name,
   and QDict holding object properties & instantiates
   it
 - user_creatable_add_opts - takes a QemuOpts holding
   a full object definition & instantiates it
 - user_creatable_add_opts_foreach - variant on
   user_creatable_add_opts which can be directly used
   in conjunction with qemu_opts_foreach.
 - user_creatable_del - takes an ID and deletes the
   corresponding object

The existing code is updated to use these new methods.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1455129674-17255-2-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
berrange authored and bonzini committed Feb 16, 2016
1 parent 73d60fa commit 90998d5
Show file tree
Hide file tree
Showing 6 changed files with 290 additions and 175 deletions.
52 changes: 11 additions & 41 deletions hmp.c
Expand Up @@ -30,6 +30,7 @@
#include "qapi/string-output-visitor.h"
#include "qapi/util.h"
#include "qapi-visit.h"
#include "qom/object_interfaces.h"
#include "ui/console.h"
#include "block/qapi.h"
#include "qemu-io.h"
Expand Down Expand Up @@ -1655,58 +1656,27 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
void hmp_object_add(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
Error *err_end = NULL;
QemuOpts *opts;
char *type = NULL;
char *id = NULL;
OptsVisitor *ov;
QDict *pdict;
Visitor *v;
Object *obj = NULL;

opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
if (err) {
goto out;
hmp_handle_error(mon, &err);
return;
}

ov = opts_visitor_new(opts);
pdict = qdict_clone_shallow(qdict);
v = opts_get_visitor(ov);

visit_start_struct(v, NULL, NULL, 0, &err);
if (err) {
goto out_clean;
}

qdict_del(pdict, "qom-type");
visit_type_str(v, "qom-type", &type, &err);
if (err) {
goto out_end;
}
obj = user_creatable_add(qdict, opts_get_visitor(ov), &err);
opts_visitor_cleanup(ov);
qemu_opts_del(opts);

qdict_del(pdict, "id");
visit_type_str(v, "id", &id, &err);
if (err) {
goto out_end;
hmp_handle_error(mon, &err);
}

object_add(type, id, pdict, v, &err);

out_end:
visit_end_struct(v, &err_end);
if (!err && err_end) {
qmp_object_del(id, NULL);
if (obj) {
object_unref(obj);
}
error_propagate(&err, err_end);
out_clean:
opts_visitor_cleanup(ov);

QDECREF(pdict);
qemu_opts_del(opts);
g_free(id);
g_free(type);

out:
hmp_handle_error(mon, &err);
}

void hmp_getfd(Monitor *mon, const QDict *qdict)
Expand Down Expand Up @@ -1934,7 +1904,7 @@ void hmp_object_del(Monitor *mon, const QDict *qdict)
const char *id = qdict_get_str(qdict, "id");
Error *err = NULL;

qmp_object_del(id, &err);
user_creatable_del(id, &err);
hmp_handle_error(mon, &err);
}

Expand Down
3 changes: 0 additions & 3 deletions include/monitor/monitor.h
Expand Up @@ -43,9 +43,6 @@ void monitor_read_command(Monitor *mon, int show_prompt);
int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
void *opaque);

void object_add(const char *type, const char *id, const QDict *qdict,
Visitor *v, Error **errp);

AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
bool has_opaque, const char *opaque,
Error **errp);
Expand Down
92 changes: 92 additions & 0 deletions include/qom/object_interfaces.h
Expand Up @@ -2,6 +2,8 @@
#define OBJECT_INTERFACES_H

#include "qom/object.h"
#include "qapi/qmp/qdict.h"
#include "qapi/visitor.h"

#define TYPE_USER_CREATABLE "user-creatable"

Expand Down Expand Up @@ -72,4 +74,94 @@ void user_creatable_complete(Object *obj, Error **errp);
* from implements USER_CREATABLE interface.
*/
bool user_creatable_can_be_deleted(UserCreatable *uc, Error **errp);

/**
* user_creatable_add:
* @qdict: the object definition
* @v: the visitor
* @errp: if an error occurs, a pointer to an area to store the error
*
* Create an instance of the user creatable object whose type
* is defined in @qdict by the 'qom-type' field, placing it
* in the object composition tree with name provided by the
* 'id' field. The remaining fields in @qdict are used to
* initialize the object properties.
*
* Returns: the newly created object or NULL on error
*/
Object *user_creatable_add(const QDict *qdict,
Visitor *v, Error **errp);

/**
* user_creatable_add_type:
* @type: the object type name
* @id: the unique ID for the object
* @qdict: the object properties
* @v: the visitor
* @errp: if an error occurs, a pointer to an area to store the error
*
* Create an instance of the user creatable object @type, placing
* it in the object composition tree with name @id, initializing
* it with properties from @qdict
*
* Returns: the newly created object or NULL on error
*/
Object *user_creatable_add_type(const char *type, const char *id,
const QDict *qdict,
Visitor *v, Error **errp);

/**
* user_creatable_add_opts:
* @opts: the object definition
* @errp: if an error occurs, a pointer to an area to store the error
*
* Create an instance of the user creatable object whose type
* is defined in @opts by the 'qom-type' option, placing it
* in the object composition tree with name provided by the
* 'id' field. The remaining options in @opts are used to
* initialize the object properties.
*
* Returns: the newly created object or NULL on error
*/
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp);


/**
* user_creatable_add_opts_predicate:
* @type: the QOM type to be added
*
* A callback function to determine whether an object
* of type @type should be created. Instances of this
* callback should be passed to user_creatable_add_opts_foreach
*/
typedef bool (*user_creatable_add_opts_predicate)(const char *type);

/**
* user_creatable_add_opts_foreach:
* @opaque: a user_creatable_add_opts_predicate callback or NULL
* @opts: options to create
* @errp: if an error occurs, a pointer to an area to store the error
*
* An iterator callback to be used in conjunction with
* the qemu_opts_foreach() method for creating a list of
* objects from a set of QemuOpts
*
* The @opaque parameter can be passed a user_creatable_add_opts_predicate
* callback to filter which types of object are created during iteration.
*
* Returns: 0 on success, -1 on error
*/
int user_creatable_add_opts_foreach(void *opaque,
QemuOpts *opts, Error **errp);

/**
* user_creatable_del:
* @id: the unique ID for the object
* @errp: if an error occurs, a pointer to an area to store the error
*
* Delete an instance of the user creatable object identified
* by @id.
*/
void user_creatable_del(const char *id, Error **errp);

#endif
76 changes: 7 additions & 69 deletions qmp.c
Expand Up @@ -633,65 +633,13 @@ void qmp_add_client(const char *protocol, const char *fdname,
close(fd);
}

void object_add(const char *type, const char *id, const QDict *qdict,
Visitor *v, Error **errp)
{
Object *obj;
ObjectClass *klass;
const QDictEntry *e;
Error *local_err = NULL;

klass = object_class_by_name(type);
if (!klass) {
error_setg(errp, "invalid object type: %s", type);
return;
}

if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
error_setg(errp, "object type '%s' isn't supported by object-add",
type);
return;
}

if (object_class_is_abstract(klass)) {
error_setg(errp, "object type '%s' is abstract", type);
return;
}

obj = object_new(type);
if (qdict) {
for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
object_property_set(obj, v, e->key, &local_err);
if (local_err) {
goto out;
}
}
}

object_property_add_child(object_get_objects_root(),
id, obj, &local_err);
if (local_err) {
goto out;
}

user_creatable_complete(obj, &local_err);
if (local_err) {
object_property_del(object_get_objects_root(),
id, &error_abort);
goto out;
}
out:
if (local_err) {
error_propagate(errp, local_err);
}
object_unref(obj);
}

void qmp_object_add(const char *type, const char *id,
bool has_props, QObject *props, Error **errp)
{
const QDict *pdict = NULL;
QmpInputVisitor *qiv;
Object *obj;

if (props) {
pdict = qobject_to_qdict(props);
Expand All @@ -702,27 +650,17 @@ void qmp_object_add(const char *type, const char *id,
}

qiv = qmp_input_visitor_new(props);
object_add(type, id, pdict, qmp_input_get_visitor(qiv), errp);
obj = user_creatable_add_type(type, id, pdict,
qmp_input_get_visitor(qiv), errp);
qmp_input_visitor_cleanup(qiv);
if (obj) {
object_unref(obj);
}
}

void qmp_object_del(const char *id, Error **errp)
{
Object *container;
Object *obj;

container = object_get_objects_root();
obj = object_resolve_path_component(container, id);
if (!obj) {
error_setg(errp, "object id not found");
return;
}

if (!user_creatable_can_be_deleted(USER_CREATABLE(obj), errp)) {
error_setg(errp, "%s is in use, can not be deleted", id);
return;
}
object_unparent(obj);
user_creatable_del(id, errp);
}

MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp)
Expand Down

0 comments on commit 90998d5

Please sign in to comment.