reset: allow registering handlers that aren't called by snapshot loading

Snapshot loading only expects to call deterministic handlers, not
non-deterministic ones. So introduce a way of registering handlers that
won't be called when reseting for snapshots.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Message-id: 20221025004327.568476-2-Jason@zx2c4.com
[PMM: updated json doc comment with Markus' text; fixed
 checkpatch style nit]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Jason A. Donenfeld 2022-10-25 02:43:17 +02:00 committed by Peter Maydell
parent c8d6c286ab
commit 7966d70f6f
15 changed files with 54 additions and 27 deletions

View File

@ -1356,12 +1356,12 @@ static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data)
aspeed_soc_num_cpus(amc->soc_name); aspeed_soc_num_cpus(amc->soc_name);
} }
static void fby35_reset(MachineState *state) static void fby35_reset(MachineState *state, ShutdownCause reason)
{ {
AspeedMachineState *bmc = ASPEED_MACHINE(state); AspeedMachineState *bmc = ASPEED_MACHINE(state);
AspeedGPIOState *gpio = &bmc->soc.gpio; AspeedGPIOState *gpio = &bmc->soc.gpio;
qemu_devices_reset(); qemu_devices_reset(reason);
/* Board ID: 7 (Class-1, 4 slots) */ /* Board ID: 7 (Class-1, 4 slots) */
object_property_set_bool(OBJECT(gpio), "gpioV4", true, &error_fatal); object_property_set_bool(OBJECT(gpio), "gpioV4", true, &error_fatal);

View File

@ -1239,7 +1239,7 @@ static void mps2_set_remap(Object *obj, const char *value, Error **errp)
} }
} }
static void mps2_machine_reset(MachineState *machine) static void mps2_machine_reset(MachineState *machine, ShutdownCause reason)
{ {
MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
@ -1249,7 +1249,7 @@ static void mps2_machine_reset(MachineState *machine)
* reset see the correct mapping. * reset see the correct mapping.
*/ */
remap_memory(mms, mms->remap); remap_memory(mms, mms->remap);
qemu_devices_reset(); qemu_devices_reset(reason);
} }
static void mps2tz_class_init(ObjectClass *oc, void *data) static void mps2tz_class_init(ObjectClass *oc, void *data)

View File

@ -33,6 +33,7 @@ typedef struct QEMUResetEntry {
QTAILQ_ENTRY(QEMUResetEntry) entry; QTAILQ_ENTRY(QEMUResetEntry) entry;
QEMUResetHandler *func; QEMUResetHandler *func;
void *opaque; void *opaque;
bool skip_on_snapshot_load;
} QEMUResetEntry; } QEMUResetEntry;
static QTAILQ_HEAD(, QEMUResetEntry) reset_handlers = static QTAILQ_HEAD(, QEMUResetEntry) reset_handlers =
@ -47,6 +48,16 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque)
QTAILQ_INSERT_TAIL(&reset_handlers, re, entry); QTAILQ_INSERT_TAIL(&reset_handlers, re, entry);
} }
void qemu_register_reset_nosnapshotload(QEMUResetHandler *func, void *opaque)
{
QEMUResetEntry *re = g_new0(QEMUResetEntry, 1);
re->func = func;
re->opaque = opaque;
re->skip_on_snapshot_load = true;
QTAILQ_INSERT_TAIL(&reset_handlers, re, entry);
}
void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
{ {
QEMUResetEntry *re; QEMUResetEntry *re;
@ -60,12 +71,16 @@ void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
} }
} }
void qemu_devices_reset(void) void qemu_devices_reset(ShutdownCause reason)
{ {
QEMUResetEntry *re, *nre; QEMUResetEntry *re, *nre;
/* reset all devices */ /* reset all devices */
QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) { QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) {
if (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD &&
re->skip_on_snapshot_load) {
continue;
}
re->func(re->opaque); re->func(re->opaque);
} }
} }

View File

