Merge remote-tracking branch 'remotes/ehabkost/tags/numa-next-pull-request' into staging

NUMA queue, 2018-05-30

* New command-line option: --preconfig
  This option allows pausing QEMU and allow the configuration
  using QMP commands before running board initialization code.
* New QMP set-numa-node, now made possible because of --preconfig
* Small update on -numa error messages

# gpg: Signature made Thu 31 May 2018 00:02:59 BST
# gpg:                using RSA key 2807936F984DC5A6
# gpg: Good signature from "Eduardo Habkost <ehabkost@redhat.com>"
# Primary key fingerprint: 5A32 2FD5 ABC4 D3DB ACCF  D1AA 2807 936F 984D C5A6

* remotes/ehabkost/tags/numa-next-pull-request:
  tests: functional tests for QMP command set-numa-node
  qmp: add set-numa-node command
  qmp: permit query-hotpluggable-cpus in preconfig state
  tests: extend qmp test with preconfig checks
  cli: add --preconfig option
  tests: qapi-schema tests for allow-preconfig
  qapi: introduce new cmd option "allow-preconfig"
  hmp: disable monitor in preconfig state
  qapi: introduce preconfig runstate
  numa: split out NumaOptions parsing into set_numa_options()
  numa: postpone options post-processing till machine_run_board_init()
  numa: clarify error message when node index is out of range in -numa dist, ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2018-05-31 11:12:36 +01:00
