mirror of https://github.com/xqemu/xqemu.git
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 -----BEGIN PGP SIGNATURE----- iQIcBAABCAAGBQJbDy2jAAoJECgHk2+YTcWm8OgP/As0judZ7JwT5F5fR4nxtQPr EODeEI+e/IahGH58Bafx24Fvxy0HZIgwqBDnPgclA8d3ebwmDQIejgk5/00zq2xv cktRpzXGSBGJCVNctVz8xqN91m0lPtVgeRvXUJPn3hthXRSLO4p0vbyOW8g/C+O2 +dEcGqifAQatyxs9gYmmWoUia8zle/v1bd2v/x/DwiFW9cd47yDr3+ChHh6+nx0W uh2zymD+ykVeNJ9WSxc3k8zTzQnuxbDK1fNbZsztk9KQDMWG3+u7KRNoJ86/7hKL RMUfRCUMBgemuZsrFF8wSsha27e9VgCw4oR8dQ5AnTgMjK6nch/839XuFWh7j5qu ntS4vt1v6IczdflKXX7IUILAgvVffLh2SCGWlKq9Q1eKo+CZTCea+iSbb2QobAE+ 9TyuqXVKCsGKLoqkbK39d1UjZFhDQJhMsyuOHreKEINmJRmLI5qrNbEaaysb+mMB DnFE1NiWjE+6X4w9U1l8lnKNUakOPNDG8cbgtuiEKDC9e3OZeiS8yyPLaQajELSR Ig7N2GxrLMSfS3LNMSwkACILzVeu03aFoHyCPrpUqD8mpxidN0mmFVup8dawtkJ1 A5dHrKDmzlOT6DivJOgT8/Os/wMo3ErPcvyu69rTUO9PKSbwcFPwi6bMMDzgb4xO kAles9X7HrHxSeJiggRW =RHIj -----END PGP SIGNATURE----- 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:
commit
a3ac12fba0
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
11
monitor.c
11
monitor.c
|
@ -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;
|
||||
|
|
75
numa.c
75
numa.c
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
qmp.c
10
qmp.c
|
@ -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;
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -972,4 +972,13 @@ void qtest_qmp_device_add(const char *driver, const char *id, const char *fmt,
|
|||
*/
|
||||
void qtest_qmp_device_del(const char *id);
|
||||
|
||||
/**
|
||||
* qmp_rsp_is_err:
|
||||
* @rsp: QMP response to check for error
|
||||
*
|
||||
* Test @rsp for error and discard @rsp.
|
||||
* Returns 'true' if there is error in @rsp and 'false' otherwise.
|
||||
*/
|
||||
bool qmp_rsp_is_err(QDict *rsp);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -260,6 +260,66 @@ static void aarch64_numa_cpu(const void *data)
|
|||
g_free(cli);
|
||||
}
|
||||
|
||||
static void pc_dynamic_cpu_cfg(const void *data)
|
||||
{
|
||||
QObject *e;
|
||||
QDict *resp;
|
||||
QList *cpus;
|
||||
QTestState *qs;
|
||||
|
||||
qs = qtest_startf("%s %s", data ? (char *)data : "",
|
||||
"-nodefaults --preconfig -smp 2");
|
||||
|
||||
/* create 2 numa nodes */
|
||||
g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
|
||||
" 'arguments': { 'type': 'node', 'nodeid': 0 } }")));
|
||||
g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
|
||||
" 'arguments': { 'type': 'node', 'nodeid': 1 } }")));
|
||||
|
||||
/* map 2 cpus in non default reverse order
|
||||
* i.e socket1->node0, socket0->node1
|
||||
*/
|
||||
g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
|
||||
" 'arguments': { 'type': 'cpu', 'node-id': 0, 'socket-id': 1 } }")));
|
||||
g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
|
||||
" 'arguments': { 'type': 'cpu', 'node-id': 1, 'socket-id': 0 } }")));
|
||||
|
||||
/* let machine initialization to complete and run */
|
||||
g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'exit-preconfig' }")));
|
||||
qtest_qmp_eventwait(qs, "RESUME");
|
||||
|
||||
/* check that CPUs are mapped as expected */
|
||||
resp = qtest_qmp(qs, "{ 'execute': 'query-hotpluggable-cpus'}");
|
||||
g_assert(qdict_haskey(resp, "return"));
|
||||
cpus = qdict_get_qlist(resp, "return");
|
||||
g_assert(cpus);
|
||||
while ((e = qlist_pop(cpus))) {
|
||||
const QDict *cpu, *props;
|
||||
int64_t socket, node;
|
||||
|
||||
cpu = qobject_to(QDict, e);
|
||||
g_assert(qdict_haskey(cpu, "props"));
|
||||
props = qdict_get_qdict(cpu, "props");
|
||||
|
||||
g_assert(qdict_haskey(props, "node-id"));
|
||||
node = qdict_get_int(props, "node-id");
|
||||
g_assert(qdict_haskey(props, "socket-id"));
|
||||
socket = qdict_get_int(props, "socket-id");
|
||||
|
||||
if (socket == 0) {
|
||||
g_assert_cmpint(node, ==, 1);
|
||||
} else if (socket == 1) {
|
||||
g_assert_cmpint(node, ==, 0);
|
||||
} else {
|
||||
g_assert(false);
|
||||
}
|
||||
qobject_unref(e);
|
||||
}
|
||||
qobject_unref(resp);
|
||||
|
||||
qtest_quit(qs);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *args = NULL;
|
||||
|
@ -278,6 +338,7 @@ int main(int argc, char **argv)
|
|||
|
||||
if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64")) {
|
||||
qtest_add_data_func("/numa/pc/cpu/explicit", args, pc_numa_cpu);
|
||||
qtest_add_data_func("/numa/pc/dynamic/cpu", args, pc_dynamic_cpu_cfg);
|
||||
}
|
||||
|
||||
if (!strcmp(arch, "ppc64")) {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
tests/qapi-schema/allow-preconfig-test.json:2: 'allow-preconfig' of command 'allow-preconfig-test' should only use true value
|
|
@ -0,0 +1 @@
|
|||
1
|
|
@ -0,0 +1,2 @@
|
|||
# Check against allow-preconfig illegal value
|
||||
{ 'command': 'allow-preconfig-test', 'allow-preconfig': 'some-string' }
|
|
@ -28,9 +28,9 @@ object q_obj_cmd-arg
|
|||
member arg2: str optional=True
|
||||
member arg3: bool optional=False
|
||||
command cmd q_obj_cmd-arg -> Object
|
||||
gen=True success_response=True boxed=False oob=False
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
command cmd-boxed Object -> None
|
||||
gen=True success_response=True boxed=True oob=False
|
||||
gen=True success_response=True boxed=True oob=False preconfig=False
|
||||
doc freeform
|
||||
body=
|
||||
= Section
|
||||
|
|
|
@ -5,4 +5,4 @@ module ident-with-escape.json
|
|||
object q_obj_fooA-arg
|
||||
member bar1: str optional=False
|
||||
command fooA q_obj_fooA-arg -> None
|
||||
gen=True success_response=True boxed=False oob=False
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
|
|
|
@ -3,6 +3,6 @@ enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
|
|||
prefix QTYPE
|
||||
module indented-expr.json
|
||||
command eins None -> None
|
||||
gen=True success_response=True boxed=False oob=False
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
command zwei None -> None
|
||||
gen=True success_response=True boxed=False oob=False
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
|
|
|
@ -139,8 +139,8 @@
|
|||
{ 'command': 'boxed-struct', 'boxed': true, 'data': 'UserDefZero' }
|
||||
{ 'command': 'boxed-union', 'data': 'UserDefNativeListUnion', 'boxed': true }
|
||||
|
||||
# Smoke test on Out-Of-Band
|
||||
{ 'command': 'an-oob-command', 'allow-oob': true }
|
||||
# Smoke test on Out-Of-Band and allow-preconfig-test
|
||||
{ 'command': 'test-flags-command', 'allow-oob': true, 'allow-preconfig': true }
|
||||
|
||||
# For testing integer range flattening in opts-visitor. The following schema
|
||||
# corresponds to the option format:
|
||||
|
|
|
@ -16,7 +16,7 @@ object Empty1
|
|||
object Empty2
|
||||
base Empty1
|
||||
command user_def_cmd0 Empty2 -> Empty2
|
||||
gen=True success_response=True boxed=False oob=False
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
enum QEnumTwo ['value1', 'value2']
|
||||
prefix QENUM_TWO
|
||||
object UserDefOne
|
||||
|
@ -143,31 +143,31 @@ object UserDefNativeListUnion
|
|||
case sizes: q_obj_sizeList-wrapper
|
||||
case any: q_obj_anyList-wrapper
|
||||
command user_def_cmd None -> None
|
||||
gen=True success_response=True boxed=False oob=False
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
object q_obj_user_def_cmd1-arg
|
||||
member ud1a: UserDefOne optional=False
|
||||
command user_def_cmd1 q_obj_user_def_cmd1-arg -> None
|
||||
gen=True success_response=True boxed=False oob=False
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
object q_obj_user_def_cmd2-arg
|
||||
member ud1a: UserDefOne optional=False
|
||||
member ud1b: UserDefOne optional=True
|
||||
command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo
|
||||
gen=True success_response=True boxed=False oob=False
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
object q_obj_guest-get-time-arg
|
||||
member a: int optional=False
|
||||
member b: int optional=True
|
||||
command guest-get-time q_obj_guest-get-time-arg -> int
|
||||
gen=True success_response=True boxed=False oob=False
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
object q_obj_guest-sync-arg
|
||||
member arg: any optional=False
|
||||
command guest-sync q_obj_guest-sync-arg -> any
|
||||
gen=True success_response=True boxed=False oob=False
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
command boxed-struct UserDefZero -> None
|
||||
gen=True success_response=True boxed=True oob=False
|
||||
gen=True success_response=True boxed=True oob=False preconfig=False
|
||||
command boxed-union UserDefNativeListUnion -> None
|
||||
gen=True success_response=True boxed=True oob=False
|
||||
command an-oob-command None -> None
|
||||
gen=True success_response=True boxed=False oob=True
|
||||
gen=True success_response=True boxed=True oob=False preconfig=False
|
||||
command test-flags-command None -> None
|
||||
gen=True success_response=True boxed=False oob=True preconfig=True
|
||||
object UserDefOptions
|
||||
member i64: intList optional=True
|
||||
member u64: uint64List optional=True
|
||||
|
@ -231,4 +231,4 @@ object q_obj___org.qemu_x-command-arg
|
|||
member c: __org.qemu_x-Union2 optional=False
|
||||
member d: __org.qemu_x-Alt optional=False
|
||||
command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1
|
||||
gen=True success_response=True boxed=False oob=False
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
|
|
|
@ -41,12 +41,12 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
|
|||
print('alternate %s' % name)
|
||||
self._print_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):
|
||||
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 oob=%s' % \
|
||||
(gen, success_response, boxed, allow_oob))
|
||||
print(' gen=%s success_response=%s boxed=%s oob=%s preconfig=%s' % \
|
||||
(gen, success_response, boxed, allow_oob, allow_preconfig))
|
||||
|
||||
def visit_event(self, name, info, arg_type, boxed):
|
||||
print('event %s %s' % (name, arg_type and arg_type.name))
|
||||
|
|
|
@ -392,6 +392,45 @@ static void add_query_tests(QmpSchema *schema)
|
|||
}
|
||||
}
|
||||
|
||||
static void test_qmp_preconfig(void)
|
||||
{
|
||||
QDict *rsp, *ret;
|
||||
QTestState *qs = qtest_startf("%s --preconfig", common_args);
|
||||
|
||||
/* preconfig state */
|
||||
/* enabled commands, no error expected */
|
||||
g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-commands' }")));
|
||||
|
||||
/* forbidden commands, expected error */
|
||||
g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
|
||||
|
||||
/* check that query-status returns preconfig state */
|
||||
rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
|
||||
ret = qdict_get_qdict(rsp, "return");
|
||||
g_assert(ret);
|
||||
g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "preconfig");
|
||||
qobject_unref(rsp);
|
||||
|
||||
/* exit preconfig state */
|
||||
g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'exit-preconfig' }")));
|
||||
qtest_qmp_eventwait(qs, "RESUME");
|
||||
|
||||
/* check that query-status returns running state */
|
||||
rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
|
||||
ret = qdict_get_qdict(rsp, "return");
|
||||
g_assert(ret);
|
||||
g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "running");
|
||||
qobject_unref(rsp);
|
||||
|
||||
/* check that exit-preconfig returns error after exiting preconfig */
|
||||
g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'exit-preconfig' }")));
|
||||
|
||||
/* enabled commands, no error expected */
|
||||
g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
|
||||
|
||||
qtest_quit(qs);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QmpSchema schema;
|
||||
|
@ -403,6 +442,7 @@ int main(int argc, char *argv[])
|
|||
qtest_add_func("qmp/oob", test_qmp_oob);
|
||||
qmp_schema_init(&schema);
|
||||
add_query_tests(&schema);
|
||||
qtest_add_func("qmp/preconfig", test_qmp_preconfig);
|
||||
|
||||
ret = g_test_run();
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ void qmp_user_def_cmd(Error **errp)
|
|||
{
|
||||
}
|
||||
|
||||
void qmp_an_oob_command(Error **errp)
|
||||
void qmp_test_flags_command(Error **errp)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
35
vl.c
35
vl.c
|
@ -594,7 +594,7 @@ static int default_driver_check(void *opaque, QemuOpts *opts, Error **errp)
|
|||
/***********************************************************/
|
||||
/* QEMU state */
|
||||
|
||||
static RunState current_run_state = RUN_STATE_PRELAUNCH;
|
||||
static RunState current_run_state = RUN_STATE_PRECONFIG;
|
||||
|
||||
/* We use RUN_STATE__MAX but any invalid value will do */
|
||||
static RunState vmstop_requested = RUN_STATE__MAX;
|
||||
|
@ -607,6 +607,13 @@ typedef struct {
|
|||
|
||||
static const RunStateTransition runstate_transitions_def[] = {
|
||||
/* from -> to */
|
||||
{ RUN_STATE_PRECONFIG, RUN_STATE_PRELAUNCH },
|
||||
/* Early switch to inmigrate state to allow -incoming CLI option work
|
||||
* as it used to. TODO: delay actual switching to inmigrate state to
|
||||
* the point after machine is built and remove this hack.
|
||||
*/
|
||||
{ RUN_STATE_PRECONFIG, RUN_STATE_INMIGRATE },
|
||||
|
||||
{ RUN_STATE_DEBUG, RUN_STATE_RUNNING },
|
||||
{ RUN_STATE_DEBUG, RUN_STATE_FINISH_MIGRATE },
|
||||
{ RUN_STATE_DEBUG, RUN_STATE_PRELAUNCH },
|
||||
|
@ -1630,6 +1637,7 @@ static pid_t shutdown_pid;
|
|||
static int powerdown_requested;
|
||||
static int debug_requested;
|
||||
static int suspend_requested;
|
||||
static bool preconfig_exit_requested = true;
|
||||
static WakeupReason wakeup_reason;
|
||||
static NotifierList powerdown_notifiers =
|
||||
NOTIFIER_LIST_INITIALIZER(powerdown_notifiers);
|
||||
|
@ -1714,6 +1722,11 @@ static int qemu_debug_requested(void)
|
|||
return r;
|
||||
}
|
||||
|
||||
void qemu_exit_preconfig_request(void)
|
||||
{
|
||||
preconfig_exit_requested = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the VM. Issue an event unless @reason is SHUTDOWN_CAUSE_NONE.
|
||||
*/
|
||||
|
@ -1887,6 +1900,13 @@ static bool main_loop_should_exit(void)
|
|||
RunState r;
|
||||
ShutdownCause request;
|
||||
|
||||
if (preconfig_exit_requested) {
|
||||
if (runstate_check(RUN_STATE_PRECONFIG)) {
|
||||
runstate_set(RUN_STATE_PRELAUNCH);
|
||||
}
|
||||
preconfig_exit_requested = false;
|
||||
return true;
|
||||
}
|
||||
if (qemu_debug_requested()) {
|
||||
vm_stop(RUN_STATE_DEBUG);
|
||||
}
|
||||
|
@ -3667,6 +3687,9 @@ int main(int argc, char **argv, char **envp)
|
|||
exit(1);
|
||||
}
|
||||
break;
|
||||
case QEMU_OPTION_preconfig:
|
||||
preconfig_exit_requested = false;
|
||||
break;
|
||||
case QEMU_OPTION_enable_kvm:
|
||||
olist = qemu_find_opts("machine");
|
||||
qemu_opts_parse_noisily(olist, "accel=kvm", false);
|
||||
|
@ -4031,6 +4054,12 @@ int main(int argc, char **argv, char **envp)
|
|||
|
||||
replay_configure(icount_opts);
|
||||
|
||||
if (incoming && !preconfig_exit_requested) {
|
||||
error_report("'preconfig' and 'incoming' options are "
|
||||
"mutually exclusive");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
machine_class = select_machine();
|
||||
|
||||
set_memory_options(&ram_slots, &maxram_size, machine_class);
|
||||
|
@ -4548,6 +4577,10 @@ int main(int argc, char **argv, char **envp)
|
|||
}
|
||||
parse_numa_opts(current_machine);
|
||||
|
||||
/* do monitor/qmp handling at preconfig state if requested */
|
||||
main_loop();
|
||||
|
||||
/* from here on runstate is RUN_STATE_PRELAUNCH */
|
||||
machine_run_board_init(current_machine);
|
||||
|
||||
realtime_init();
|
||||
|
|
Loading…
Reference in New Issue