diff mbox series

[v4,01/11] reset: allow registering handlers that aren't called by snapshot loading

Message ID 20221025004327.568476-2-Jason@zx2c4.com
State New
Headers show
Series rerandomize RNG seeds on reboot and handle record&replay | expand

Commit Message

Jason A. Donenfeld Oct. 25, 2022, 12:43 a.m. UTC
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>
---
 hw/arm/aspeed.c            |  4 ++--
 hw/arm/mps2-tz.c           |  4 ++--
 hw/core/reset.c            | 15 ++++++++++++++-
 hw/hppa/machine.c          |  4 ++--
 hw/i386/microvm.c          |  4 ++--
 hw/i386/pc.c               |  6 +++---
 hw/ppc/pegasos2.c          |  4 ++--
 hw/ppc/pnv.c               |  4 ++--
 hw/ppc/spapr.c             |  4 ++--
 hw/s390x/s390-virtio-ccw.c |  4 ++--
 include/hw/boards.h        |  2 +-
 include/sysemu/reset.h     |  5 ++++-
 migration/savevm.c         |  2 +-
 qapi/run-state.json        |  5 ++++-
 softmmu/runstate.c         | 11 ++++++++---
 15 files changed, 51 insertions(+), 27 deletions(-)

Comments

Markus Armbruster Oct. 25, 2022, 6:11 a.m. UTC | #1
"Jason A. Donenfeld" <Jason@zx2c4.com> writes:

> 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>

[...]

> diff --git a/qapi/run-state.json b/qapi/run-state.json
> index 49989d30e6..e44c0de914 100644
> --- a/qapi/run-state.json
> +++ b/qapi/run-state.json
> @@ -86,12 +86,15 @@
>  #                   ignores --no-reboot. This is useful for sanitizing
>  #                   hypercalls on s390 that are used during kexec/kdump/boot
>  #
> +# @snapshot-load: A snapshot is being loaded by the record & replay
> +#                 subsystem; internal value (since 7.2)
> +#

If "internal value" was an established way to mark parts that aren't
visible externally, this would do.  Since it isn't, it's too terse.
Suggest something like "This value is used only within QEMU.  It doesn't
occur in QMP."

>  ##
>  { 'enum': 'ShutdownCause',
>    # Beware, shutdown_caused_by_guest() depends on enumeration order
>    'data': [ 'none', 'host-error', 'host-qmp-quit', 'host-qmp-system-reset',
>              'host-signal', 'host-ui', 'guest-shutdown', 'guest-reset',
> -            'guest-panic', 'subsystem-reset'] }
> +            'guest-panic', 'subsystem-reset', 'snapshot-load'] }
>  
>  ##
>  # @StatusInfo:

[...]
Jason A. Donenfeld Oct. 25, 2022, 12:09 p.m. UTC | #2
Hi Markus,

On Tue, Oct 25, 2022 at 08:11:51AM +0200, Markus Armbruster wrote:
> > diff --git a/qapi/run-state.json b/qapi/run-state.json
> > index 49989d30e6..e44c0de914 100644
> > --- a/qapi/run-state.json
> > +++ b/qapi/run-state.json
> > @@ -86,12 +86,15 @@
> >  #                   ignores --no-reboot. This is useful for sanitizing
> >  #                   hypercalls on s390 that are used during kexec/kdump/boot
> >  #
> > +# @snapshot-load: A snapshot is being loaded by the record & replay
> > +#                 subsystem; internal value (since 7.2)
> > +#
> 
> If "internal value" was an established way to mark parts that aren't
> visible externally, this would do.  Since it isn't, it's too terse.
> Suggest something like "This value is used only within QEMU.  It doesn't
> occur in QMP."

Thanks for the precise text. I can do that for a v5, or, Peter - do you
want to just fold that in upon committing these patches?

