diff mbox

[v3,4/8] replay: save/load initial state

Message ID 20160920123149.5400.87854.stgit@PASHA-ISP.def.inno (mailing list archive)
State New, archived
Headers show

Commit Message

Pavel Dovgalyuk Sept. 20, 2016, 12:31 p.m. UTC
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.

v3 changes:
 - added rrsnapshot option

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
---
 docs/replay.txt          |   12 ++++++++++++
 include/sysemu/replay.h  |    6 ++++++
 qemu-options.hx          |    8 +++++---
 replay/Makefile.objs     |    1 +
 replay/replay-internal.h |    3 +++
 replay/replay-snapshot.c |   31 +++++++++++++++++++++++++++++++
 replay/replay.c          |    7 +++++++
 vl.c                     |    8 +++++++-
 8 files changed, 72 insertions(+), 4 deletions(-)
 create mode 100644 replay/replay-snapshot.c

Comments

Paolo Bonzini Sept. 20, 2016, 12:37 p.m. UTC | #1
On 20/09/2016 14:31, Pavel Dovgalyuk wrote:
> @@ -291,6 +292,8 @@ void replay_configure(QemuOpts *opts)
>          exit(1);
>      }
>  
> +    replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
> +
>      replay_enable(fname, mode);
>  

Should you set snapshot = 1 here if there is no rrsnapshot option?

Paolo
Pavel Dovgalyuk Sept. 20, 2016, 12:39 p.m. UTC | #2
> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
> On 20/09/2016 14:31, Pavel Dovgalyuk wrote:
> > @@ -291,6 +292,8 @@ void replay_configure(QemuOpts *opts)
> >          exit(1);
> >      }
> >
> > +    replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
> > +
> >      replay_enable(fname, mode);
> >
> 
> Should you set snapshot = 1 here if there is no rrsnapshot option?

No, because there is default snapshot name for the case when user 
specifies overlay for the drives.

Pavel Dovgalyuk
Paolo Bonzini Sept. 20, 2016, 12:52 p.m. UTC | #3
On 20/09/2016 14:39, Pavel Dovgalyuk wrote:
> > > +    replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
> > > +
> > >      replay_enable(fname, mode);
> > >
> > 
> > Should you set snapshot = 1 here if there is no rrsnapshot option?
> 
> No, because there is default snapshot name for the case when user 
> specifies overlay for the drives.

There are three possibilities:

a) these patches:
   with implicit overlay:
      -drive file=disk.raw,if=none,id=img-direct
      -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay

   with explicit overlay:
     -drive file=disk.raw,if=none,id=img-direct
     -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay,overlay=foo.qcow2

   Advantages:
   - does the right thing in the "implicit overlay" case.

   Disadvantages:
   - no need really to specify disk.raw in the "explicit overlay" case, since
     it's already specified when you create the overlay with qemu-img.

   Vote for implicit overlay: excellent
   Vote for explicit overlay: bad (need to track two file names)

b) always specify -snapshot manually:
   with implicit overlay:
      -drive file=disk.raw,if=none,id=img-direct -snapshot
      -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay

   with explicit overlay:
     -drive file=foo.qcow2,if=none,id=img-direct
     -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay

   Advantages:
   - can use default snapshot name in the "explicit overlay" case

   Disadvantages:
   - need to specify -snapshot explicitly for the "implicit overlay" case

   Vote for implicit overlay: awful (disk.raw destroy if you forget -snapshot)
   Vote for explicit overlay: excellent

c) no rrsnapshot implies -snapshot:
   without overlay:
      -drive file=disk.raw,if=none,id=img-direct
      -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay

   with overlay:
     -drive file=foo.qcow2,if=none,id=img-direct
     -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
     -icount ...,rrsnapshot=snapname

   Advantages:
   - does the right thing in the "implicit overlay" case.

   Disadvantages:
   - always have to specify snapshot name in the "explicit overlay" case

   Vote for implicit overlay: excellent (same as a)
   Vote for explicit overlay: decent

We have to choose between (a) and (c) I think, because the risk of corruption
for (b) is too high.  I prefer (c).  Kevin, what do you think?

Thanks,

Paolo
Pavel Dovgalyuk Sept. 20, 2016, 1:37 p.m. UTC | #4
> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
> On 20/09/2016 14:39, Pavel Dovgalyuk wrote:
> > > > +    replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
> > > > +
> > > >      replay_enable(fname, mode);
> > > >
> > >
> > > Should you set snapshot = 1 here if there is no rrsnapshot option?
> >
> > No, because there is default snapshot name for the case when user
> > specifies overlay for the drives.
> 
> There are three possibilities:
> 
> a) these patches:
>    with implicit overlay:
>       -drive file=disk.raw,if=none,id=img-direct
>       -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
> 
>    with explicit overlay:
>      -drive file=disk.raw,if=none,id=img-direct
>      -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay,overlay=foo.qcow2
> 
>    Advantages:
>    - does the right thing in the "implicit overlay" case.

     - automatically creates overlay

