[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v5 17/20] monitor: use qmp_dispatch()
From: |
Marc-André Lureau |
Subject: |
Re: [Qemu-devel] [PATCH v5 17/20] monitor: use qmp_dispatch() |
Date: |
Wed, 17 Aug 2016 13:04:40 -0400 (EDT) |
Hi
----- Original Message -----
> Replace the old manual dispatch and validation code by the generic one
> provided by qapi common code.
>
> Note that it is now possible to call the following commands that used to
> be disabled by compile-time conditionals:
> - dump-skeys
> - query-spice
> - rtc-reset-reinjection
> - query-gic-capabilities
>
> Their fallback functions return an appropriate "feature disabled" error.
This is no longer valid, I dropped that comment.
> Signed-off-by: Marc-André Lureau <address@hidden>
> ---
> monitor.c | 326
> +++++++----------------------------------------------------
> trace-events | 1 -
> 2 files changed, 34 insertions(+), 293 deletions(-)
>
> diff --git a/monitor.c b/monitor.c
> index f07fc31..81926c7 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -166,7 +166,6 @@ struct MonFdset {
> };
>
> typedef struct {
> - QObject *id;
> JSONMessageParser parser;
> /*
> * When a client connects, we're in capabilities negotiation mode.
> @@ -229,8 +228,6 @@ static int mon_refcount;
> static mon_cmd_t mon_cmds[];
> static mon_cmd_t info_cmds[];
>
> -static const mon_cmd_t qmp_cmds[];
> -
> Monitor *cur_mon;
>
> static QEMUClockType event_clock_type = QEMU_CLOCK_REALTIME;
> @@ -401,49 +398,6 @@ static void monitor_json_emitter(Monitor *mon, const
> QObject *data)
> QDECREF(json);
> }
>
> -static QDict *build_qmp_error_dict(Error *err)
> -{
> - QObject *obj;
> -
> - obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %s } }",
> - QapiErrorClass_lookup[error_get_class(err)],
> - error_get_pretty(err));
> -
> - return qobject_to_qdict(obj);
> -}
> -
> -static void monitor_protocol_emitter(Monitor *mon, QObject *data,
> - Error *err)
> -{
> - QDict *qmp;
> -
> - trace_monitor_protocol_emitter(mon);
> -
> - if (!err) {
> - /* success response */
> - qmp = qdict_new();
> - if (data) {
> - qobject_incref(data);
> - qdict_put_obj(qmp, "return", data);
> - } else {
> - /* return an empty QDict by default */
> - qdict_put(qmp, "return", qdict_new());
> - }
> - } else {
> - /* error response */
> - qmp = build_qmp_error_dict(err);
> - }
> -
> - if (mon->qmp.id) {
> - qdict_put_obj(qmp, "id", mon->qmp.id);
> - mon->qmp.id = NULL;
> - }
> -
> - monitor_json_emitter(mon, QOBJECT(qmp));
> - QDECREF(qmp);
> -}
> -
> -
> static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
> /* Limit guest-triggerable events to 1 per second */
> [QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS },
> @@ -2180,11 +2134,6 @@ static mon_cmd_t mon_cmds[] = {
> { NULL, NULL, },
> };
>
> -static const mon_cmd_t qmp_cmds[] = {
> -#include "qmp-commands-old.h"
> - { /* NULL */ },
> -};
> -
> /*******************************************************************/
>
> static const char *pch;
> @@ -2535,11 +2484,6 @@ static const mon_cmd_t *search_dispatch_table(const
> mon_cmd_t *disp_table,
> return NULL;
> }
>
> -static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
> -{
> - return search_dispatch_table(qmp_cmds, cmdname);
> -}
> -
> /*
> * Parse command name from @cmdp according to command table @table.
> * If blank, return NULL.
> @@ -3690,199 +3634,6 @@ static bool invalid_qmp_mode(const Monitor *mon,
> const char *cmd,
> return false;
> }
>
> -/*
> - * Argument validation rules:
> - *
> - * 1. The argument must exist in cmd_args qdict
> - * 2. The argument type must be the expected one
> - *
> - * Special case: If the argument doesn't exist in cmd_args and
> - * the QMP_ACCEPT_UNKNOWNS flag is set, then the
> - * checking is skipped for it.
> - */
> -static void check_client_args_type(const QDict *client_args,
> - const QDict *cmd_args, int flags,
> - Error **errp)
> -{
> - const QDictEntry *ent;
> -
> - for (ent = qdict_first(client_args); ent;ent =
> qdict_next(client_args,ent)){
> - QObject *obj;
> - QString *arg_type;
> - const QObject *client_arg = qdict_entry_value(ent);
> - const char *client_arg_name = qdict_entry_key(ent);
> -
> - obj = qdict_get(cmd_args, client_arg_name);
> - if (!obj) {
> - if (flags & QMP_ACCEPT_UNKNOWNS) {
> - /* handler accepts unknowns */
> - continue;
> - }
> - /* client arg doesn't exist */
> - error_setg(errp, QERR_INVALID_PARAMETER, client_arg_name);
> - return;
> - }
> -
> - arg_type = qobject_to_qstring(obj);
> - assert(arg_type != NULL);
> -
> - /* check if argument's type is correct */
> - switch (qstring_get_str(arg_type)[0]) {
> - case 'F':
> - case 'B':
> - case 's':
> - if (qobject_type(client_arg) != QTYPE_QSTRING) {
> - error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
> - client_arg_name, "string");
> - return;
> - }
> - break;
> - case 'i':
> - case 'l':
> - case 'M':
> - case 'o':
> - if (qobject_type(client_arg) != QTYPE_QINT) {
> - error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
> - client_arg_name, "int");
> - return;
> - }
> - break;
> - case 'T':
> - if (qobject_type(client_arg) != QTYPE_QINT &&
> - qobject_type(client_arg) != QTYPE_QFLOAT) {
> - error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
> - client_arg_name, "number");
> - return;
> - }
> - break;
> - case 'b':
> - case '-':
> - if (qobject_type(client_arg) != QTYPE_QBOOL) {
> - error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
> - client_arg_name, "bool");
> - return;
> - }
> - break;
> - case 'O':
> - assert(flags & QMP_ACCEPT_UNKNOWNS);
> - break;
> - case 'q':
> - /* Any QObject can be passed. */
> - break;
> - case '/':
> - case '.':
> - /*
> - * These types are not supported by QMP and thus are not
> - * handled here. Fall through.
> - */
> - default:
> - abort();
> - }
> - }
> -}
> -
> -/*
> - * - Check if the client has passed all mandatory args
> - * - Set special flags for argument validation
> - */
> -static void check_mandatory_args(const QDict *cmd_args,
> - const QDict *client_args, int *flags,
> - Error **errp)
> -{
> - const QDictEntry *ent;
> -
> - for (ent = qdict_first(cmd_args); ent; ent = qdict_next(cmd_args, ent))
> {
> - const char *cmd_arg_name = qdict_entry_key(ent);
> - QString *type = qobject_to_qstring(qdict_entry_value(ent));
> - assert(type != NULL);
> -
> - if (qstring_get_str(type)[0] == 'O') {
> - assert((*flags & QMP_ACCEPT_UNKNOWNS) == 0);
> - *flags |= QMP_ACCEPT_UNKNOWNS;
> - } else if (qstring_get_str(type)[0] != '-' &&
> - qstring_get_str(type)[1] != '?' &&
> - !qdict_haskey(client_args, cmd_arg_name)) {
> - error_setg(errp, QERR_MISSING_PARAMETER, cmd_arg_name);
> - return;
> - }
> - }
> -}
> -
> -static QDict *qdict_from_args_type(const char *args_type)
> -{
> - int i;
> - QDict *qdict;
> - QString *key, *type, *cur_qs;
> -
> - assert(args_type != NULL);
> -
> - qdict = qdict_new();
> -
> - if (args_type == NULL || args_type[0] == '\0') {
> - /* no args, empty qdict */
> - goto out;
> - }
> -
> - key = qstring_new();
> - type = qstring_new();
> -
> - cur_qs = key;
> -
> - for (i = 0;; i++) {
> - switch (args_type[i]) {
> - case ',':
> - case '\0':
> - qdict_put(qdict, qstring_get_str(key), type);
> - QDECREF(key);
> - if (args_type[i] == '\0') {
> - goto out;
> - }
> - type = qstring_new(); /* qdict has ref */
> - cur_qs = key = qstring_new();
> - break;
> - case ':':
> - cur_qs = type;
> - break;
> - default:
> - qstring_append_chr(cur_qs, args_type[i]);
> - break;
> - }
> - }
> -
> -out:
> - return qdict;
> -}
> -
> -/*
> - * Client argument checking rules:
> - *
> - * 1. Client must provide all mandatory arguments
> - * 2. Each argument provided by the client must be expected
> - * 3. Each argument provided by the client must have the type expected
> - * by the command
> - */
> -static void qmp_check_client_args(const mon_cmd_t *cmd, QDict *client_args,
> - Error **errp)
> -{
> - Error *err = NULL;
> - int flags;
> - QDict *cmd_args;
> -
> - cmd_args = qdict_from_args_type(cmd->args_type);
> -
> - flags = 0;
> - check_mandatory_args(cmd_args, client_args, &flags, &err);
> - if (err) {
> - goto out;
> - }
> -
> - check_client_args_type(client_args, cmd_args, flags, &err);
> -
> -out:
> - error_propagate(errp, err);
> - QDECREF(cmd_args);
> -}
> -
> /*
> * Input object checking rules
> *
> @@ -3941,67 +3692,58 @@ static QDict *qmp_check_input_obj(QObject *input_obj,
> Error **errp)
>
> static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
> {
> - Error *local_err = NULL;
> - QObject *obj, *data;
> - QDict *input, *args;
> - const mon_cmd_t *cmd;
> - QmpCommand *qcmd;
> + QObject *req, *rsp = NULL, *id = NULL;
> + QDict *qdict = NULL;
> const char *cmd_name;
> Monitor *mon = cur_mon;
> + Error *err = NULL;
>
> - args = input = NULL;
> - data = NULL;
> -
> - obj = json_parser_parse(tokens, NULL);
> - if (!obj) {
> - // FIXME: should be triggered in json_parser_parse()
> - error_setg(&local_err, QERR_JSON_PARSING);
> + req = json_parser_parse_err(tokens, NULL, &err);
> + if (err || !req || qobject_type(req) != QTYPE_QDICT) {
> + if (!err) {
> + error_setg(&err, QERR_JSON_PARSING);
> + }
> goto err_out;
> }
>
> - input = qmp_check_input_obj(obj, &local_err);
> - if (!input) {
> - qobject_decref(obj);
> + qdict = qmp_check_input_obj(req, &err);
> + if (!qdict) {
> goto err_out;
> }
>
> - mon->qmp.id = qdict_get(input, "id");
> - qobject_incref(mon->qmp.id);
> + id = qdict_get(qdict, "id");
> + qobject_incref(id);
> + qdict_del(qdict, "id");
>
> - cmd_name = qdict_get_str(input, "execute");
> + cmd_name = qdict_get_str(qdict, "execute");
> trace_handle_qmp_command(mon, cmd_name);
> - cmd = qmp_find_cmd(cmd_name);
> - qcmd = qmp_find_command(cmd_name);
> - if (!qcmd || !cmd) {
> - error_set(&local_err, ERROR_CLASS_COMMAND_NOT_FOUND,
> - "The command %s has not been found", cmd_name);
> - goto err_out;
> - }
> - if (invalid_qmp_mode(mon, cmd_name, &local_err)) {
> +
> + if (invalid_qmp_mode(mon, cmd_name, &err)) {
> goto err_out;
> }
>
> - obj = qdict_get(input, "arguments");
> - if (!obj) {
> - args = qdict_new();
> - } else {
> - args = qobject_to_qdict(obj);
> - QINCREF(args);
> - }
> + rsp = qmp_dispatch(req);
>
> - qmp_check_client_args(cmd, args, &local_err);
> - if (local_err) {
> - goto err_out;
> +err_out:
> + if (err) {
> + qdict = qdict_new();
> + qdict_put_obj(qdict, "error", qmp_build_error_object(err));
> + error_free(err);
> + rsp = QOBJECT(qdict);
> }
>
> - qcmd->fn(args, &data, &local_err);
> + if (rsp) {
> + if (id) {
> + qdict_put_obj(qobject_to_qdict(rsp), "id", id);
> + id = NULL;
> + }
>
> -err_out:
> - monitor_protocol_emitter(mon, data, local_err);
> - qobject_decref(data);
> - error_free(local_err);
> - QDECREF(input);
> - QDECREF(args);
> + monitor_json_emitter(mon, rsp);
> + }
> +
> + qobject_decref(id);
> + qobject_decref(rsp);
> + qobject_decref(req);
> }
>
> static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
> diff --git a/trace-events b/trace-events
> index 616cc52..8d59631 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -98,7 +98,6 @@ qemu_co_mutex_unlock_return(void *mutex, void *self) "mutex
> %p self %p"
>
> # monitor.c
> handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \"%s\""
> -monitor_protocol_emitter(void *mon) "mon %p"
> monitor_protocol_event_handler(uint32_t event, void *qdict) "event=%d
> data=%p"
> monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p"
> monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate)
> "event=%d data=%p rate=%" PRId64
> --
> 2.9.0
>
>
- [Qemu-devel] [PATCH v5 09/20] monitor: simplify invalid_qmp_mode(), (continued)
- [Qemu-devel] [PATCH v5 09/20] monitor: simplify invalid_qmp_mode(), Marc-André Lureau, 2016/08/17
- [Qemu-devel] [PATCH v5 11/20] qapi: export the marshallers, Marc-André Lureau, 2016/08/17
- [Qemu-devel] [PATCH v5 10/20] monitor: register gen:false commands manually, Marc-André Lureau, 2016/08/17
- [Qemu-devel] [PATCH v5 13/20] monitor: implement 'qmp_query_commands' without qmp_cmds, Marc-André Lureau, 2016/08/17
- [Qemu-devel] [PATCH v5 12/20] monitor: use qmp_find_command() (using generated qapi code), Marc-André Lureau, 2016/08/17
- [Qemu-devel] [PATCH v5 15/20] qapi: remove the "middle" mode, Marc-André Lureau, 2016/08/17
- [Qemu-devel] [PATCH v5 14/20] monitor: remove mhandler.cmd_new, Marc-André Lureau, 2016/08/17
- [Qemu-devel] [PATCH v5 16/20] qapi: check invalid arguments on no-args commands, Marc-André Lureau, 2016/08/17
- [Qemu-devel] [PATCH v5 18/20] build-sys: remove qmp-commands-old.h, Marc-André Lureau, 2016/08/17
- [Qemu-devel] [PATCH v5 17/20] monitor: use qmp_dispatch(), Marc-André Lureau, 2016/08/17
- Re: [Qemu-devel] [PATCH v5 17/20] monitor: use qmp_dispatch(),
Marc-André Lureau <=
- [Qemu-devel] [PATCH v5 19/20] qmp-commands.hx: fix some styling, Marc-André Lureau, 2016/08/17
- [Qemu-devel] [PATCH v5 20/20] Replace qmp-commands.hx by doc/qmp-commands.txt, Marc-André Lureau, 2016/08/17