Jason
Peter Maydell Oct. 25, 2022, 12:26 p.m. UTC | #3
On Tue, 25 Oct 2022 at 13:09, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>
> Hi Markus,
>
> On Tue, Oct 25, 2022 at 08:11:51AM +0200, Markus Armbruster wrote:
> > > diff --git a/qapi/run-state.json b/qapi/run-state.json
> > > index 49989d30e6..e44c0de914 100644
> > > --- a/qapi/run-state.json
> > > +++ b/qapi/run-state.json
> > > @@ -86,12 +86,15 @@
> > >  #                   ignores --no-reboot. This is useful for sanitizing
> > >  #                   hypercalls on s390 that are used during kexec/kdump/boot
> > >  #
> > > +# @snapshot-load: A snapshot is being loaded by the record & replay
> > > +#                 subsystem; internal value (since 7.2)
> > > +#
> >
> > If "internal value" was an established way to mark parts that aren't
> > visible externally, this would do.  Since it isn't, it's too terse.
> > Suggest something like "This value is used only within QEMU.  It doesn't
> > occur in QMP."
>
> Thanks for the precise text. I can do that for a v5, or, Peter - do you
> want to just fold that in upon committing these patches?

If there's no other issues with the series I'll just fold that change in.

-- PMM
Jason A. Donenfeld Oct. 25, 2022, 12:32 p.m. UTC | #4
On Tue, Oct 25, 2022 at 2:26 PM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Tue, 25 Oct 2022 at 13:09, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> >
> > Hi Markus,
> >
> > On Tue, Oct 25, 2022 at 08:11:51AM +0200, Markus Armbruster wrote:
> > > > diff --git a/qapi/run-state.json b/qapi/run-state.json
> > > > index 49989d30e6..e44c0de914 100644
> > > > --- a/qapi/run-state.json
> > > > +++ b/qapi/run-state.json
> > > > @@ -86,12 +86,15 @@
> > > >  #                   ignores --no-reboot. This is useful for sanitizing
> > > >  #                   hypercalls on s390 that are used during kexec/kdump/boot
> > > >  #
> > > > +# @snapshot-load: A snapshot is being loaded by the record & replay
> > > > +#                 subsystem; internal value (since 7.2)
> > > > +#
> > >
> > > If "internal value" was an established way to mark parts that aren't
> > > visible externally, this would do.  Since it isn't, it's too terse.
> > > Suggest something like "This value is used only within QEMU.  It doesn't
> > > occur in QMP."
> >
> > Thanks for the precise text. I can do that for a v5, or, Peter - do you
> > want to just fold that in upon committing these patches?
>
> If there's no other issues with the series I'll just fold that change in.

Great, okay. Last time when we found this original snapshot reset
issue, it surfaced because you put this somewhere that the CI ran on.
It might not be a bad idea to give this another whirl in the same CI
there.

Jason
Peter Maydell Oct. 25, 2022, 12:34 p.m. UTC | #5
On Tue, 25 Oct 2022 at 13:33, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>
> On Tue, Oct 25, 2022 at 2:26 PM Peter Maydell <peter.maydell@linaro.org> wrote:
> >
> > On Tue, 25 Oct 2022 at 13:09, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> > >
> > > Hi Markus,
> > >
> > > On Tue, Oct 25, 2022 at 08:11:51AM +0200, Markus Armbruster wrote:
> > > > > diff --git a/qapi/run-state.json b/qapi/run-state.json
> > > > > index 49989d30e6..e44c0de914 100644
> > > > > --- a/qapi/run-state.json
> > > > > +++ b/qapi/run-state.json
> > > > > @@ -86,12 +86,15 @@
> > > > >  #                   ignores --no-reboot. This is useful for sanitizing
> > > > >  #                   hypercalls on s390 that are used during kexec/kdump/boot
> > > > >  #
> > > > > +# @snapshot-load: A snapshot is being loaded by the record & replay
> > > > > +#                 subsystem; internal value (since 7.2)
> > > > > +#
> > > >
> > > > If "internal value" was an established way to mark parts that aren't
> > > > visible externally, this would do.  Since it isn't, it's too terse.
> > > > Suggest something like "This value is used only within QEMU.  It doesn't
> > > > occur in QMP."
> > >
> > > Thanks for the precise text. I can do that for a v5, or, Peter - do you
> > > want to just fold that in upon committing these patches?
> >
> > If there's no other issues with the series I'll just fold that change in.
>
> Great, okay. Last time when we found this original snapshot reset
> issue, it surfaced because you put this somewhere that the CI ran on.