> 
>    Disadvantages:
>    - no need really to specify disk.raw in the "explicit overlay" case, since
>      it's already specified when you create the overlay with qemu-img.
> 
>    Vote for implicit overlay: excellent
>    Vote for explicit overlay: bad (need to track two file names)

Disadvantage is for replay only. Running QEMU in record mode automatically
creates overlay. Therefore two filenames are required.

> c) no rrsnapshot implies -snapshot:
>    without overlay:
>       -drive file=disk.raw,if=none,id=img-direct
>       -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
> 
>    with overlay:
>      -drive file=foo.qcow2,if=none,id=img-direct
>      -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
>      -icount ...,rrsnapshot=snapname

But how record will create this overlay?
This method requires creating overlay manually, because backing file is
not specified at all.


Pavel Dovgalyuk
Paolo Bonzini Sept. 20, 2016, 1:45 p.m. UTC | #5
On 20/09/2016 15:37, Pavel Dovgalyuk wrote:
>> c) no rrsnapshot implies -snapshot:
>>    without overlay:
>>       -drive file=disk.raw,if=none,id=img-direct
>>       -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
>>
>>    with overlay:
>>      -drive file=foo.qcow2,if=none,id=img-direct
>>      -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
>>      -icount ...,rrsnapshot=snapname
> 
> But how record will create this overlay?
> This method requires creating overlay manually, because backing file is
> not specified at all.

You create it manually, or you just use a .qcow2 file to begin with for
your image.  Then:

1) if you specify no snapshot, a temporary .qcow2 file is created on top
so data is not destroyed

2) if you specify a snapshot, that snapshot is preserved (so you don't
lose the base state even though the file changes)

Paolo
Pavel Dovgalyuk Sept. 20, 2016, 1:51 p.m. UTC | #6
> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
> On 20/09/2016 15:37, Pavel Dovgalyuk wrote:
> >> c) no rrsnapshot implies -snapshot:
> >>    without overlay:
> >>       -drive file=disk.raw,if=none,id=img-direct
> >>       -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
> >>
> >>    with overlay:
> >>      -drive file=foo.qcow2,if=none,id=img-direct
> >>      -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
> >>      -icount ...,rrsnapshot=snapname
> >
> > But how record will create this overlay?
> > This method requires creating overlay manually, because backing file is
> > not specified at all.
> 
> You create it manually, or you just use a .qcow2 file to begin with for
> your image.  Then:
> 
> 1) if you specify no snapshot, a temporary .qcow2 file is created on top
> so data is not destroyed
> 
> 2) if you specify a snapshot, that snapshot is preserved (so you don't
> lose the base state even though the file changes)

Now I see.
This seems ok, but:
 - this approach adds some garbage to original disk image
 - won't work with raw images

Pavel Dovgalyuk
Paolo Bonzini Sept. 20, 2016, 1:53 p.m. UTC | #7
On 20/09/2016 15:51, Pavel Dovgalyuk wrote:
>> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
>> On 20/09/2016 15:37, Pavel Dovgalyuk wrote:
>>>> c) no rrsnapshot implies -snapshot:
>>>>    without overlay:
>>>>       -drive file=disk.raw,if=none,id=img-direct
>>>>       -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
>>>>
>>>>    with overlay:
>>>>      -drive file=foo.qcow2,if=none,id=img-direct
>>>>      -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
>>>>      -icount ...,rrsnapshot=snapname
>>>
>>> But how record will create this overlay?
>>> This method requires creating overlay manually, because backing file is
>>> not specified at all.
>>
>> You create it manually, or you just use a .qcow2 file to begin with for
>> your image.  Then:
>>
>> 1) if you specify no snapshot, a temporary .qcow2 file is created on top
>> so data is not destroyed
>>
>> 2) if you specify a snapshot, that snapshot is preserved (so you don't
>> lose the base state even though the file changes)
> 
> Now I see.
> This seems ok, but:
>  - this approach adds some garbage to original disk image
>  - won't work with raw images

Yes, for raw images or if you want to keep the pristine image you have
to do a "qemu-img create -f qcow2 -b disk.raw foo.qcow2".

Paolo
diff mbox

Patch

diff --git a/docs/replay.txt b/docs/replay.txt
index 5be8f25..ce3c6b8 100644
--- a/docs/replay.txt
+++ b/docs/replay.txt
@@ -204,6 +204,18 @@  Overlay file may be specified as follows:
  -drive driver=blkreplay,if=none,image=img-direct,
         overlay=overlay.qcow2,id=img-blkreplay
 
