QMP quit, host signals and UI shutdown requests force QEMU to exit by setting shutdown_action to SHUTDOWN_ACTION_POWEROFF.
This can race with guest shutdown processing. With -no-shutdown, consider the following sequence: 1. Management sends system_powerdown, then sends SIGTERM after waiting for the guest to shut down. 2. QEMU starts processing a guest shutdown request. 3. SIGTERM arrives after qemu_kill_report(), while QEMU is sending the guest SHUTDOWN event. 4. The signal handler changes shutdown_action to POWEROFF, so QEMU exits instead of pausing. Management receives SHUTDOWN with guest=true, but QEMU exits despite -no-shutdown, without reporting a host SHUTDOWN event or printing the signal diagnostic. Store forced and regular shutdown requests separately, and decide whether to exit based on the request being processed. Leave shutdown_action under user control. A forced request arriving while a regular request is being processed remains pending for the next main loop iteration. Keep qemu_shutdown_requested() checking both kinds of requests for its Xen caller. There is no need to clear shutdown_force_requested with qatomic_xchg(): processing a forced shutdown request always exits the main loop. Signed-off-by: Vladimir Sementsov-Ogievskiy <[email protected]> --- monitor/qmp-cmds.c | 1 - system/runstate.c | 24 ++++++++++++++++-------- ui/cocoa.m | 1 - ui/sdl2.c | 2 -- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 7525a88e049..6d0ba75ff16 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -44,7 +44,6 @@ NameInfo *qmp_query_name(Error **errp) void qmp_quit(Error **errp) { - shutdown_action = SHUTDOWN_ACTION_POWEROFF; qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_QMP_QUIT); } diff --git a/system/runstate.c b/system/runstate.c index 2b28e2a30e2..5d10ff0df99 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -564,9 +564,9 @@ int vm_stop_force_state(RunState state) static ShutdownCause reset_requested; static ShutdownCause shutdown_requested; +static ShutdownCause shutdown_force_requested; static int shutdown_exit_code = EXIT_SUCCESS; static int shutdown_signal; -static bool force_shutdown; static pid_t shutdown_pid; static int powerdown_requested; static int debug_requested; @@ -584,12 +584,12 @@ static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE); bool qemu_shutdown_requested(void) { - return shutdown_requested; + return shutdown_requested || shutdown_force_requested; } bool qemu_force_shutdown_requested(void) { - return force_shutdown; + return shutdown_force_requested; } ShutdownCause qemu_reset_requested_get(void) @@ -972,11 +972,12 @@ bool qemu_wakeup_suspend_enabled(void) */ static void qemu_system_shutdown_request_safe(ShutdownCause reason) { - shutdown_requested = reason; if (reason == SHUTDOWN_CAUSE_HOST_QMP_QUIT || reason == SHUTDOWN_CAUSE_HOST_SIGNAL || reason == SHUTDOWN_CAUSE_HOST_UI) { - force_shutdown = true; + shutdown_force_requested = reason; + } else { + shutdown_requested = reason; } qemu_notify_event(); } @@ -992,7 +993,6 @@ void qemu_system_killed(int signal, pid_t pid) { shutdown_signal = signal; shutdown_pid = pid; - shutdown_action = SHUTDOWN_ACTION_POWEROFF; qemu_system_shutdown_request_safe(SHUTDOWN_CAUSE_HOST_SIGNAL); } @@ -1042,6 +1042,7 @@ static bool main_loop_should_exit(int *status) { RunState r; ShutdownCause request; + bool force = false; if (qemu_debug_requested()) { vm_stop(RUN_STATE_DEBUG); @@ -1049,11 +1050,18 @@ static bool main_loop_should_exit(int *status) if (qemu_suspend_requested()) { qemu_system_suspend(); } - request = qatomic_xchg(&shutdown_requested, SHUTDOWN_CAUSE_NONE); + + if (shutdown_force_requested) { + force = true; + request = shutdown_force_requested; + } else { + request = qatomic_xchg(&shutdown_requested, SHUTDOWN_CAUSE_NONE); + } + if (request) { qemu_kill_report(); qemu_system_shutdown(request); - if (shutdown_action == SHUTDOWN_ACTION_PAUSE) { + if (!force && shutdown_action == SHUTDOWN_ACTION_PAUSE) { vm_stop(RUN_STATE_SHUTDOWN); } else { if (shutdown_exit_code != EXIT_SUCCESS) { diff --git a/ui/cocoa.m b/ui/cocoa.m index 3751be37922..5447fb637ad 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -1221,7 +1221,6 @@ - (void)applicationWillTerminate:(NSNotification *)aNotification COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n"); with_bql(^{ - shutdown_action = SHUTDOWN_ACTION_POWEROFF; qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI); }); diff --git a/ui/sdl2.c b/ui/sdl2.c index 1c97d23a47c..d647905a379 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -645,7 +645,6 @@ static void handle_windowevent(SDL_Event *ev) allow_close = false; } if (allow_close) { - shutdown_action = SHUTDOWN_ACTION_POWEROFF; qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI); } } else { @@ -692,7 +691,6 @@ void sdl2_poll_events(struct sdl2_console *scon) allow_close = false; } if (allow_close) { - shutdown_action = SHUTDOWN_ACTION_POWEROFF; qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI); } break; -- 2.43.0
