Pārlūkot izejas kodu

replay: save/load initial state

This patch implements initial vmstate creation or loading at the start
of record/replay. It is needed for rewinding the execution in the replay mode.

v4 changes:
 - snapshots are not created by default anymore

v3 changes:
 - added rrsnapshot option

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20170124071746.4572.61449.stgit@PASHA-ISP>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Pavel Dovgalyuk 8 gadi atpakaļ
vecāks
revīzija
9c2037d0a4
6 mainītis faili ar 59 papildinājumiem un 3 dzēšanām
  1. 16 0
      docs/replay.txt
  2. 9 0
      include/sysemu/replay.h
  3. 6 2
      qemu-options.hx
  4. 17 0
      replay/replay-snapshot.c
  5. 5 0
      replay/replay.c
  6. 6 1
      vl.c

+ 16 - 0
docs/replay.txt

@@ -196,6 +196,22 @@ is recorded to the log. In replay phase the queue is matched with
 events read from the log. Therefore block devices requests are processed
 events read from the log. Therefore block devices requests are processed
 deterministically.
 deterministically.
 
 
+Snapshotting
+------------
+
+New VM snapshots may be created in replay mode. They can be used later
+to recover the desired VM state. All VM states created in replay mode
+are associated with the moment of time in the replay scenario.
+After recovering the VM state replay will start from that position.
+
+Default starting snapshot name may be specified with icount field
+rrsnapshot as follows:
+ -icount shift=7,rr=record,rrfile=replay.bin,rrsnapshot=snapshot_name
+
+This snapshot is created at start of recording and restored at start
+of replaying. It also can be loaded while replaying to roll back
+the execution.
+
 Network devices
 Network devices
 ---------------
 ---------------
 
 

+ 9 - 0
include/sysemu/replay.h

@@ -43,6 +43,9 @@ typedef struct ReplayNetState ReplayNetState;
 
 
 extern ReplayMode replay_mode;
 extern ReplayMode replay_mode;
 
 
+/* Name of the initial VM snapshot */
+extern char *replay_snapshot;
+
 /* Replay process control functions */
 /* Replay process control functions */
 
 
 /*! Enables recording or saving event log with specified parameters */
 /*! Enables recording or saving event log with specified parameters */
@@ -149,4 +152,10 @@ void replay_unregister_net(ReplayNetState *rns);
 void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
 void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
                              const struct iovec *iov, int iovcnt);
                              const struct iovec *iov, int iovcnt);
 
 
+/* VM state operations */
+
+/*! Called at the start of execution.
+    Loads or saves initial vmstate depending on execution mode. */
+void replay_vmstate_init(void);
+
 #endif
 #endif

+ 6 - 2
qemu-options.hx

@@ -3400,12 +3400,12 @@ re-inject them.
 ETEXI
 ETEXI
 
 
 DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
 DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
-    "-icount [shift=N|auto][,align=on|off][,sleep=on|off,rr=record|replay,rrfile=<filename>]\n" \
+    "-icount [shift=N|auto][,align=on|off][,sleep=on|off,rr=record|replay,rrfile=<filename>,rrsnapshot=<snapshot>]\n" \
     "                enable virtual instruction counter with 2^N clock ticks per\n" \
     "                enable virtual instruction counter with 2^N clock ticks per\n" \
     "                instruction, enable aligning the host and virtual clocks\n" \
     "                instruction, enable aligning the host and virtual clocks\n" \
     "                or disable real time cpu sleeping\n", QEMU_ARCH_ALL)
     "                or disable real time cpu sleeping\n", QEMU_ARCH_ALL)
 STEXI
 STEXI
-@item -icount [shift=@var{N}|auto][,rr=record|replay,rrfile=@var{filename}]
+@item -icount [shift=@var{N}|auto][,rr=record|replay,rrfile=@var{filename},rrsnapshot=@var{snapshot}]
 @findex -icount
 @findex -icount
 Enable virtual instruction counter.  The virtual cpu will execute one
 Enable virtual instruction counter.  The virtual cpu will execute one
 instruction every 2^@var{N} ns of virtual time.  If @code{auto} is specified
 instruction every 2^@var{N} ns of virtual time.  If @code{auto} is specified