+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 overridden with icount field
+rrsnapshot as follows:
+ -icount shift=7,rr=record,rrfile=replay.bin,rrsnapshot=non_default_snapshot
+
 Network devices
 ---------------
 
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index a408633..aa378ce 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -145,4 +145,10 @@  void replay_unregister_net(ReplayNetState *rns);
 void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
                              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
diff --git a/qemu-options.hx b/qemu-options.hx
index 0b621bb..1483ad8 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3367,12 +3367,12 @@  re-inject them.
 ETEXI
 
 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" \
     "                instruction, enable aligning the host and virtual clocks\n" \
     "                or disable real time cpu sleeping\n", QEMU_ARCH_ALL)
 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
 Enable virtual instruction counter.  The virtual cpu will execute one
 instruction every 2^@var{N} ns of virtual time.  If @code{auto} is specified
@@ -3404,7 +3404,9 @@  when the shift value is high (how high depends on the host machine).
 
 When @option{rr} option is specified deterministic record/replay is enabled.
 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. At the start of record new snapshot
+is created. It get 'replay_init' name or the one specified with @{snapshot}
+option. In replay mode this option is used to load the initial VM state.
 ETEXI
 
 DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \
diff --git a/replay/Makefile.objs b/replay/Makefile.objs
index f55a6b5..4600d74 100644
--- a/replay/Makefile.objs
+++ b/replay/Makefile.objs
@@ -5,3 +5,4 @@  common-obj-y += replay-time.o
 common-obj-y += replay-input.o
 common-obj-y += replay-char.o
 common-obj-y += replay-net.o
+common-obj-y += replay-snapshot.o
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index d28cfb7..6f2f6e2 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -71,6 +71,9 @@  extern unsigned int replay_data_kind;
 /* File for replay writing */
 extern FILE *replay_file;
 
+/* Default name of the initial VM snapshot */
+extern char *replay_snapshot;
+
 void replay_put_byte(uint8_t byte);
 void replay_put_event(uint8_t event);
 void replay_put_word(uint16_t word);
diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c
new file mode 100644
index 0000000..6079b29
--- /dev/null
+++ b/replay/replay-snapshot.c
@@ -0,0 +1,31 @@ 
+/*
+ * replay-snapshot.c
+ *
+ * Copyright (c) 2010-2016 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "sysemu/replay.h"
+#include "replay-internal.h"
+#include "sysemu/sysemu.h"
+#include "monitor/monitor.h"
+#include "qapi/qmp/qstring.h"
+
+void replay_vmstate_init(void)
+{
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        QDict *opts = qdict_new();
+        qdict_put(opts, "name", qstring_from_str(replay_snapshot));
+        hmp_savevm(cur_mon, opts);
+        QDECREF(opts);
+    } else if (replay_mode == REPLAY_MODE_PLAY) {
+        load_vmstate(replay_snapshot);
+    }
+}
diff --git a/replay/replay.c b/replay/replay.c
index e040f6f..ef1e5e9 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -26,6 +26,7 @@ 
 #define HEADER_SIZE                 (sizeof(uint32_t) + sizeof(uint64_t))
 
 ReplayMode replay_mode = REPLAY_MODE_NONE;
+char *replay_snapshot;
 
 /* Name of replay file  */
 static char *replay_filename;
@@ -291,6 +292,8 @@  void replay_configure(QemuOpts *opts)
         exit(1);
     }
 
+    replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
+
     replay_enable(fname, mode);
 
 out:
@@ -343,6 +346,10 @@  void replay_finish(void)
         g_free(replay_filename);
         replay_filename = NULL;
     }
+    if (replay_snapshot) {
+        g_free(replay_snapshot);
+        replay_snapshot = NULL;
+    }
 
     replay_finish_events();
     replay_mutex_destroy();
diff --git a/vl.c b/vl.c
index 9adca19..c0d43f0 100644
--- a/vl.c
+++ b/vl.c
@@ -460,6 +460,10 @@  static QemuOptsList qemu_icount_opts = {
         }, {
             .name = "rrfile",
             .type = QEMU_OPT_STRING,
+        }, {
+            .name = "rrsnapshot",
+            .type = QEMU_OPT_STRING,
+            .def_value_str = "replay_init"
         },
         { /* end of list */ }
     },
@@ -4590,7 +4594,9 @@  int main(int argc, char **argv, char **envp)
     replay_checkpoint(CHECKPOINT_RESET);
     qemu_system_reset(VMRESET_SILENT);
     register_global_state();
-    if (loadvm) {
+    if (replay_mode != REPLAY_MODE_NONE) {
+        replay_vmstate_init();
+    } else if (loadvm) {
         if (load_vmstate(loadvm) < 0) {
             autostart = 0;
         }