@ -411,12 +411,12 @@ static void machine_hppa_init(MachineState *machine)
cpu[0]->env.gr[19] = FW_CFG_IO_BASE; cpu[0]->env.gr[19] = FW_CFG_IO_BASE;
} }
static void hppa_machine_reset(MachineState *ms) static void hppa_machine_reset(MachineState *ms, ShutdownCause reason)
{ {
unsigned int smp_cpus = ms->smp.cpus; unsigned int smp_cpus = ms->smp.cpus;
int i; int i;
qemu_devices_reset(); qemu_devices_reset(reason);
/* Start all CPUs at the firmware entry point. /* Start all CPUs at the firmware entry point.
* Monarch CPU will initialize firmware, secondary CPUs * Monarch CPU will initialize firmware, secondary CPUs

View File

@ -467,7 +467,7 @@ static void microvm_machine_state_init(MachineState *machine)
microvm_devices_init(mms); microvm_devices_init(mms);
} }
static void microvm_machine_reset(MachineState *machine) static void microvm_machine_reset(MachineState *machine, ShutdownCause reason)
{ {
MicrovmMachineState *mms = MICROVM_MACHINE(machine); MicrovmMachineState *mms = MICROVM_MACHINE(machine);
CPUState *cs; CPUState *cs;
@ -480,7 +480,7 @@ static void microvm_machine_reset(MachineState *machine)
mms->kernel_cmdline_fixed = true; mms->kernel_cmdline_fixed = true;
} }
qemu_devices_reset(); qemu_devices_reset(reason);
CPU_FOREACH(cs) { CPU_FOREACH(cs) {
cpu = X86_CPU(cs); cpu = X86_CPU(cs);

View File

@ -1847,12 +1847,12 @@ static void pc_machine_initfn(Object *obj)
cxl_machine_init(obj, &pcms->cxl_devices_state); cxl_machine_init(obj, &pcms->cxl_devices_state);
} }
static void pc_machine_reset(MachineState *machine) static void pc_machine_reset(MachineState *machine, ShutdownCause reason)
{ {
CPUState *cs; CPUState *cs;
X86CPU *cpu; X86CPU *cpu;
qemu_devices_reset(); qemu_devices_reset(reason);
/* Reset APIC after devices have been reset to cancel /* Reset APIC after devices have been reset to cancel
* any changes that qemu_devices_reset() might have done. * any changes that qemu_devices_reset() might have done.
@ -1867,7 +1867,7 @@ static void pc_machine_reset(MachineState *machine)
static void pc_machine_wakeup(MachineState *machine) static void pc_machine_wakeup(MachineState *machine)
{ {
cpu_synchronize_all_states(); cpu_synchronize_all_states();
pc_machine_reset(machine); pc_machine_reset(machine, SHUTDOWN_CAUSE_NONE);
cpu_synchronize_all_post_reset(); cpu_synchronize_all_post_reset();
} }

View File

@ -248,14 +248,14 @@ static void pegasos2_pci_config_write(Pegasos2MachineState *pm, int bus,
pegasos2_mv_reg_write(pm, pcicfg + 4, len, val); pegasos2_mv_reg_write(pm, pcicfg + 4, len, val);
} }
static void pegasos2_machine_reset(MachineState *machine) static void pegasos2_machine_reset(MachineState *machine, ShutdownCause reason)
{ {
Pegasos2MachineState *pm = PEGASOS2_MACHINE(machine); Pegasos2MachineState *pm = PEGASOS2_MACHINE(machine);
void *fdt; void *fdt;
uint64_t d[2]; uint64_t d[2];
int sz; int sz;
qemu_devices_reset(); qemu_devices_reset(reason);
if (!pm->vof) { if (!pm->vof) {
return; /* Firmware should set up machine so nothing to do */ return; /* Firmware should set up machine so nothing to do */
} }

View File

