From c06982122036546fcbfe40f5b22ae7088d28c9a2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 3 Jul 2018 10:53:27 +0200 Subject: qmp: Say "out-of-band" instead of "Out-Of-Band" Affects documentation and a few error messages. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20180703085358.13941-2-armbru@redhat.com> --- docs/devel/qapi-code-gen.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/devel') diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index 94a7e8f4d0..9625798d16 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -641,7 +641,7 @@ possible, the command expression should include the optional key 'success-response' with boolean value false. So far, only QGA makes use of this member. -A command can be declared to support Out-Of-Band (OOB) execution. By +A command can be declared to support out-of-band (OOB) execution. By default, commands do not support OOB. To declare a command that supports it, the schema includes an extra 'allow-oob' field. For example: -- cgit 1.4.1 From 00ecec151d2323e742af94cccf2de77025f3c0c1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 3 Jul 2018 10:53:38 +0200 Subject: qmp: Redo how the client requests out-of-band execution Commit cf869d53172 "qmp: support out-of-band (oob) execution" added a general mechanism for command-independent arguments just for an out-of-band flag: The "control" key is introduced to store this extra flag. "control" field is used to store arguments that are shared by all the commands, rather than command specific arguments. Let "run-oob" be the first. However, it failed to reject unknown members of "control". For instance, in QMP command {"execute": "query-name", "id": 42, "control": {"crap": true}} "crap" gets silently ignored. Instead of fixing this, revert the general "control" mechanism (because YAGNI), and do it the way I initially proposed, with key "exec-oob". Simpler code, simpler interface. An out-of-band command {"execute": "migrate-pause", "id": 42, "control": {"run-oob": true}} becomes {"exec-oob": "migrate-pause", "id": 42} Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20180703085358.13941-13-armbru@redhat.com> [Commit message typo fixed] --- docs/devel/qapi-code-gen.txt | 10 ++++----- docs/interop/qmp-spec.txt | 18 +++++++--------- monitor.c | 3 +++ qapi/qmp-dispatch.c | 51 ++++++++++++++++++-------------------------- tests/qmp-test.c | 7 ++---- tests/test-qga.c | 3 +-- 6 files changed, 39 insertions(+), 53 deletions(-) (limited to 'docs/devel') diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index 9625798d16..f020f6bab2 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -649,13 +649,11 @@ example: { 'command': 'migrate_recover', 'data': { 'uri': 'str' }, 'allow-oob': true } -To execute a command with out-of-band priority, the client specifies -the "control" field in the request, with "run-oob" set to -true. Example: +To execute a command with out-of-band priority, the client uses key +"exec-oob" instead of "execute". Example: - => { "execute": "command-support-oob", - "arguments": { ... }, - "control": { "run-oob": true } } + => { "exec-oob": "migrate-recover", + "arguments": { "uri": "tcp:192.168.1.200:12345" } } <= { "return": { } } Without it, even the commands that support out-of-band execution will diff --git a/docs/interop/qmp-spec.txt b/docs/interop/qmp-spec.txt index a1d6f9ee06..1566b8ae5e 100644 --- a/docs/interop/qmp-spec.txt +++ b/docs/interop/qmp-spec.txt @@ -92,12 +92,16 @@ Currently supported capabilities are: The format for command execution is: -{ "execute": json-string, "arguments": json-object, "id": json-value, - "control": json-object } +{ "execute": json-string, "arguments": json-object, "id": json-value } + +or + +{ "exec-oob": json-string, "arguments": json-object, "id": json-value } Where, -- The "execute" member identifies the command to be executed by the Server +- The "execute" or "exec-oob" member identifies the command to be + executed by the server. The latter requests out-of-band execution. - The "arguments" member is used to pass any arguments required for the execution of the command, it is optional when no arguments are required. Each command documents what contents will be considered @@ -106,9 +110,6 @@ The format for command execution is: command execution, it is optional and will be part of the response if provided. The "id" member can be any json-value. A json-number incremented for each successive command works fine. -- The optional "control" member further specifies how the command is - to be executed. Currently, its only member is optional "run-oob". - See section "2.3.1 Out-of-band execution" for details. 2.3.1 Out-of-band execution --------------------------- @@ -129,9 +130,6 @@ To be able to match responses back to their commands, the client needs to pass "id" with out-of-band commands. Passing it with all commands is recommended for clients that accept capability "oob". -To execute a command out-of-band, the client puts "run-oob": true into -execute's member "control". - If the client sends in-band commands faster than the server can execute them, the server will eventually drop commands to limit the queue length. The sever sends event COMMAND_DROPPED then. @@ -274,7 +272,7 @@ S: { "timestamp": { "seconds": 1258551470, "microseconds": 802384 }, 3.7 Out-of-band execution ------------------------- -C: { "execute": "migrate-pause", "id": 42, "control": { "run-oob": true } } +C: { "exec-oob": "migrate-pause", "id": 42 } S: { "id": 42, "error": { "class": "GenericError", "desc": "migrate-pause is currently only supported during postcopy-active state" } } diff --git a/monitor.c b/monitor.c index 2e443bba13..3bf3e68bdc 100644 --- a/monitor.c +++ b/monitor.c @@ -1300,6 +1300,9 @@ static bool qmp_cmd_oob_check(Monitor *mon, QDict *req, Error **errp) QmpCommand *cmd; command = qdict_get_try_str(req, "execute"); + if (!command) { + command = qdict_get_try_str(req, "exec-oob"); + } if (!command) { error_setg(errp, "Command field 'execute' missing"); return false; diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 0ad0fab8ed..12be120fe7 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -23,11 +23,11 @@ QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, Error **errp) { + const char *exec_key = NULL; const QDictEntry *ent; const char *arg_name; const QObject *arg_obj; - bool has_exec_key = false; - QDict *dict = NULL; + QDict *dict; dict = qobject_to(QDict, request); if (!dict) { @@ -40,23 +40,23 @@ QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, arg_name = qdict_entry_key(ent); arg_obj = qdict_entry_value(ent); - if (!strcmp(arg_name, "execute")) { + if (!strcmp(arg_name, "execute") + || (!strcmp(arg_name, "exec-oob") && allow_oob)) { if (qobject_type(arg_obj) != QTYPE_QSTRING) { - error_setg(errp, - "QMP input member 'execute' must be a string"); + error_setg(errp, "QMP input member '%s' must be a string", + arg_name); return NULL; } - has_exec_key = true; - } else if (!strcmp(arg_name, "arguments")) { - if (qobject_type(arg_obj) != QTYPE_QDICT) { - error_setg(errp, - "QMP input member 'arguments' must be an object"); + if (exec_key) { + error_setg(errp, "QMP input member '%s' clashes with '%s'", + arg_name, exec_key); return NULL; } - } else if (!strcmp(arg_name, "control") && allow_oob) { + exec_key = arg_name; + } else if (!strcmp(arg_name, "arguments")) { if (qobject_type(arg_obj) != QTYPE_QDICT) { error_setg(errp, - "QMP input member 'control' must be a dict"); + "QMP input member 'arguments' must be an object"); return NULL; } } else { @@ -66,7 +66,7 @@ QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, } } - if (!has_exec_key) { + if (!exec_key) { error_setg(errp, "QMP input lacks member 'execute'"); return NULL; } @@ -88,7 +88,11 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, return NULL; } - command = qdict_get_str(dict, "execute"); + command = qdict_get_try_str(dict, "execute"); + if (!command) { + assert(allow_oob); + command = qdict_get_str(dict, "exec-oob"); + } cmd = qmp_find_command(cmds, command); if (cmd == NULL) { error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, @@ -137,25 +141,12 @@ QObject *qmp_build_error_object(Error *err) } /* - * Detect whether a request should be run out-of-band, by quickly - * peeking at whether we have: { "control": { "run-oob": true } }. By - * default commands are run in-band. + * Does @qdict look like a command to be run out-of-band? */ bool qmp_is_oob(QDict *dict) { - QBool *bool_obj; - - dict = qdict_get_qdict(dict, "control"); - if (!dict) { - return false; - } - - bool_obj = qobject_to(QBool, qdict_get(dict, "run-oob")); - if (!bool_obj) { - return false; - } - - return qbool_get_bool(bool_obj); + return qdict_haskey(dict, "exec-oob") + && !qdict_haskey(dict, "execute"); } QObject *qmp_dispatch(QmpCommandList *cmds, QObject *request, diff --git a/tests/qmp-test.c b/tests/qmp-test.c index c9d01b87ca..a7b6ec98e4 100644 --- a/tests/qmp-test.c +++ b/tests/qmp-test.c @@ -176,8 +176,7 @@ static void unblock_blocked_cmd(void) static void send_oob_cmd_that_fails(QTestState *s, const char *id) { - qtest_async_qmp(s, "{ 'execute': 'migrate-pause', 'id': %s," - " 'control': { 'run-oob': true } }", id); + qtest_async_qmp(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id); } static void recv_cmd_id(QTestState *s, const char *id) @@ -229,9 +228,7 @@ static void test_qmp_oob(void) * Try any command that does not support OOB but with OOB flag. We * should get failure. */ - resp = qtest_qmp(qts, - "{ 'execute': 'query-cpus'," - " 'control': { 'run-oob': true } }"); + resp = qtest_qmp(qts, "{ 'exec-oob': 'query-cpus' }"); g_assert(qdict_haskey(resp, "error")); qobject_unref(resp); diff --git a/tests/test-qga.c b/tests/test-qga.c index febabc7ad5..daadf22ea3 100644 --- a/tests/test-qga.c +++ b/tests/test-qga.c @@ -249,8 +249,7 @@ static void test_qga_invalid_oob(gconstpointer fix) QDict *ret, *error; const char *class; - ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'," - " 'control': {'run-oob': true}}"); + ret = qmp_fd(fixture->fd, "{'exec-oob': 'guest-ping'}"); g_assert_nonnull(ret); error = qdict_get_qdict(ret, "error"); -- cgit 1.4.1 From 153d73f320f422ecb5807ac3a93547b9f819599b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 3 Jul 2018 10:53:58 +0200 Subject: qapi: Polish command flags documentation in qapi-code-gen.txt Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20180703085358.13941-33-armbru@redhat.com> --- docs/devel/qapi-code-gen.txt | 61 ++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 36 deletions(-) (limited to 'docs/devel') diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index f020f6bab2..8decd6f17d 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -624,60 +624,48 @@ its return value. In rare cases, QAPI cannot express a type-safe representation of a corresponding Client JSON Protocol command. You then have to suppress generation of a marshalling function by including a key 'gen' with -boolean value false, and instead write your own function. Please try -to avoid adding new commands that rely on this, and instead use -type-safe unions. For an example of this usage: +boolean value false, and instead write your own function. For +example: { 'command': 'netdev_add', 'data': {'type': 'str', 'id': 'str'}, 'gen': false } +Please try to avoid adding new commands that rely on this, and instead +use type-safe unions. + Normally, the QAPI schema is used to describe synchronous exchanges, where a response is expected. But in some cases, the action of a command is expected to change state in a way that a successful response is not possible (although the command will still return a normal dictionary error on failure). When a successful reply is not -possible, the command expression should include the optional key +possible, the command expression includes the optional key 'success-response' with boolean value false. So far, only QGA makes use of this member. -A command can be declared to support out-of-band (OOB) execution. By -default, commands do not support OOB. To declare a command that -supports it, the schema includes an extra 'allow-oob' field. For -example: +Key 'allow-oob' declares whether the command supports out-of-band +(OOB) execution. It defaults to false. For example: { 'command': 'migrate_recover', 'data': { 'uri': 'str' }, 'allow-oob': true } -To execute a command with out-of-band priority, the client uses key -"exec-oob" instead of "execute". Example: - - => { "exec-oob": "migrate-recover", - "arguments": { "uri": "tcp:192.168.1.200:12345" } } - <= { "return": { } } - -Without it, even the commands that support out-of-band execution will -still be run in-band. +See qmp-spec.txt for out-of-band execution syntax and semantics. -Under normal QMP command execution, the following apply to each -command: +Commands supporting out-of-band execution can still be executed +in-band. -- They are executed in order, -- They run only in main thread of QEMU, -- They run with the BQL held. +When a command is executed in-band, its handler runs in the main +thread with the BQL held. -When a command is executed with OOB, the following changes occur: +When a command is executed out-of-band, its handler runs in a +dedicated monitor I/O thread with the BQL *not* held. -- They can be completed before a pending in-band command, -- They run in a dedicated monitor thread, -- They run with the BQL not held. +An OOB-capable command handler must satisfy the following conditions: -OOB command handlers must satisfy the following conditions: - -- It terminates quickly, -- It does not invoke system calls that may block, +- It terminates quickly. +- It does not invoke system calls that may block. - It does not access guest RAM that may block when userfaultfd is - enabled for postcopy live migration, + enabled for postcopy live migration. - It takes only "fast" locks, i.e. all critical sections protected by any lock it takes also satisfy the conditions for OOB command handler code. @@ -686,17 +674,18 @@ The restrictions on locking limit access to shared state. Such access requires synchronization, but OOB commands can't take the BQL or any other "slow" lock. -If in doubt, do not implement OOB execution support. +When in doubt, do not implement OOB execution support. -A command may use the optional 'allow-preconfig' key to permit its execution -at early runtime configuration stage (preconfig runstate). -If not specified then a command defaults to 'allow-preconfig': false. +Key 'allow-preconfig' declares whether the command is available before +the machine is built. It defaults to false. For example: -An example of declaring a command that is enabled during preconfig: { 'command': 'qmp_capabilities', 'data': { '*enable': [ 'QMPCapability' ] }, 'allow-preconfig': true } +QMP is available before the machine is built only when QEMU was +started with --preconfig. + === Events === Usage: { 'event': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT, -- cgit 1.4.1