@@ -3438,6 +3438,10 @@ when the shift value is high (how high depends on the host machine).
 When @option{rr} option is specified deterministic record/replay is enabled.
 When @option{rr} option is specified deterministic record/replay is enabled.
 Replay log is written into @var{filename} file in record mode and
 Replay log is written into @var{filename} file in record mode and
 read from this file in replay mode.
 read from this file in replay mode.
+
+Option rrsnapshot is used to create new vm snapshot named @var{snapshot}
+at the start of execution recording. In replay mode this option is used
+to load the initial VM state.
 ETEXI
 ETEXI
 
 
 DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \
 DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \

+ 17 - 0
replay/replay-snapshot.c

@@ -59,3 +59,20 @@ void replay_vmstate_register(void)
 {
 {
     vmstate_register(NULL, 0, &vmstate_replay, &replay_state);
     vmstate_register(NULL, 0, &vmstate_replay, &replay_state);
 }
 }
+
+void replay_vmstate_init(void)
+{
+    if (replay_snapshot) {
+        if (replay_mode == REPLAY_MODE_RECORD) {
+            if (save_vmstate(cur_mon, replay_snapshot) != 0) {
+                error_report("Could not create snapshot for icount record");
+                exit(1);
+            }
+        } else if (replay_mode == REPLAY_MODE_PLAY) {
+            if (load_vmstate(replay_snapshot) != 0) {
+                error_report("Could not load snapshot for icount replay");
+                exit(1);
+            }
+        }
+    }
+}

+ 5 - 0
replay/replay.c

@@ -26,6 +26,7 @@
 #define HEADER_SIZE                 (sizeof(uint32_t) + sizeof(uint64_t))
 #define HEADER_SIZE                 (sizeof(uint32_t) + sizeof(uint64_t))
 
 
 ReplayMode replay_mode = REPLAY_MODE_NONE;
 ReplayMode replay_mode = REPLAY_MODE_NONE;
+char *replay_snapshot;
 
 
 /* Name of replay file  */
 /* Name of replay file  */
 static char *replay_filename;
 static char *replay_filename;
@@ -292,6 +293,7 @@ void replay_configure(QemuOpts *opts)
         exit(1);
         exit(1);
     }
     }
 
 
+    replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
     replay_vmstate_register();
     replay_vmstate_register();
     replay_enable(fname, mode);
     replay_enable(fname, mode);
 
 
@@ -346,6 +348,9 @@ void replay_finish(void)
         replay_filename = NULL;
         replay_filename = NULL;
     }
     }
 
 
+    g_free(replay_snapshot);
+    replay_snapshot = NULL;
+
     replay_finish_events();
     replay_finish_events();
     replay_mutex_destroy();
     replay_mutex_destroy();
 }
 }

+ 6 - 1
vl.c

@@ -465,6 +465,9 @@ static QemuOptsList qemu_icount_opts = {
         }, {
         }, {
             .name = "rrfile",
             .name = "rrfile",
             .type = QEMU_OPT_STRING,
             .type = QEMU_OPT_STRING,
+        }, {
+            .name = "rrsnapshot",
+            .type = QEMU_OPT_STRING,
         },
         },
         { /* end of list */ }
         { /* end of list */ }
     },
     },
@@ -4634,7 +4637,9 @@ int main(int argc, char **argv, char **envp)
     replay_checkpoint(CHECKPOINT_RESET);
     replay_checkpoint(CHECKPOINT_RESET);
     qemu_system_reset(VMRESET_SILENT);
     qemu_system_reset(VMRESET_SILENT);
     register_global_state();
     register_global_state();
-    if (loadvm) {
+    if (replay_mode != REPLAY_MODE_NONE) {
+        replay_vmstate_init();
+    } else if (loadvm) {
         if (load_vmstate(loadvm) < 0) {
         if (load_vmstate(loadvm) < 0) {
             autostart = 0;
             autostart = 0;
         }
         }