35 changed files with 402 additions and 80 deletions
+10 -1
View File
@@ -559,7 +559,7 @@ following example objects:
Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
'*returns': TYPE-NAME, '*boxed': true,
'*gen': false, '*success-response': false,
'*allow-oob': true }
'*allow-oob': true, '*allow-preconfig': true }
Commands are defined by using a dictionary containing several members,
where three members are most common. The 'command' member is a
@@ -683,6 +683,15 @@ OOB command handlers must satisfy the following conditions:
If 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.
An example of declaring a command that is enabled during preconfig:
{ 'command': 'qmp_capabilities',
'data': { '*enable': [ 'QMPCapability' ] },
'allow-preconfig': true }
=== Events ===
Usage: { 'event': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
+3 -2
View File
@@ -737,7 +737,7 @@ static char *cpu_slot_to_string(const CPUArchId *cpu)
return g_string_free(s, false);
}
static void machine_numa_finish_init(MachineState *machine)
static void machine_numa_finish_cpu_init(MachineState *machine)
{
int i;
bool default_mapping;
@@ -792,7 +792,8 @@ void machine_run_board_init(MachineState *machine)
MachineClass *machine_class = MACHINE_GET_CLASS(machine);
if (nb_numa_nodes) {
machine_numa_finish_init(machine);
numa_complete_configuration(machine);
machine_numa_finish_cpu_init(machine);
}
/* If the machine supports the valid_cpu_types check and the user
+1
View File
@@ -23,6 +23,7 @@ typedef enum QmpCommandOptions
QCO_NO_OPTIONS = 0x0,
QCO_NO_SUCCESS_RESP = (1U << 0),
QCO_ALLOW_OOB = (1U << 1),
QCO_ALLOW_PRECONFIG = (1U << 2),
} QmpCommandOptions;
typedef struct QmpCommand
+2
View File
@@ -22,7 +22,9 @@ struct NumaNodeMem {
};
extern NodeInfo numa_info[MAX_NODES];
int parse_numa(void *opaque, QemuOpts *opts, Error **errp);
void parse_numa_opts(MachineState *ms);
void numa_complete_configuration(MachineState *ms);
void query_numa_node_mem(NumaNodeMem node_mem[]);
extern QemuOptsList qemu_numa_opts;
void numa_legacy_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
+1
View File
@@ -66,6 +66,7 @@ typedef enum WakeupReason {
QEMU_WAKEUP_REASON_OTHER,
} WakeupReason;
void qemu_exit_preconfig_request(void);
void qemu_system_reset_request(ShutdownCause reason);
void qemu_system_suspend_request(void);
void qemu_register_suspend_notifier(Notifier *notifier);
+8 -3
View File
@@ -1179,8 +1179,7 @@ static void monitor_init_qmp_commands(void)
qmp_init_marshal(&qmp_commands);
qmp_register_command(&qmp_commands, "query-qmp-schema",
qmp_query_qmp_schema,
QCO_NO_OPTIONS);
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
QCO_NO_OPTIONS);
qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
@@ -1190,7 +1189,7 @@ static 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_ALLOW_PRECONFIG);
}
static bool qmp_cap_enabled(Monitor *mon, QMPCapability cap)
@@ -3371,6 +3370,12 @@ static void handle_hmp_command(Monitor *mon, const char *cmdline)
trace_handle_hmp_command(mon, cmdline);
if (runstate_check(RUN_STATE_PRECONFIG)) {
monitor_printf(mon, "HMP not available in preconfig state, "
"use QMP instead\n");
return;
}
cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
if (!cmd) {
return;
+48 -27
View File
@@ -141,9 +141,8 @@ static void parse_numa_distance(NumaDistOptions *dist, Error **errp)
uint8_t val = dist->val;
if (src >= MAX_NODES || dst >= MAX_NODES) {
error_setg(errp,
"Invalid node %d, max possible could be %d",
MAX(src, dst), MAX_NODES);
error_setg(errp, "Parameter '%s' expects an integer between 0 and %d",
src >= MAX_NODES ? "src" : "dst", MAX_NODES - 1);
return;
}
@@ -170,28 +169,11 @@ static void parse_numa_distance(NumaDistOptions *dist, Error **errp)
have_numa_distance = true;
}
static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
static
void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
{
NumaOptions *object = NULL;
MachineState *ms = opaque;
Error *err = NULL;
{
Visitor *v = opts_visitor_new(opts);
visit_type_NumaOptions(v, NULL, &object, &err);
visit_free(v);
}
if (err) {
goto end;
}
/* Fix up legacy suffix-less format */
if ((object->type == NUMA_OPTIONS_TYPE_NODE) && object->u.node.has_mem) {
const char *mem_str = qemu_opt_get(opts, "mem");
qemu_strtosz_MiB(mem_str, NULL, &object->u.node.mem);
}
switch (object->type) {
case NUMA_OPTIONS_TYPE_NODE:
parse_numa_node(ms, &object->u.node, &err);
@@ -224,6 +206,31 @@ static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
abort();
}
end:
error_propagate(errp, err);
}
int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
{
NumaOptions *object = NULL;
MachineState *ms = MACHINE(opaque);
Error *err = NULL;
Visitor *v = opts_visitor_new(opts);
visit_type_NumaOptions(v, NULL, &object, &err);
visit_free(v);
if (err) {
goto end;
}
/* Fix up legacy suffix-less format */
if ((object->type == NUMA_OPTIONS_TYPE_NODE) && object->u.node.has_mem) {
const char *mem_str = qemu_opt_get(opts, "mem");
qemu_strtosz_MiB(mem_str, NULL, &object->u.node.mem);
}
set_numa_options(ms, object, &err);
end:
qapi_free_NumaOptions(object);
if (err) {
@@ -339,15 +346,11 @@ void numa_default_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
nodes[i].node_mem = size - usedmem;
}
void parse_numa_opts(MachineState *ms)
void numa_complete_configuration(MachineState *ms)
{
int i;
MachineClass *mc = MACHINE_GET_CLASS(ms);
if (qemu_opts_foreach(qemu_find_opts("numa"), parse_numa, ms, NULL)) {
exit(1);
}
/*
* If memory hotplug is enabled (slots > 0) but without '-numa'
* options explicitly on CLI, guestes will break.
@@ -434,6 +437,24 @@ void parse_numa_opts(MachineState *ms)
}
}
void parse_numa_opts(MachineState *ms)
{
if (qemu_opts_foreach(qemu_find_opts("numa"), parse_numa, ms, NULL)) {
exit(1);
}
}
void qmp_set_numa_node(NumaOptions *cmd, Error **errp)
{
if (!runstate_check(RUN_STATE_PRECONFIG)) {
error_setg(errp, "The command is permitted only in '%s' state",
RunState_str(RUN_STATE_PRECONFIG));
return;
}
set_numa_options(MACHINE(qdev_get_machine()), cmd, errp);
}
void numa_cpu_pre_plug(const CPUArchId *slot, DeviceState *dev, Error **errp)
{
int node_id = object_property_get_int(OBJECT(dev), "node-id", &error_abort);
+4 -1
View File
@@ -262,13 +262,16 @@
# @allow-oob: whether the command allows out-of-band execution.
# (Since: 2.12)
#
# @allow-preconfig: command can be executed in preconfig runstate,
# default: false (Since 3.0)
#
# TODO: @success-response (currently irrelevant, because it's QGA, not QMP)
#
# Since: 2.5
##
{ 'struct': 'SchemaInfoCommand',
'data': { 'arg-type': 'str', 'ret-type': 'str',
'allow-oob': 'bool' } }
'allow-oob': 'bool', 'allow-preconfig': 'bool' } }
##
# @SchemaInfoEvent:
+45 -4
View File
@@ -37,7 +37,8 @@
#
##
{ 'command': 'qmp_capabilities',
'data': { '*enable': [ 'QMPCapability' ] } }
'data': { '*enable': [ 'QMPCapability' ] },
'allow-preconfig': true }
##
# @QMPCapability:
@@ -155,7 +156,8 @@
# Note: This example has been shortened as the real response is too long.
#
##
{ 'command': 'query-commands', 'returns': ['CommandInfo'] }
{ 'command': 'query-commands', 'returns': ['CommandInfo'],
'allow-preconfig': true }
##
# @LostTickPolicy:
@@ -1242,6 +1244,29 @@
##
{ 'command': 'cont' }
##
# @exit-preconfig:
#
# Exit from "preconfig" state
#
# This command makes QEMU exit the preconfig state and proceed with
# VM initialization using configuration data provided on the command line
# and via the QMP monitor during the preconfig state. The command is only
# available during the preconfig state (i.e. when the --preconfig command
# line option was in use).
#
# Since 3.0
#
# Returns: nothing
#
# Example:
#
# -> { "execute": "exit-preconfig" }
# <- { "return": {} }
#
##
{ 'command': 'exit-preconfig', 'allow-preconfig': true }
##
# @system_wakeup:
#
@@ -2648,7 +2673,8 @@
#
##
{'command': 'query-command-line-options', 'data': { '*option': 'str' },
'returns': ['CommandLineOptionInfo'] }
'returns': ['CommandLineOptionInfo'],
'allow-preconfig': true }
##
# @X86CPURegister32:
@@ -3259,7 +3285,8 @@
# ]}
#
##
{ 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'] }
{ 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'],
'allow-preconfig': true }
##
# @GuidInfo:
@@ -3483,3 +3510,17 @@
##
{ 'command': 'x-oob-test', 'data' : { 'lock': 'bool' },
'allow-oob': true }
##
# @set-numa-node:
#
# Runtime equivalent of '-numa' CLI option, available at
# preconfigure stage to configure numa mapping before initializing
# machine.
#
# Since 3.0
##
{ 'command': 'set-numa-node', 'boxed': true,
'data': 'NumaOptions',
'allow-preconfig': true
}
+8
View File
@@ -18,6 +18,7 @@
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qbool.h"
#include "sysemu/sysemu.h"
QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
{
@@ -101,6 +102,13 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
return NULL;
}
if (runstate_check(RUN_STATE_PRECONFIG) &&
!(cmd->options & QCO_ALLOW_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 {
+6 -2
View File
@@ -49,12 +49,15 @@
# @colo: guest is paused to save/restore VM state under colo checkpoint,
# VM can not get into this state unless colo capability is enabled
# for migration. (since 2.8)
# @preconfig: QEMU is paused before board specific init callback is executed.
# The state is reachable only if the --preconfig CLI option is used.
# (Since 3.0)
##
{ 'enum': 'RunState',
'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
'running', 'save-vm', 'shutdown', 'suspended', 'watchdog',
'guest-panicked', 'colo' ] }
'guest-panicked', 'colo', 'preconfig' ] }
##
# @StatusInfo:
@@ -91,7 +94,8 @@
# "status": "running" } }
#
##
{ 'command': 'query-status', 'returns': 'StatusInfo' }
{ 'command': 'query-status', 'returns': 'StatusInfo',
'allow-preconfig': true }
##
# @SHUTDOWN:
+13
View File
@@ -3299,6 +3299,19 @@ STEXI
Run the emulation in single step mode.
ETEXI
DEF("preconfig", 0, QEMU_OPTION_preconfig, \
"--preconfig pause QEMU before machine is initialized\n",
QEMU_ARCH_ALL)
STEXI
@item --preconfig
@findex --preconfig
Pause QEMU for interactive configuration before the machine is created,
which allows querying and configuring properties that will affect
machine initialization. Use the QMP command 'exit-preconfig' to exit
the preconfig state and move to the next state (ie. run guest if -S
isn't used or pause the second time if -S is used).
ETEXI
DEF("S", 0, QEMU_OPTION_S, \
"-S freeze CPU at startup (use 'c' to start execution)\n",
QEMU_ARCH_ALL)
+40
View File
@@ -5,6 +5,7 @@
* CPU emulation::
* Translator Internals::
* QEMU compared to other emulators::
* Managed start up options::
* Bibliography::
@end menu
@@ -314,6 +315,45 @@ VirtualBox [9], Xen [10] and KVM [11] are based on QEMU. QEMU-SystemC
[12] uses QEMU to simulate a system where some hardware devices are
developed in SystemC.
@node Managed start up options
@section Managed start up options
In system mode emulation, it's possible to create a VM in a paused state using
the -S command line option. In this state the machine is completely initialized
according to command line options and ready to execute VM code but VCPU threads
are not executing any code. The VM state in this paused state depends on the way
QEMU was started. It could be in:
@table @asis
@item initial state (after reset/power on state)
@item with direct kernel loading, the initial state could be amended to execute
code loaded by QEMU in the VM's RAM and with incoming migration
@item with incoming migration, initial state will by amended with the migrated
machine state after migration completes.
@end table
This paused state is typically used by users to query machine state and/or
additionally configure the machine (by hotplugging devices) in runtime before
allowing VM code to run.
However, at the -S pause point, it's impossible to configure options that affect
initial VM creation (like: -smp/-m/-numa ...) or cold plug devices. That's
when the --preconfig command line option should be used. It allows pausing QEMU
before the initial VM creation, in a new preconfig state, where additional
queries and configuration can be performed via QMP before moving on to
the resulting configuration startup. In the preconfig state, QEMU only allows
a limited set of commands over the QMP monitor, where the commands do not
depend on an initialized machine, including but not limited to:
@table @asis
@item qmp_capabilities
@item query-qmp-schema
@item query-commands
@item query-status
@item exit-preconfig
@end table
The full list of commands is in QMP schema which could be queried with
query-qmp-schema, where commands supported at preconfig state have option
'allow-preconfig' set to true.
@node Bibliography
@section Bibliography
+10
View File
@@ -161,6 +161,16 @@ SpiceInfo *qmp_query_spice(Error **errp)
};
#endif
void qmp_exit_preconfig(Error **errp)
{
if (!runstate_check(RUN_STATE_PRECONFIG)) {
error_setg(errp, "The command is permitted only in '%s' state",
RunState_str(RUN_STATE_PRECONFIG));
return;
}
qemu_exit_preconfig_request();
}
void qmp_cont(Error **errp)
{
BlockBackend *blk;
+7 -4
View File
@@ -193,13 +193,15 @@ out:
return ret
def gen_register_command(name, success_response, allow_oob):
def gen_register_command(name, success_response, allow_oob, allow_preconfig):
options = []
if not success_response:
options += ['QCO_NO_SUCCESS_RESP']
if allow_oob:
options += ['QCO_ALLOW_OOB']
if allow_preconfig:
options += ['QCO_ALLOW_PRECONFIG']
if not options:
options = ['QCO_NO_OPTIONS']
@@ -275,8 +277,8 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
c_prefix=c_name(self._prefix, protect=False)))
genc.add(gen_registry(self._regy, self._prefix))
def visit_command(self, name, info, arg_type, ret_type,
gen, success_response, boxed, allow_oob):
def visit_command(self, name, info, arg_type, ret_type, gen,
success_response, boxed, allow_oob, allow_preconfig):
if not gen:
return
self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
@@ -285,7 +287,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, allow_oob)
self._regy += gen_register_command(name, success_response, allow_oob,
allow_preconfig)
def gen_commands(schema, output_dir, prefix):
+11 -7
View File
@@ -872,7 +872,8 @@ def check_keys(expr_elem, meta, required, optional=[]):
raise QAPISemError(info,
"'%s' of %s '%s' should only use false value"
% (key, meta, name))
if (key == 'boxed' or key == 'allow-oob') and value is not True:
if (key == 'boxed' or key == 'allow-oob' or
key == 'allow-preconfig') and value is not True:
raise QAPISemError(info,
"'%s' of %s '%s' should only use true value"
% (key, meta, name))
@@ -922,7 +923,7 @@ def check_exprs(exprs):
meta = 'command'
check_keys(expr_elem, 'command', [],
['data', 'returns', 'gen', 'success-response',
'boxed', 'allow-oob'])
'boxed', 'allow-oob', 'allow-preconfig'])
elif 'event' in expr:
meta = 'event'
check_keys(expr_elem, 'event', [], ['data', 'boxed'])
@@ -1044,8 +1045,8 @@ class QAPISchemaVisitor(object):
def visit_alternate_type(self, name, info, variants):
pass
def visit_command(self, name, info, arg_type, ret_type,
gen, success_response, boxed, allow_oob):
def visit_command(self, name, info, arg_type, ret_type, gen,
success_response, boxed, allow_oob, allow_preconfig):
pass
def visit_event(self, name, info, arg_type, boxed):
@@ -1422,7 +1423,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
class QAPISchemaCommand(QAPISchemaEntity):
def __init__(self, name, info, doc, arg_type, ret_type,
gen, success_response, boxed, allow_oob):
gen, success_response, boxed, allow_oob, allow_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)
@@ -1434,6 +1435,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
self.success_response = success_response
self.boxed = boxed
self.allow_oob = allow_oob
self.allow_preconfig = allow_preconfig
def check(self, schema):
if self._arg_type_name:
@@ -1458,7 +1460,8 @@ class QAPISchemaCommand(QAPISchemaEntity):
visitor.visit_command(self.name, self.info,
self.arg_type, self.ret_type,
self.gen, self.success_response,
self.boxed, self.allow_oob)
self.boxed, self.allow_oob,
self.allow_preconfig)
class QAPISchemaEvent(QAPISchemaEntity):
@@ -1678,6 +1681,7 @@ class QAPISchema(object):
success_response = expr.get('success-response', True)
boxed = expr.get('boxed', False)
allow_oob = expr.get('allow-oob', False)
allow_preconfig = expr.get('allow-preconfig', False)
if isinstance(data, OrderedDict):
data = self._make_implicit_object_type(
name, info, doc, 'arg', self._make_members(data, info))
@@ -1686,7 +1690,7 @@ class QAPISchema(object):
rets = self._make_array_type(rets[0], info)
self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
gen, success_response,
boxed, allow_oob))
boxed, allow_oob, allow_preconfig))
def _def_event(self, expr, info, doc):
name = expr['event']
+2 -2
View File
@@ -226,8 +226,8 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
name=doc.symbol,
body=texi_entity(doc, 'Members')))
def visit_command(self, name, info, arg_type, ret_type,
gen, success_response, boxed, allow_oob):
def visit_command(self, name, info, arg_type, ret_type, gen,
success_response, boxed, allow_oob, allow_preconfig):
doc = self.cur_doc
if boxed:
body = texi_body(doc)
+4 -3
View File
@@ -171,14 +171,15 @@ const QLitObject %(c_name)s = %(c_string)s;
{'members': [{'type': self._use_type(m.type)}
for m in variants.variants]})
def visit_command(self, name, info, arg_type, ret_type,
gen, success_response, boxed, allow_oob):
def visit_command(self, name, info, arg_type, ret_type, gen,
success_response, boxed, allow_oob, allow_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_qlit(name, 'command',
{'arg-type': self._use_type(arg_type),
'ret-type': self._use_type(ret_type),
'allow-oob': allow_oob})
'allow-oob': allow_oob,
'allow-preconfig': allow_preconfig})
def visit_event(self, name, info, arg_type, boxed):
arg_type = arg_type or self._schema.the_empty_object_type
+1
View File
@@ -525,6 +525,7 @@ qapi-schema += missing-type.json
qapi-schema += nested-struct-data.json
qapi-schema += non-objects.json
qapi-schema += oob-test.json
qapi-schema += allow-preconfig-test.json
qapi-schema += pragma-doc-required-crap.json
qapi-schema += pragma-extra-junk.json
qapi-schema += pragma-name-case-whitelist-crap.json
+7
View File
@@ -1098,3 +1098,10 @@ void qtest_qmp_device_del(const char *id)
qobject_unref(response1);
qobject_unref(response2);
}
bool qmp_rsp_is_err(QDict *rsp)
{
QDict *error = qdict_get_qdict(rsp, "error");
qobject_unref(rsp);
return !!error;
}

Some files were not shown because too many files have changed in this diff Show More