No, I was just running "make check-avocado" locally.

thanks
-- PMM
Jason A. Donenfeld Oct. 25, 2022, 12:42 p.m. UTC | #6
On Tue, Oct 25, 2022 at 2:34 PM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Tue, 25 Oct 2022 at 13:33, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> >
> > On Tue, Oct 25, 2022 at 2:26 PM Peter Maydell <peter.maydell@linaro.org> wrote:
> > >
> > > On Tue, 25 Oct 2022 at 13:09, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> > > >
> > > > Hi Markus,
> > > >
> > > > On Tue, Oct 25, 2022 at 08:11:51AM +0200, Markus Armbruster wrote:
> > > > > > diff --git a/qapi/run-state.json b/qapi/run-state.json
> > > > > > index 49989d30e6..e44c0de914 100644
> > > > > > --- a/qapi/run-state.json
> > > > > > +++ b/qapi/run-state.json
> > > > > > @@ -86,12 +86,15 @@
> > > > > >  #                   ignores --no-reboot. This is useful for sanitizing
> > > > > >  #                   hypercalls on s390 that are used during kexec/kdump/boot
> > > > > >  #
> > > > > > +# @snapshot-load: A snapshot is being loaded by the record & replay
> > > > > > +#                 subsystem; internal value (since 7.2)
> > > > > > +#
> > > > >
> > > > > If "internal value" was an established way to mark parts that aren't
> > > > > visible externally, this would do.  Since it isn't, it's too terse.
> > > > > Suggest something like "This value is used only within QEMU.  It doesn't
> > > > > occur in QMP."
> > > >
> > > > Thanks for the precise text. I can do that for a v5, or, Peter - do you
> > > > want to just fold that in upon committing these patches?
> > >
> > > If there's no other issues with the series I'll just fold that change in.
> >
> > Great, okay. Last time when we found this original snapshot reset
> > issue, it surfaced because you put this somewhere that the CI ran on.
>
> No, I was just running "make check-avocado" locally.

Oh, okay. I'll try out a full `make check` locally then just to be sure.

Jason
Jason A. Donenfeld Oct. 25, 2022, 12:50 p.m. UTC | #7
On Tue, Oct 25, 2022 at 2:42 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>
> On Tue, Oct 25, 2022 at 2:34 PM Peter Maydell <peter.maydell@linaro.org> wrote:
> >
> > On Tue, 25 Oct 2022 at 13:33, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> > >
> > > On Tue, Oct 25, 2022 at 2:26 PM Peter Maydell <peter.maydell@linaro.org> wrote:
> > > >
> > > > On Tue, 25 Oct 2022 at 13:09, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> > > > >
> > > > > Hi Markus,
> > > > >
> > > > > On Tue, Oct 25, 2022 at 08:11:51AM +0200, Markus Armbruster wrote:
> > > > > > > diff --git a/qapi/run-state.json b/qapi/run-state.json
> > > > > > > index 49989d30e6..e44c0de914 100644
> > > > > > > --- a/qapi/run-state.json
> > > > > > > +++ b/qapi/run-state.json
> > > > > > > @@ -86,12 +86,15 @@
> > > > > > >  #                   ignores --no-reboot. This is useful for sanitizing
> > > > > > >  #                   hypercalls on s390 that are used during kexec/kdump/boot
> > > > > > >  #
> > > > > > > +# @snapshot-load: A snapshot is being loaded by the record & replay
> > > > > > > +#                 subsystem; internal value (since 7.2)
> > > > > > > +#
> > > > > >
> > > > > > If "internal value" was an established way to mark parts that aren't
> > > > > > visible externally, this would do.  Since it isn't, it's too terse.
> > > > > > Suggest something like "This value is used only within QEMU.  It doesn't
> > > > > > occur in QMP."
> > > > >
> > > > > Thanks for the precise text. I can do that for a v5, or, Peter - do you
> > > > > want to just fold that in upon committing these patches?
> > > >
> > > > If there's no other issues with the series I'll just fold that change in.
> > >
> > > Great, okay. Last time when we found this original snapshot reset
> > > issue, it surfaced because you put this somewhere that the CI ran on.
> >
> > No, I was just running "make check-avocado" locally.
>
> Oh, okay. I'll try out a full `make check` locally then just to be sure.