@ -643,13 +643,13 @@ static void pnv_powerdown_notify(Notifier *n, void *opaque)
} }
} }
static void pnv_reset(MachineState *machine) static void pnv_reset(MachineState *machine, ShutdownCause reason)
{ {
PnvMachineState *pnv = PNV_MACHINE(machine); PnvMachineState *pnv = PNV_MACHINE(machine);
IPMIBmc *bmc; IPMIBmc *bmc;
void *fdt; void *fdt;
qemu_devices_reset(); qemu_devices_reset(reason);
/* /*
* The machine should provide by default an internal BMC simulator. * The machine should provide by default an internal BMC simulator.

View File

@ -1623,7 +1623,7 @@ void spapr_check_mmu_mode(bool guest_radix)
} }
} }
static void spapr_machine_reset(MachineState *machine) static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
{ {
SpaprMachineState *spapr = SPAPR_MACHINE(machine); SpaprMachineState *spapr = SPAPR_MACHINE(machine);
PowerPCCPU *first_ppc_cpu; PowerPCCPU *first_ppc_cpu;
@ -1649,7 +1649,7 @@ static void spapr_machine_reset(MachineState *machine)
spapr_setup_hpt(spapr); spapr_setup_hpt(spapr);
} }
qemu_devices_reset(); qemu_devices_reset(reason);
spapr_ovec_cleanup(spapr->ov5_cas); spapr_ovec_cleanup(spapr->ov5_cas);
spapr->ov5_cas = spapr_ovec_new(); spapr->ov5_cas = spapr_ovec_new();

View File

@ -411,7 +411,7 @@ static void s390_pv_prepare_reset(S390CcwMachineState *ms)
s390_pv_prep_reset(); s390_pv_prep_reset();
} }
static void s390_machine_reset(MachineState *machine) static void s390_machine_reset(MachineState *machine, ShutdownCause reason)
{ {
S390CcwMachineState *ms = S390_CCW_MACHINE(machine); S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
enum s390_reset reset_type; enum s390_reset reset_type;
@ -433,7 +433,7 @@ static void s390_machine_reset(MachineState *machine)
s390_machine_unprotect(ms); s390_machine_unprotect(ms);
} }
qemu_devices_reset(); qemu_devices_reset(reason);
s390_crypto_reset(); s390_crypto_reset();
/* configure and start the ipl CPU only */ /* configure and start the ipl CPU only */

View File

@ -231,7 +231,7 @@ struct MachineClass {
const char *deprecation_reason; const char *deprecation_reason;
void (*init)(MachineState *state); void (*init)(MachineState *state);
void (*reset)(MachineState *state); void (*reset)(MachineState *state, ShutdownCause reason);
void (*wakeup)(MachineState *state); void (*wakeup)(MachineState *state);
int (*kvm_type)(MachineState *machine, const char *arg); int (*kvm_type)(MachineState *machine, const char *arg);

View File

@ -1,10 +1,13 @@
#ifndef QEMU_SYSEMU_RESET_H #ifndef QEMU_SYSEMU_RESET_H
#define QEMU_SYSEMU_RESET_H #define QEMU_SYSEMU_RESET_H
#include "qapi/qapi-events-run-state.h"
typedef void QEMUResetHandler(void *opaque); typedef void QEMUResetHandler(void *opaque);
void qemu_register_reset(QEMUResetHandler *func, void *opaque); void qemu_register_reset(QEMUResetHandler *func, void *opaque);
void qemu_register_reset_nosnapshotload(QEMUResetHandler *func, void *opaque);
void qemu_unregister_reset(QEMUResetHandler *func, void *opaque); void qemu_unregister_reset(QEMUResetHandler *func, void *opaque);
void qemu_devices_reset(void); void qemu_devices_reset(ShutdownCause reason);
#endif #endif

View File

@ -3058,7 +3058,7 @@ bool load_snapshot(const char *name, const char *vmstate,
goto err_drain; goto err_drain;
} }
qemu_system_reset(SHUTDOWN_CAUSE_NONE); qemu_system_reset(SHUTDOWN_CAUSE_SNAPSHOT_LOAD);
mis->from_src_file = f; mis->from_src_file = f;
if (!yank_register_instance(MIGRATION_YANK_INSTANCE, errp)) { if (!yank_register_instance(MIGRATION_YANK_INSTANCE, errp)) {

View File

@ -86,12 +86,16 @@
# ignores --no-reboot. This is useful for sanitizing # ignores --no-reboot. This is useful for sanitizing
# hypercalls on s390 that are used during kexec/kdump/boot # hypercalls on s390 that are used during kexec/kdump/boot
# #
# @snapshot-load: A snapshot is being loaded by the record & replay
# subsystem. This value is used only within QEMU. It
# doesn't occur in QMP. (since 7.2)
#
## ##
{ 'enum': 'ShutdownCause', { 'enum': 'ShutdownCause',
# Beware, shutdown_caused_by_guest() depends on enumeration order # Beware, shutdown_caused_by_guest() depends on enumeration order
'data': [ 'none', 'host-error', 'host-qmp-quit', 'host-qmp-system-reset', 'data': [ 'none', 'host-error', 'host-qmp-quit', 'host-qmp-system-reset',
'host-signal', 'host-ui', 'guest-shutdown', 'guest-reset', 'host-signal', 'host-ui', 'guest-shutdown', 'guest-reset',
'guest-panic', 'subsystem-reset'] } 'guest-panic', 'subsystem-reset', 'snapshot-load'] }
## ##
# @StatusInfo: # @StatusInfo:

View File

@ -441,11 +441,16 @@ void qemu_system_reset(ShutdownCause reason)
cpu_synchronize_all_states(); cpu_synchronize_all_states();
if (mc && mc->reset) { if (mc && mc->reset) {
mc->reset(current_machine); mc->reset(current_machine, reason);
} else { } else {
qemu_devices_reset(); qemu_devices_reset(reason);
} }
if (reason && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) { switch (reason) {
case SHUTDOWN_CAUSE_NONE:
case SHUTDOWN_CAUSE_SUBSYSTEM_RESET:
case SHUTDOWN_CAUSE_SNAPSHOT_LOAD:
break;
default:
qapi_event_send_reset(shutdown_caused_by_guest(reason), reason); qapi_event_send_reset(shutdown_caused_by_guest(reason), reason);
} }
cpu_synchronize_all_post_reset(); cpu_synchronize_all_post_reset();