qemu/replay/replay-snapshot.c
Pavel Dovgalyuk 0b30dc0164 replay: save vmstate of the asynchronous events
This patch fixes saving and loading the snapshots in the replay mode.
It is required for the snapshots created in the moment when the header
of the asynchronous event is read. This information was not saved in
the snapshot. After loading the vmstate replay continued with the file offset
passed the event header. The event header is lost in this case and replay
hangs.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
Message-Id: <20180227095322.1060.53929.stgit@pasha-VirtualBox>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2018-03-12 17:10:38 +01:00

98 lines
2.8 KiB
C

/*
* 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"
#include "qemu/error-report.h"
#include "migration/vmstate.h"
#include "migration/snapshot.h"
static int replay_pre_save(void *opaque)
{
ReplayState *state = opaque;
state->file_offset = ftell(replay_file);
state->host_clock_last = qemu_clock_get_last(QEMU_CLOCK_HOST);
return 0;
}
static int replay_post_load(void *opaque, int version_id)
{
ReplayState *state = opaque;
fseek(replay_file, state->file_offset, SEEK_SET);
qemu_clock_set_last(QEMU_CLOCK_HOST, state->host_clock_last);
/* If this was a vmstate, saved in recording mode,
we need to initialize replay data fields. */
replay_fetch_data_kind();
return 0;
}
static const VMStateDescription vmstate_replay = {
.name = "replay",
.version_id = 1,
.minimum_version_id = 1,
.pre_save = replay_pre_save,
.post_load = replay_post_load,
.fields = (VMStateField[]) {
VMSTATE_INT64_ARRAY(cached_clock, ReplayState, REPLAY_CLOCK_COUNT),
VMSTATE_UINT64(current_step, ReplayState),
VMSTATE_INT32(instructions_count, ReplayState),
VMSTATE_UINT32(data_kind, ReplayState),
VMSTATE_UINT32(has_unread_data, ReplayState),
VMSTATE_UINT64(file_offset, ReplayState),
VMSTATE_UINT64(block_request_id, ReplayState),
VMSTATE_UINT64(host_clock_last, ReplayState),
VMSTATE_INT32(read_event_kind, ReplayState),
VMSTATE_UINT64(read_event_id, ReplayState),
VMSTATE_INT32(read_event_checkpoint, ReplayState),
VMSTATE_END_OF_LIST()
},
};
void replay_vmstate_register(void)
{
vmstate_register(NULL, 0, &vmstate_replay, &replay_state);
}
void replay_vmstate_init(void)
{
Error *err = NULL;
if (replay_snapshot) {
if (replay_mode == REPLAY_MODE_RECORD) {
if (save_snapshot(replay_snapshot, &err) != 0) {
error_report_err(err);
error_report("Could not create snapshot for icount record");
exit(1);
}
} else if (replay_mode == REPLAY_MODE_PLAY) {
if (load_snapshot(replay_snapshot, &err) != 0) {
error_report_err(err);
error_report("Could not load snapshot for icount replay");
exit(1);
}
}
}
}
bool replay_can_snapshot(void)
{
return replay_mode == REPLAY_MODE_NONE
|| !replay_has_events();
}