Ok:                 559
Expected Fail:      0
Fail:               0
Unexpected Pass:    0
Skipped:            66
Timeout:            0

Full log written to /home/zx2c4/qemu/build/meson-logs/testlog.txt
make[1]: Leaving directory '/home/zx2c4/qemu/build'

Not sure what the 66 skipped ones are all about, but at least I saw it
doing the migration test, so that's good. Full log attached.

Jason
Peter Maydell Oct. 25, 2022, 1:54 p.m. UTC | #8
On Tue, 25 Oct 2022 at 13:50, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>
> On Tue, Oct 25, 2022 at 2:42 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> >
> > On Tue, Oct 25, 2022 at 2:34 PM Peter Maydell <peter.maydell@linaro.org> wrote:
> > > No, I was just running "make check-avocado" locally.
> >
> > Oh, okay. I'll try out a full `make check` locally then just to be sure.

"make check" doesn't run the "make check-avocado" tests (because
they take a lot longer than most developers want for a simple
smoke test, and do things like downloading guest images for tests.)

thanks
-- PMM
Jason A. Donenfeld Oct. 25, 2022, 1:58 p.m. UTC | #9
On Tue, Oct 25, 2022 at 02:54:01PM +0100, Peter Maydell wrote:
> On Tue, 25 Oct 2022 at 13:50, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> >
> > On Tue, Oct 25, 2022 at 2:42 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> > >
> > > On Tue, Oct 25, 2022 at 2:34 PM Peter Maydell <peter.maydell@linaro.org> wrote:
> > > > No, I was just running "make check-avocado" locally.
> > >
> > > Oh, okay. I'll try out a full `make check` locally then just to be sure.
> 
> "make check" doesn't run the "make check-avocado" tests (because
> they take a lot longer than most developers want for a simple
> smoke test, and do things like downloading guest images for tests.)

Ah, okay, running.

Jason
Jason A. Donenfeld Oct. 25, 2022, 3:19 p.m. UTC | #10
On Tue, Oct 25, 2022 at 03:58:06PM +0200, Jason A. Donenfeld wrote:
> On Tue, Oct 25, 2022 at 02:54:01PM +0100, Peter Maydell wrote:
> > On Tue, 25 Oct 2022 at 13:50, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> > >
> > > On Tue, Oct 25, 2022 at 2:42 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> > > >
> > > > On Tue, Oct 25, 2022 at 2:34 PM Peter Maydell <peter.maydell@linaro.org> wrote:
> > > > > No, I was just running "make check-avocado" locally.
> > > >
> > > > Oh, okay. I'll try out a full `make check` locally then just to be sure.
> > 
> > "make check" doesn't run the "make check-avocado" tests (because
> > they take a lot longer than most developers want for a simple
> > smoke test, and do things like downloading guest images for tests.)
> 
> Ah, okay, running.

Okay, I did it and got:

    "cancel": 4,
    "errors": 1,
    "failures": 0,
    "interrupt": 7,
    "pass": 10,
    "skip": 170,

Not sure what that one error is about -- it doesn't seem related though.
results.json attached here if you want to have a look.

Jason
diff mbox series

