[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v4 5/9] qapi: introduce new cmd option "allowed-in-p
From: |
Igor Mammedov |
Subject: |
[Qemu-devel] [PATCH v4 5/9] qapi: introduce new cmd option "allowed-in-preconfig" |
Date: |
Mon, 12 Mar 2018 14:11:11 +0100 |
New option will be used to allow commands, which are prepared/need
to run run in preconfig state. Other commands that should be able
to run in preconfig state, should be ammeded to not expect machine
in initialized state or deal with it.
For compatibility reasons, commands, that don't use new flag
'allowed-in-preconfig' explicitly, are not permited to run in
preconfig state but allowed in all other states like they used
to be.
Within this patch allow following commands in preconfig state:
qmp_capabilities
query-qmp-schema
query-commands
query-status
cont
to allow qmp connection, basic introspection and moving to the next
state.
PS:
set-numa-node and query-hotpluggable-cpus will be enabled later in
a separate patch.
Signed-off-by: Igor Mammedov <address@hidden>
---
v4:
* replaces complex "universal" approach
"[PATCH v3 5/9] QAPI: allow to specify valid runstates per command"
with a simpler new command flag "allowed-in-preconfig".
(Eric Blake <address@hidden>)
---
include/qapi/qmp/dispatch.h | 3 ++-
docs/devel/qapi-code-gen.txt | 10 +++++++++-
monitor.c | 5 +++--
qapi/introspect.json | 6 +++++-
qapi/misc.json | 7 ++++---
qapi/qmp-dispatch.c | 8 ++++++++
qapi/run-state.json | 3 ++-
scripts/qapi/commands.py | 19 ++++++++++++++-----
scripts/qapi/common.py | 15 ++++++++++-----
scripts/qapi/doc.py | 2 +-
scripts/qapi/introspect.py | 10 ++++++++--
tests/qapi-schema/test-qapi.py | 2 +-
12 files changed, 67 insertions(+), 23 deletions(-)
diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 1e694b5..2d02b75 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -21,7 +21,8 @@ typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
typedef enum QmpCommandOptions
{
QCO_NO_OPTIONS = 0x0,
- QCO_NO_SUCCESS_RESP = 0x1,
+ QCO_NO_SUCCESS_RESP = 1U << 0,
+ QCO_ALLOWED_IN_PRECONFIG = 1U << 1,
} QmpCommandOptions;
typedef struct QmpCommand
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 25b7180..170f15f 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -556,7 +556,8 @@ following example objects:
Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
'*returns': TYPE-NAME, '*boxed': true,
- '*gen': false, '*success-response': false }
+ '*gen': false, '*success-response': false,
+ '*allowed-in-preconfig': true }
Commands are defined by using a dictionary containing several members,
where three members are most common. The 'command' member is a
@@ -636,6 +637,13 @@ 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 may use optional 'allowed-in-preconfig' key to permit
+its execution at early runtime configuration stage (preconfig runstate).
+If not specified then a command defaults to 'allowed-in-preconfig: false'.
+
+An example of declaring preconfig enabled command:
+ { 'command': 'qmp_capabilities',
+ 'allowed-in-preconfig': true }
=== Events ===
diff --git a/monitor.c b/monitor.c
index ea0ca57..0adf220 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1016,7 +1016,7 @@ void monitor_init_qmp_commands(void)
qmp_register_command(&qmp_commands, "query-qmp-schema",
qmp_query_qmp_schema,
- QCO_NO_OPTIONS);
+ QCO_ALLOWED_IN_PRECONFIG);
qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
QCO_NO_OPTIONS);
qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
@@ -1026,7 +1026,8 @@ void monitor_init_qmp_commands(void)
QTAILQ_INIT(&qmp_cap_negotiation_commands);
qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
- qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS);
+ qmp_marshal_qmp_capabilities,
+ QCO_ALLOWED_IN_PRECONFIG);
}
void qmp_qmp_capabilities(Error **errp)
diff --git a/qapi/introspect.json b/qapi/introspect.json
index 5b3e6e9..05faded 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -259,12 +259,16 @@
#
# @ret-type: the name of the command's result type.
#
+# @allowed-in-preconfig: command could be executed in preconfig runstate,
+# default: 'false' (Since 2.12)
+#
# TODO: @success-response (currently irrelevant, because it's QGA, not QMP)
#
# Since: 2.5
##
{ 'struct': 'SchemaInfoCommand',
- 'data': { 'arg-type': 'str', 'ret-type': 'str' } }
+ 'data': { 'arg-type': 'str', 'ret-type': 'str',
+ 'allowed-in-preconfig': 'bool' } }
##
# @SchemaInfoEvent:
diff --git a/qapi/misc.json b/qapi/misc.json
index bcd5d10..1f48d35 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -24,7 +24,7 @@
# Since: 0.13
#
##
-{ 'command': 'qmp_capabilities' }
+{ 'command': 'qmp_capabilities', 'allowed-in-preconfig': true }
##
# @VersionTriple:
@@ -127,7 +127,8 @@
# Note: This example has been shortened as the real response is too long.
#
##
-{ 'command': 'query-commands', 'returns': ['CommandInfo'] }
+{ 'command': 'query-commands', 'returns': ['CommandInfo'],
+ 'allowed-in-preconfig': true }
##
# @LostTickPolicy:
@@ -1180,7 +1181,7 @@
# <- { "return": {} }
#
##
-{ 'command': 'cont' }
+{ 'command': 'cont', 'allowed-in-preconfig': true }
##
# @system_wakeup:
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index e31ac4b..81dbd19 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -17,6 +17,7 @@
#include "qapi/qmp/json-parser.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
+#include "sysemu/sysemu.h"
static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
{
@@ -92,6 +93,13 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds,
QObject *request,
return NULL;
}
+ if (runstate_check(RUN_STATE_PRECONFIG) &&
+ !(cmd->options & QCO_ALLOWED_IN_PRECONFIG)) {
+ error_setg(errp, "The command '%s' isn't permitted in '%s' state",
+ cmd->name, RunState_str(RUN_STATE_PRECONFIG));
+ return NULL;
+ }
+
if (!qdict_haskey(dict, "arguments")) {
args = qdict_new();
} else {
diff --git a/qapi/run-state.json b/qapi/run-state.json
index ce846a5..174a2a3 100644
--- a/qapi/run-state.json
+++ b/qapi/run-state.json
@@ -94,7 +94,8 @@
# "status": "running" } }
#
##
-{ 'command': 'query-status', 'returns': 'StatusInfo' }
+{ 'command': 'query-status', 'returns': 'StatusInfo',
+ 'allowed-in-preconfig': true }
##
# @SHUTDOWN:
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 21a7e0d..bd8dc5e 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -193,10 +193,18 @@ out:
return ret
-def gen_register_command(name, success_response):
- options = 'QCO_NO_OPTIONS'
+def gen_register_command(name, success_response, allowed_in_preconfig):
+ options = []
+
if not success_response:
- options = 'QCO_NO_SUCCESS_RESP'
+ options += ['QCO_NO_SUCCESS_RESP']
+ if allowed_in_preconfig:
+ options += ['QCO_ALLOWED_IN_PRECONFIG']
+
+ if not options:
+ options = ['QCO_NO_OPTIONS']
+
+ options = " | ".join(options)
ret = mcgen('''
qmp_register_command(cmds, "%(name)s",
@@ -268,7 +276,7 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
genc.add(gen_registry(self._regy, self._prefix))
def visit_command(self, name, info, arg_type, ret_type,
- gen, success_response, boxed):
+ gen, success_response, boxed, allowed_in_preconfig):
if not gen:
return
self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
@@ -277,7 +285,8 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
self._genc.add(gen_marshal_output(ret_type))
self._genh.add(gen_marshal_decl(name))
self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
- self._regy += gen_register_command(name, success_response)
+ self._regy += gen_register_command(name, success_response,
+ allowed_in_preconfig)
def gen_commands(schema, output_dir, prefix):
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 97e9060..e92f514 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -921,7 +921,8 @@ def check_exprs(exprs):
elif 'command' in expr:
meta = 'command'
check_keys(expr_elem, 'command', [],
- ['data', 'returns', 'gen', 'success-response', 'boxed'])
+ ['data', 'returns', 'gen', 'success-response',
+ 'boxed', 'allowed-in-preconfig'])
elif 'event' in expr:
meta = 'event'
check_keys(expr_elem, 'event', [], ['data', 'boxed'])
@@ -1044,7 +1045,7 @@ class QAPISchemaVisitor(object):
pass
def visit_command(self, name, info, arg_type, ret_type,
- gen, success_response, boxed):
+ gen, success_response, boxed, allowed_in_preconfig):
pass
def visit_event(self, name, info, arg_type, boxed):
@@ -1421,7 +1422,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
class QAPISchemaCommand(QAPISchemaEntity):
def __init__(self, name, info, doc, arg_type, ret_type,
- gen, success_response, boxed):
+ gen, success_response, boxed, allowed_in_preconfig):
QAPISchemaEntity.__init__(self, name, info, doc)
assert not arg_type or isinstance(arg_type, str)
assert not ret_type or isinstance(ret_type, str)
@@ -1432,6 +1433,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
self.gen = gen
self.success_response = success_response
self.boxed = boxed
+ self.allowed_in_preconfig = allowed_in_preconfig
def check(self, schema):
if self._arg_type_name:
@@ -1455,7 +1457,8 @@ class QAPISchemaCommand(QAPISchemaEntity):
def visit(self, visitor):
visitor.visit_command(self.name, self.info,
self.arg_type, self.ret_type,
- self.gen, self.success_response, self.boxed)
+ self.gen, self.success_response, self.boxed,
+ self.allowed_in_preconfig)
class QAPISchemaEvent(QAPISchemaEntity):
@@ -1674,6 +1677,7 @@ class QAPISchema(object):
gen = expr.get('gen', True)
success_response = expr.get('success-response', True)
boxed = expr.get('boxed', False)
+ allowed_in_preconfig = expr.get('allowed-in-preconfig', False)
if isinstance(data, OrderedDict):
data = self._make_implicit_object_type(
name, info, doc, 'arg', self._make_members(data, info))
@@ -1681,7 +1685,8 @@ class QAPISchema(object):
assert len(rets) == 1
rets = self._make_array_type(rets[0], info)
self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
- gen, success_response, boxed))
+ gen, success_response, boxed,
+ allowed_in_preconfig))
def _def_event(self, expr, info, doc):
name = expr['event']
diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py
index 0ea68bf..464c89b 100644
--- a/scripts/qapi/doc.py
+++ b/scripts/qapi/doc.py
@@ -228,7 +228,7 @@ class
QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
body=texi_entity(doc, 'Members')))
def visit_command(self, name, info, arg_type, ret_type,
- gen, success_response, boxed):
+ gen, success_response, boxed, allowed_in_preconfig):
doc = self.cur_doc
if boxed:
body = texi_body(doc)
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index f66c397..fa7dc01 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -29,6 +29,11 @@ def to_json(obj, level=0):
to_json(obj[key], level + 1))
for key in sorted(obj.keys())]
ret = '{' + ', '.join(elts) + '}'
+ elif isinstance(obj, bool):
+ if obj:
+ ret = 'true'
+ else:
+ ret = 'false'
else:
assert False # not implemented
if level == 1:
@@ -160,12 +165,13 @@ const char %(c_name)s[] = %(c_string)s;
for m in variants.variants]})
def visit_command(self, name, info, arg_type, ret_type,
- gen, success_response, boxed):
+ gen, success_response, boxed, allowed_in_preconfig):
arg_type = arg_type or self._schema.the_empty_object_type
ret_type = ret_type or self._schema.the_empty_object_type
self._gen_json(name, 'command',
{'arg-type': self._use_type(arg_type),
- 'ret-type': self._use_type(ret_type)})
+ 'ret-type': self._use_type(ret_type),
+ 'allowed-in-preconfig': allowed_in_preconfig})
def visit_event(self, name, info, arg_type, boxed):
arg_type = arg_type or self._schema.the_empty_object_type
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 67e417e..7b22c90 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -42,7 +42,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
self._print_variants(variants)
def visit_command(self, name, info, arg_type, ret_type,
- gen, success_response, boxed):
+ gen, success_response, boxed, allowed_in_preconfig):
print('command %s %s -> %s' % \
(name, arg_type and arg_type.name, ret_type and ret_type.name))
print(' gen=%s success_response=%s boxed=%s' % \
--
2.7.4
- Re: [Qemu-devel] [PATCH v4 3/9] cli: add -preconfig option, (continued)
- Re: [Qemu-devel] [PATCH v4 3/9] cli: add -preconfig option, Eduardo Habkost, 2018/03/23
- Re: [Qemu-devel] [PATCH v4 3/9] cli: add -preconfig option, Eduardo Habkost, 2018/03/23
- Re: [Qemu-devel] [PATCH v4 3/9] cli: add -preconfig option, Igor Mammedov, 2018/03/27
- Re: [Qemu-devel] [PATCH v4 3/9] cli: add -preconfig option, Igor Mammedov, 2018/03/28
- Re: [Qemu-devel] [PATCH v4 3/9] cli: add -preconfig option, Eduardo Habkost, 2018/03/28
- Re: [Qemu-devel] [PATCH v4 3/9] cli: add -preconfig option, Igor Mammedov, 2018/03/29
- Re: [Qemu-devel] [PATCH v4 3/9] cli: add -preconfig option, Eduardo Habkost, 2018/03/29
- Re: [Qemu-devel] [PATCH v4 3/9] cli: add -preconfig option, Eduardo Habkost, 2018/03/28
- Re: [Qemu-devel] [PATCH v4 3/9] cli: add -preconfig option, Igor Mammedov, 2018/03/29
- Re: [Qemu-devel] [PATCH v4 3/9] cli: add -preconfig option, Eduardo Habkost, 2018/03/29
[Qemu-devel] [PATCH v4 5/9] qapi: introduce new cmd option "allowed-in-preconfig",
Igor Mammedov <=
[Qemu-devel] [PATCH v4 8/9] qmp: add set-numa-node command, Igor Mammedov, 2018/03/12
[Qemu-devel] [PATCH v4 9/9] tests: functional tests for QMP command set-numa-node, Igor Mammedov, 2018/03/12
[Qemu-devel] [PATCH v4 7/9] qmp: permit query-hotpluggable-cpus in preconfig state, Igor Mammedov, 2018/03/12