Message ID | 1387386003-8949-12-git-send-email-lcapitulino@redhat.com |
---|---|
State | New |
Headers | show |
On Thu, Dec 19, 2013 at 3:00 AM, Luiz Capitulino <lcapitulino@redhat.com> wrote: > From: Paolo Bonzini <pbonzini@redhat.com> > > Add two commands that are the monitor counterparts of -object. The commands > have the same Visitor-based implementation, but use different kinds of > visitors so that the HMP command has a DWIM string-based syntax, while > the QMP variant accepts a stricter JSON-based properties dictionary. > > Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> > Reviewed-By: Igor Mammedov <imammedo@redhat.com> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com> > --- > hmp-commands.hx | 14 +++++++++++ > hmp.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ > hmp.h | 1 + > include/monitor/monitor.h | 3 +++ > include/qapi/visitor.h | 3 +-- > include/qemu/typedefs.h | 2 ++ > qapi-schema.json | 20 +++++++++++++++ > qmp-commands.hx | 27 +++++++++++++++++++++ > qmp.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++ > 9 files changed, 188 insertions(+), 2 deletions(-) > > diff --git a/hmp-commands.hx b/hmp-commands.hx > index ebe8e78..2951d1e 100644 > --- a/hmp-commands.hx > +++ b/hmp-commands.hx > @@ -1243,6 +1243,20 @@ STEXI > Remove host network device. > ETEXI > > + { > + .name = "object_add", > + .args_type = "object:O", > + .params = "[qom-type=]type,id=str[,prop=value][,...]", > + .help = "create QOM object", > + .mhandler.cmd = hmp_object_add, > + }, > + > +STEXI > +@item object_add > +@findex object_add > +Create QOM object. > +ETEXI > + > #ifdef CONFIG_SLIRP > { > .name = "hostfwd_add", > diff --git a/hmp.c b/hmp.c > index 32ee285..a1669ab 100644 > --- a/hmp.c > +++ b/hmp.c > @@ -21,6 +21,7 @@ > #include "qmp-commands.h" > #include "qemu/sockets.h" > #include "monitor/monitor.h" > +#include "qapi/opts-visitor.h" > #include "ui/console.h" > #include "block/qapi.h" > #include "qemu-io.h" > @@ -1354,6 +1355,63 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict) > hmp_handle_error(mon, &err); > } > > +void hmp_object_add(Monitor *mon, const QDict *qdict) > +{ > + Error *err = NULL; > + QemuOpts *opts; > + char *type = NULL; > + char *id = NULL; > + void *dummy = NULL; > + OptsVisitor *ov; > + QDict *pdict; > + > + opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err); > + if (error_is_set(&err)) { > + goto out; > + } > + > + ov = opts_visitor_new(opts); > + pdict = qdict_clone_shallow(qdict); > + > + visit_start_struct(opts_get_visitor(ov), &dummy, NULL, NULL, 0, &err); > + if (error_is_set(&err)) { > + goto out_clean; > + } > + > + qdict_del(pdict, "qom-type"); > + visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err); > + if (error_is_set(&err)) { > + goto out_clean; > + } > + > + qdict_del(pdict, "id"); > + visit_type_str(opts_get_visitor(ov), &id, "id", &err); > + if (error_is_set(&err)) { > + goto out_clean; > + } > + > + object_add(type, id, pdict, opts_get_visitor(ov), &err); > + if (error_is_set(&err)) { > + goto out_clean; > + } > + visit_end_struct(opts_get_visitor(ov), &err); > + if (error_is_set(&err)) { > + qmp_object_del(id, NULL); This is not bisect-able as you add this function in the next commit: CC audio/sdlaudio.o CC audio/ossaudio.o hmp.c: In function âhmp_object_addâ: hmp.c:1399:9: error: implicit declaration of function âqmp_object_delâ [-Werror=implicit-function-declaration] hmp.c:1399:9: error: nested extern declaration of âqmp_object_delâ [-Werror=nested-externs] CC audio/wavcapture.o cc1: all warnings being treated as errors Regards, Peter
On Fri, 20 Dec 2013 12:15:53 +1000 Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote: > On Thu, Dec 19, 2013 at 3:00 AM, Luiz Capitulino <lcapitulino@redhat.com> wrote: > > From: Paolo Bonzini <pbonzini@redhat.com> > > > > Add two commands that are the monitor counterparts of -object. The commands > > have the same Visitor-based implementation, but use different kinds of > > visitors so that the HMP command has a DWIM string-based syntax, while > > the QMP variant accepts a stricter JSON-based properties dictionary. > > > > Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> > > Reviewed-By: Igor Mammedov <imammedo@redhat.com> > > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com> > > --- > > hmp-commands.hx | 14 +++++++++++ > > hmp.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ > > hmp.h | 1 + > > include/monitor/monitor.h | 3 +++ > > include/qapi/visitor.h | 3 +-- > > include/qemu/typedefs.h | 2 ++ > > qapi-schema.json | 20 +++++++++++++++ > > qmp-commands.hx | 27 +++++++++++++++++++++ > > qmp.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++ > > 9 files changed, 188 insertions(+), 2 deletions(-) > > > > diff --git a/hmp-commands.hx b/hmp-commands.hx > > index ebe8e78..2951d1e 100644 > > --- a/hmp-commands.hx > > +++ b/hmp-commands.hx > > @@ -1243,6 +1243,20 @@ STEXI > > Remove host network device. > > ETEXI > > > > + { > > + .name = "object_add", > > + .args_type = "object:O", > > + .params = "[qom-type=]type,id=str[,prop=value][,...]", > > + .help = "create QOM object", > > + .mhandler.cmd = hmp_object_add, > > + }, > > + > > +STEXI > > +@item object_add > > +@findex object_add > > +Create QOM object. > > +ETEXI > > + > > #ifdef CONFIG_SLIRP > > { > > .name = "hostfwd_add", > > diff --git a/hmp.c b/hmp.c > > index 32ee285..a1669ab 100644 > > --- a/hmp.c > > +++ b/hmp.c > > @@ -21,6 +21,7 @@ > > #include "qmp-commands.h" > > #include "qemu/sockets.h" > > #include "monitor/monitor.h" > > +#include "qapi/opts-visitor.h" > > #include "ui/console.h" > > #include "block/qapi.h" > > #include "qemu-io.h" > > @@ -1354,6 +1355,63 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict) > > hmp_handle_error(mon, &err); > > } > > > > +void hmp_object_add(Monitor *mon, const QDict *qdict) > > +{ > > + Error *err = NULL; > > + QemuOpts *opts; > > + char *type = NULL; > > + char *id = NULL; > > + void *dummy = NULL; > > + OptsVisitor *ov; > > + QDict *pdict; > > + > > + opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err); > > + if (error_is_set(&err)) { > > + goto out; > > + } > > + > > + ov = opts_visitor_new(opts); > > + pdict = qdict_clone_shallow(qdict); > > + > > + visit_start_struct(opts_get_visitor(ov), &dummy, NULL, NULL, 0, &err); > > + if (error_is_set(&err)) { > > + goto out_clean; > > + } > > + > > + qdict_del(pdict, "qom-type"); > > + visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err); > > + if (error_is_set(&err)) { > > + goto out_clean; > > + } > > + > > + qdict_del(pdict, "id"); > > + visit_type_str(opts_get_visitor(ov), &id, "id", &err); > > + if (error_is_set(&err)) { > > + goto out_clean; > > + } > > + > > + object_add(type, id, pdict, opts_get_visitor(ov), &err); > > + if (error_is_set(&err)) { > > + goto out_clean; > > + } > > + visit_end_struct(opts_get_visitor(ov), &err); > > + if (error_is_set(&err)) { > > + qmp_object_del(id, NULL); > > This is not bisect-able as you add this function in the next commit: Thanks for catching it. This was a bad pull request. Paolo, can resend?
diff --git a/hmp-commands.hx b/hmp-commands.hx index ebe8e78..2951d1e 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1243,6 +1243,20 @@ STEXI Remove host network device. ETEXI + { + .name = "object_add", + .args_type = "object:O", + .params = "[qom-type=]type,id=str[,prop=value][,...]", + .help = "create QOM object", + .mhandler.cmd = hmp_object_add, + }, + +STEXI +@item object_add +@findex object_add +Create QOM object. +ETEXI + #ifdef CONFIG_SLIRP { .name = "hostfwd_add", diff --git a/hmp.c b/hmp.c index 32ee285..a1669ab 100644 --- a/hmp.c +++ b/hmp.c @@ -21,6 +21,7 @@ #include "qmp-commands.h" #include "qemu/sockets.h" #include "monitor/monitor.h" +#include "qapi/opts-visitor.h" #include "ui/console.h" #include "block/qapi.h" #include "qemu-io.h" @@ -1354,6 +1355,63 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &err); } +void hmp_object_add(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + QemuOpts *opts; + char *type = NULL; + char *id = NULL; + void *dummy = NULL; + OptsVisitor *ov; + QDict *pdict; + + opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err); + if (error_is_set(&err)) { + goto out; + } + + ov = opts_visitor_new(opts); + pdict = qdict_clone_shallow(qdict); + + visit_start_struct(opts_get_visitor(ov), &dummy, NULL, NULL, 0, &err); + if (error_is_set(&err)) { + goto out_clean; + } + + qdict_del(pdict, "qom-type"); + visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err); + if (error_is_set(&err)) { + goto out_clean; + } + + qdict_del(pdict, "id"); + visit_type_str(opts_get_visitor(ov), &id, "id", &err); + if (error_is_set(&err)) { + goto out_clean; + } + + object_add(type, id, pdict, opts_get_visitor(ov), &err); + if (error_is_set(&err)) { + goto out_clean; + } + visit_end_struct(opts_get_visitor(ov), &err); + if (error_is_set(&err)) { + qmp_object_del(id, NULL); + } + +out_clean: + opts_visitor_cleanup(ov); + + QDECREF(pdict); + qemu_opts_del(opts); + g_free(id); + g_free(type); + g_free(dummy); + +out: + hmp_handle_error(mon, &err); +} + void hmp_getfd(Monitor *mon, const QDict *qdict) { const char *fdname = qdict_get_str(qdict, "fdname"); diff --git a/hmp.h b/hmp.h index 54cf71f..521449b 100644 --- a/hmp.h +++ b/hmp.h @@ -89,5 +89,6 @@ void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict); void hmp_chardev_add(Monitor *mon, const QDict *qdict); void hmp_chardev_remove(Monitor *mon, const QDict *qdict); void hmp_qemu_io(Monitor *mon, const QDict *qdict); +void hmp_object_add(Monitor *mon, const QDict *qdict); #endif diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index 10fa0e3..22d8b8f 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -93,6 +93,9 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret); int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret); +int qmp_object_add(Monitor *mon, const QDict *qdict, QObject **ret); +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, diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 48a2a2e..29da211 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -13,6 +13,7 @@ #ifndef QAPI_VISITOR_CORE_H #define QAPI_VISITOR_CORE_H +#include "qemu/typedefs.h" #include "qapi/qmp/qobject.h" #include "qapi/error.h" #include <stdlib.h> @@ -26,8 +27,6 @@ typedef struct GenericList struct GenericList *next; } GenericList; -typedef struct Visitor Visitor; - void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp); void visit_end_handle(Visitor *v, Error **errp); diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index a4c1b84..4524496 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -10,6 +10,8 @@ typedef struct QEMUBH QEMUBH; typedef struct AioContext AioContext; +typedef struct Visitor Visitor; + struct Monitor; typedef struct Monitor Monitor; typedef struct MigrationParams MigrationParams; diff --git a/qapi-schema.json b/qapi-schema.json index d6f8615..451310b 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2759,6 +2759,26 @@ { 'command': 'netdev_del', 'data': {'id': 'str'} } ## +# @object-add: +# +# Create a QOM object. +# +# @qom-type: the class name for the object to be created +# +# @id: the name of the new object +# +# @props: #optional a dictionary of properties to be passed to the backend +# +# Returns: Nothing on success +# Error if @qom-type is not a valid class name +# +# Since: 2.0 +## +{ 'command': 'object-add', + 'data': {'qom-type': 'str', 'id': 'str', '*props': 'dict'}, + 'gen': 'no' } + +## # @NetdevNoneOptions # # Use it alone to have zero network devices. diff --git a/qmp-commands.hx b/qmp-commands.hx index fba15cd..d09ea53 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -879,6 +879,33 @@ Example: EQMP { + .name = "object-add", + .args_type = "qom-type:s,id:s,props:q?", + .mhandler.cmd_new = qmp_object_add, + }, + +SQMP +object-add +---------- + +Create QOM object. + +Arguments: + +- "qom-type": the object's QOM type, i.e. the class name (json-string) +- "id": the object's ID, must be unique (json-string) +- "props": a dictionary of object property values (optional, json-dict) + +Example: + +-> { "execute": "object-add", "arguments": { "qom-type": "rng-random", "id": "rng1", + "props": { "filename": "/dev/hwrng" } } } +<- { "return": {} } + +EQMP + + + { .name = "block_resize", .args_type = "device:B,size:o", .mhandler.cmd_new = qmp_marshal_input_block_resize, diff --git a/qmp.c b/qmp.c index 4c149b3..580f5e6 100644 --- a/qmp.c +++ b/qmp.c @@ -24,6 +24,8 @@ #include "hw/qdev.h" #include "sysemu/blockdev.h" #include "qom/qom-qobject.h" +#include "qapi/qmp/qobject.h" +#include "qapi/qmp-input-visitor.h" #include "hw/boards.h" NameInfo *qmp_query_name(Error **errp) @@ -529,3 +531,63 @@ void qmp_add_client(const char *protocol, const char *fdname, error_setg(errp, "protocol '%s' is invalid", protocol); close(fd); } + +void object_add(const char *type, const char *id, const QDict *qdict, + Visitor *v, Error **errp) +{ + Object *obj; + const QDictEntry *e; + Error *local_err = NULL; + + if (!object_class_by_name(type)) { + error_setg(errp, "invalid class name"); + 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 (error_is_set(&local_err)) { + error_propagate(errp, local_err); + object_unref(obj); + return; + } + } + } + + object_property_add_child(container_get(object_get_root(), "/objects"), + id, obj, errp); + object_unref(obj); +} + +int qmp_object_add(Monitor *mon, const QDict *qdict, QObject **ret) +{ + const char *type = qdict_get_str(qdict, "qom-type"); + const char *id = qdict_get_str(qdict, "id"); + QObject *props = qdict_get(qdict, "props"); + const QDict *pdict = NULL; + Error *local_err = NULL; + QmpInputVisitor *qiv; + + if (props) { + pdict = qobject_to_qdict(props); + if (!pdict) { + error_set(&local_err, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); + goto out; + } + } + + qiv = qmp_input_visitor_new(props); + object_add(type, id, pdict, qmp_input_get_visitor(qiv), &local_err); + qmp_input_visitor_cleanup(qiv); + +out: + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + return -1; + } + + return 0; +}