Patch

diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index bc3ecdb619..69cadb1c37 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1349,12 +1349,12 @@  static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data)
         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);
     AspeedGPIOState *gpio = &bmc->soc.gpio;
 
-    qemu_devices_reset();
+    qemu_devices_reset(reason);
 
     /* Board ID: 7 (Class-1, 4 slots) */
     object_property_set_bool(OBJECT(gpio), "gpioV4", true, &error_fatal);
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index 394192b9b2..284c09c91d 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -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);
 
@@ -1249,7 +1249,7 @@  static void mps2_machine_reset(MachineState *machine)
      * reset see the correct mapping.
      */
     remap_memory(mms, mms->remap);
-    qemu_devices_reset();
+    qemu_devices_reset(reason);
 }
 
 static void mps2tz_class_init(ObjectClass *oc, void *data)
diff --git a/hw/core/reset.c b/hw/core/reset.c
index 36be82c491..bcf323d6dd 100644
--- a/hw/core/reset.c
+++ b/hw/core/reset.c
@@ -33,6 +33,7 @@  typedef struct QEMUResetEntry {
     QTAILQ_ENTRY(QEMUResetEntry) entry;
     QEMUResetHandler *func;
     void *opaque;
+    bool skip_on_snapshot_load;
 } QEMUResetEntry;
 
 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);
 }
 
+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)
 {
     QEMUResetEntry *re;
@@ -60,12 +71,14 @@  void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
     }
 }
 
-void qemu_devices_reset(void)
+void qemu_devices_reset(ShutdownCause reason)
 {
     QEMUResetEntry *re, *nre;
 
     /* reset all devices */
     QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) {
+        if (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD && re->skip_on_snapshot_load)
+            continue;
         re->func(re->opaque);
     }
 }
diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
index e53d5f0fa7..19ea7c2c66 100644
--- a/hw/hppa/machine.c
+++ b/hw/hppa/machine.c
@@ -411,12 +411,12 @@  static void machine_hppa_init(MachineState *machine)
     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;
     int i;
 
-    qemu_devices_reset();
+    qemu_devices_reset(reason);
 
     /* Start all CPUs at the firmware entry point.
      *  Monarch CPU will initialize firmware, secondary CPUs
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 52f9aa9d8c..ffd1884100 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -467,7 +467,7 @@  static void microvm_machine_state_init(MachineState *machine)
     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);
     CPUState *cs;
@@ -480,7 +480,7 @@  static void microvm_machine_reset(MachineState *machine)
         mms->kernel_cmdline_fixed = true;
     }
 
-    qemu_devices_reset();
+    qemu_devices_reset(reason);
 
     CPU_FOREACH(cs) {
         cpu = X86_CPU(cs);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 768982ae9a..3e86083db3 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1847,12 +1847,12 @@  static void pc_machine_initfn(Object *obj)
     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;
     X86CPU *cpu;
 
-    qemu_devices_reset();
+    qemu_devices_reset(reason);
 
     /* Reset APIC after devices have been reset to cancel
      * 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)
 {
     cpu_synchronize_all_states();
-    pc_machine_reset(machine);
+    pc_machine_reset(machine, SHUTDOWN_CAUSE_NONE);
     cpu_synchronize_all_post_reset();
 }
 
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index ecf682b148..bb4d008ba9 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -248,14 +248,14 @@  static void pegasos2_pci_config_write(Pegasos2MachineState *pm, int bus,
     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);
     void *fdt;
     uint64_t d[2];
     int sz;
 
-    qemu_devices_reset();
+    qemu_devices_reset(reason);
     if (!pm->vof) {
         return; /* Firmware should set up machine so nothing to do */
     }
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 40bb573d1a..3d01e26f84 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -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);
     IPMIBmc *bmc;
     void *fdt;
 
-    qemu_devices_reset();
+    qemu_devices_reset(reason);
 
     /*
      * The machine should provide by default an internal BMC simulator.
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index f79ac85ca1..66b414d2e9 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -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);
     PowerPCCPU *first_ppc_cpu;
@@ -1649,7 +1649,7 @@  static void spapr_machine_reset(MachineState *machine)
         spapr_setup_hpt(spapr);
     }
 
-    qemu_devices_reset();
+    qemu_devices_reset(reason);
 
     spapr_ovec_cleanup(spapr->ov5_cas);
     spapr->ov5_cas = spapr_ovec_new();
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 03855c7231..8017acb1d5 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -405,7 +405,7 @@  static void s390_pv_prepare_reset(S390CcwMachineState *ms)
     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);
     enum s390_reset reset_type;
@@ -427,7 +427,7 @@  static void s390_machine_reset(MachineState *machine)
             s390_machine_unprotect(ms);
         }
 
-        qemu_devices_reset();
+        qemu_devices_reset(reason);
         s390_crypto_reset();
 
         /* configure and start the ipl CPU only */
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 311ed17e18..90f1dd3aeb 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -231,7 +231,7 @@  struct MachineClass {
     const char *deprecation_reason;
 
     void (*init)(MachineState *state);
-    void (*reset)(MachineState *state);
+    void (*reset)(MachineState *state, ShutdownCause reason);
     void (*wakeup)(MachineState *state);
     int (*kvm_type)(MachineState *machine, const char *arg);
 
diff --git a/include/sysemu/reset.h b/include/sysemu/reset.h
index 0b0d6d7598..609e4d50c2 100644
--- a/include/sysemu/reset.h
+++ b/include/sysemu/reset.h
@@ -1,10 +1,13 @@ 
 #ifndef QEMU_SYSEMU_RESET_H
 #define QEMU_SYSEMU_RESET_H
 
+#include "qapi/qapi-events-run-state.h"
+
 typedef void QEMUResetHandler(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_devices_reset(void);
+void qemu_devices_reset(ShutdownCause reason);
 
 #endif
diff --git a/migration/savevm.c b/migration/savevm.c
index 48e85c052c..a0cdb714f7 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -3058,7 +3058,7 @@  bool load_snapshot(const char *name, const char *vmstate,
         goto err_drain;
     }
 
-    qemu_system_reset(SHUTDOWN_CAUSE_NONE);
+    qemu_system_reset(SHUTDOWN_CAUSE_SNAPSHOT_LOAD);
     mis->from_src_file = f;
 
     if (!yank_register_instance(MIGRATION_YANK_INSTANCE, errp)) {
diff --git a/qapi/run-state.json b/qapi/run-state.json
index 49989d30e6..e44c0de914 100644
--- a/qapi/run-state.json
+++ b/qapi/run-state.json
@@ -86,12 +86,15 @@ 
 #                   ignores --no-reboot. This is useful for sanitizing
 #                   hypercalls on s390 that are used during kexec/kdump/boot
 #
+# @snapshot-load: A snapshot is being loaded by the record & replay
+#                 subsystem; internal value (since 7.2)
+#
 ##
 { 'enum': 'ShutdownCause',
   # Beware, shutdown_caused_by_guest() depends on enumeration order
   'data': [ 'none', 'host-error', 'host-qmp-quit', 'host-qmp-system-reset',
             'host-signal', 'host-ui', 'guest-shutdown', 'guest-reset',
-            'guest-panic', 'subsystem-reset'] }
+            'guest-panic', 'subsystem-reset', 'snapshot-load'] }
 
 ##
 # @StatusInfo:
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
index 1e68680b9d..3dd83d5e5d 100644
--- a/softmmu/runstate.c
+++ b/softmmu/runstate.c
@@ -441,11 +441,16 @@  void qemu_system_reset(ShutdownCause reason)
     cpu_synchronize_all_states();
 
     if (mc && mc->reset) {
-        mc->reset(current_machine);
+        mc->reset(current_machine, reason);
     } 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);
     }
     cpu_synchronize_all_post_reset();