migration: introduce icount field for snapshots

Saving icount as a parameters of the snapshot allows navigation between
them in the execution replay scenario.
This information can be used for finding a specific snapshot for proceeding
the recorded execution to the specific moment of the time.
E.g., 'reverse step' action (introduced in one of the following patches)
needs to load the nearest snapshot which is prior to the current moment
of time.
This patch also updates snapshot test which verifies qemu monitor output.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Acked-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Kevin Wolf <kwolf@redhat.com>

--

v4 changes:
 - squashed format update with test output update
v7 changes:
 - introduced the spaces between the fields in snapshot info output
 - updated the test to match new field widths
Message-Id: <160174518865.12451.14327573383978752463.stgit@pasha-ThinkPad-X280>

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Pavel Dovgalyuk 2020-10-03 20:13:08 +03:00 committed by Paolo Bonzini
parent bbacffc5f7
commit b39847a505
9 changed files with 71 additions and 32 deletions

View File

@ -230,6 +230,8 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs,
info->date_nsec = sn_tab[i].date_nsec; info->date_nsec = sn_tab[i].date_nsec;
info->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000; info->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000;
info->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000; info->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000;
info->icount = sn_tab[i].icount;
info->has_icount = sn_tab[i].icount != -1ULL;
info_list = g_new0(SnapshotInfoList, 1); info_list = g_new0(SnapshotInfoList, 1);
info_list->value = info; info_list->value = info;
@ -694,14 +696,15 @@ BlockStatsList *qmp_query_blockstats(bool has_query_nodes,
void bdrv_snapshot_dump(QEMUSnapshotInfo *sn) void bdrv_snapshot_dump(QEMUSnapshotInfo *sn)
{ {
char date_buf[128], clock_buf[128]; char date_buf[128], clock_buf[128];
char icount_buf[128] = {0};
struct tm tm; struct tm tm;
time_t ti; time_t ti;
int64_t secs; int64_t secs;
char *sizing = NULL; char *sizing = NULL;
if (!sn) { if (!sn) {
qemu_printf("%-10s%-20s%11s%20s%15s", qemu_printf("%-10s%-18s%7s%20s%13s%11s",
"ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK", "ICOUNT");
} else { } else {
ti = sn->date_sec; ti = sn->date_sec;
localtime_r(&ti, &tm); localtime_r(&ti, &tm);
@ -715,11 +718,16 @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn)
(int)(secs % 60), (int)(secs % 60),
(int)((sn->vm_clock_nsec / 1000000) % 1000)); (int)((sn->vm_clock_nsec / 1000000) % 1000));
sizing = size_to_str(sn->vm_state_size); sizing = size_to_str(sn->vm_state_size);
qemu_printf("%-10s%-20s%11s%20s%15s", if (sn->icount != -1ULL) {
snprintf(icount_buf, sizeof(icount_buf),
"%"PRId64, sn->icount);
}
qemu_printf("%-9s %-17s %7s%20s%13s%11s",
sn->id_str, sn->name, sn->id_str, sn->name,
sizing, sizing,
date_buf, date_buf,
clock_buf); clock_buf,
icount_buf);
} }
g_free(sizing); g_free(sizing);
} }
@ -881,6 +889,8 @@ void bdrv_image_info_dump(ImageInfo *info)
.date_nsec = elem->value->date_nsec, .date_nsec = elem->value->date_nsec,
.vm_clock_nsec = elem->value->vm_clock_sec * 1000000000ULL + .vm_clock_nsec = elem->value->vm_clock_sec * 1000000000ULL +
elem->value->vm_clock_nsec, elem->value->vm_clock_nsec,
.icount = elem->value->has_icount ?
elem->value->icount : -1ULL,
}; };
pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id); pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id);

View File

@ -663,6 +663,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
sn->date_sec = sn_info->date_sec; sn->date_sec = sn_info->date_sec;
sn->date_nsec = sn_info->date_nsec; sn->date_nsec = sn_info->date_nsec;
sn->vm_clock_nsec = sn_info->vm_clock_nsec; sn->vm_clock_nsec = sn_info->vm_clock_nsec;
sn->icount = sn_info->icount;
sn->extra_data_size = sizeof(QCowSnapshotExtraData); sn->extra_data_size = sizeof(QCowSnapshotExtraData);
/* Allocate the L1 table of the snapshot and copy the current one there. */ /* Allocate the L1 table of the snapshot and copy the current one there. */
@ -1007,6 +1008,7 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
sn_info->date_sec = sn->date_sec; sn_info->date_sec = sn->date_sec;
sn_info->date_nsec = sn->date_nsec; sn_info->date_nsec = sn->date_nsec;
sn_info->vm_clock_nsec = sn->vm_clock_nsec; sn_info->vm_clock_nsec = sn->vm_clock_nsec;
sn_info->icount = sn->icount;
} }
*psn_tab = sn_tab; *psn_tab = sn_tab;
return s->nb_snapshots; return s->nb_snapshots;

View File

@ -59,6 +59,7 @@
#include "sysemu/arch_init.h" #include "sysemu/arch_init.h"
#include "sysemu/qtest.h" #include "sysemu/qtest.h"
#include "sysemu/runstate.h" #include "sysemu/runstate.h"
#include "sysemu/replay.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qemu/help_option.h" #include "qemu/help_option.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
@ -1190,6 +1191,10 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
info->vm_state_size = sn.vm_state_size; info->vm_state_size = sn.vm_state_size;
info->vm_clock_nsec = sn.vm_clock_nsec % 1000000000; info->vm_clock_nsec = sn.vm_clock_nsec % 1000000000;
info->vm_clock_sec = sn.vm_clock_nsec / 1000000000; info->vm_clock_sec = sn.vm_clock_nsec / 1000000000;
if (sn.icount != -1ULL) {
info->icount = sn.icount;
info->has_icount = true;
}
return info; return info;
@ -1350,6 +1355,11 @@ static void internal_snapshot_prepare(BlkActionState *common,
sn->date_sec = tv.tv_sec; sn->date_sec = tv.tv_sec;
sn->date_nsec = tv.tv_usec * 1000; sn->date_nsec = tv.tv_usec * 1000;
sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if (replay_mode != REPLAY_MODE_NONE) {
sn->icount = replay_get_current_icount();
} else {
sn->icount = -1ULL;
}
ret1 = bdrv_snapshot_create(bs, sn); ret1 = bdrv_snapshot_create(bs, sn);
if (ret1 < 0) { if (ret1 < 0) {

View File

@ -42,6 +42,7 @@ typedef struct QEMUSnapshotInfo {
uint32_t date_sec; /* UTC date of the snapshot */ uint32_t date_sec; /* UTC date of the snapshot */
uint32_t date_nsec; uint32_t date_nsec;
uint64_t vm_clock_nsec; /* VM clock relative to boot */ uint64_t vm_clock_nsec; /* VM clock relative to boot */
uint64_t icount; /* record/replay step */
} QEMUSnapshotInfo; } QEMUSnapshotInfo;
int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,

View File

@ -2723,6 +2723,11 @@ int save_snapshot(const char *name, Error **errp)
sn->date_sec = tv.tv_sec; sn->date_sec = tv.tv_sec;
sn->date_nsec = tv.tv_usec * 1000; sn->date_nsec = tv.tv_usec * 1000;
sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if (replay_mode != REPLAY_MODE_NONE) {
sn->icount = replay_get_current_icount();
} else {
sn->icount = -1ULL;
}
if (name) { if (name) {
ret = bdrv_snapshot_find(bs, old_sn, name); ret = bdrv_snapshot_find(bs, old_sn, name);

View File

@ -27,13 +27,18 @@
# #
# @vm-clock-nsec: fractional part in nano seconds to be used with vm-clock-sec # @vm-clock-nsec: fractional part in nano seconds to be used with vm-clock-sec
# #
# @icount: Current instruction count. Appears when execution record/replay
# is enabled. Used for "time-traveling" to match the moment
# in the recorded execution with the snapshots. (since 5.2)
#
# Since: 1.3 # Since: 1.3
# #
## ##
{ 'struct': 'SnapshotInfo', { 'struct': 'SnapshotInfo',
'data': { 'id': 'str', 'name': 'str', 'vm-state-size': 'int', 'data': { 'id': 'str', 'name': 'str', 'vm-state-size': 'int',
'date-sec': 'int', 'date-nsec': 'int', 'date-sec': 'int', 'date-nsec': 'int',
'vm-clock-sec': 'int', 'vm-clock-nsec': 'int' } } 'vm-clock-sec': 'int', 'vm-clock-nsec': 'int',
'*icount': 'int' } }
## ##
# @ImageInfoSpecificQCow2EncryptionBase: # @ImageInfoSpecificQCow2EncryptionBase:
@ -5363,7 +5368,8 @@
# "date-sec": 1000012, # "date-sec": 1000012,
# "date-nsec": 10, # "date-nsec": 10,
# "vm-clock-sec": 100, # "vm-clock-sec": 100,
# "vm-clock-nsec": 20 # "vm-clock-nsec": 20,
# "icount": 220414
# } # }
# } # }
# #

View File

@ -88,3 +88,8 @@ int replay_read_random(void *buf, size_t len)
{ {
return 0; return 0;
} }
uint64_t replay_get_current_icount(void)
{
return 0;
}

View File

@ -392,7 +392,7 @@ _check_test_img -r all
echo echo
echo "$((sn_count - 1)) snapshots should remain:" echo "$((sn_count - 1)) snapshots should remain:"
echo " qemu-img info reports $(_img_info | grep -c '^ \{34\}') snapshots" echo " qemu-img info reports $(_img_info | grep -c '^ \{32\}') snapshots"
echo " Image header reports $(peek_file_be "$TEST_IMG" 60 4) snapshots" echo " Image header reports $(peek_file_be "$TEST_IMG" 60 4) snapshots"
echo echo
@ -519,7 +519,7 @@ _check_test_img -r all
echo echo
echo '65536 snapshots should remain:' echo '65536 snapshots should remain:'
echo " qemu-img info reports $(_img_info | grep -c '^ \{34\}') snapshots" echo " qemu-img info reports $(_img_info | grep -c '^ \{32\}') snapshots"
echo " Image header reports $(peek_file_be "$TEST_IMG" 60 4) snapshots" echo " Image header reports $(peek_file_be "$TEST_IMG" 60 4) snapshots"
# success, all done # success, all done

View File

@ -33,8 +33,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0 (qemu) savevm snap0
(qemu) info snapshots (qemu) info snapshots
List of snapshots present on all disks: List of snapshots present on all disks:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 -- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
(qemu) loadvm snap0 (qemu) loadvm snap0
(qemu) quit (qemu) quit
@ -44,8 +44,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0 (qemu) savevm snap0
(qemu) info snapshots (qemu) info snapshots
List of snapshots present on all disks: List of snapshots present on all disks:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 -- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
(qemu) loadvm snap0 (qemu) loadvm snap0
(qemu) quit (qemu) quit
@ -69,8 +69,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0 (qemu) savevm snap0
(qemu) info snapshots (qemu) info snapshots
List of snapshots present on all disks: List of snapshots present on all disks:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 -- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
(qemu) loadvm snap0 (qemu) loadvm snap0
(qemu) quit (qemu) quit
@ -94,8 +94,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0 (qemu) savevm snap0
(qemu) info snapshots (qemu) info snapshots
List of snapshots present on all disks: List of snapshots present on all disks:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 -- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
(qemu) loadvm snap0 (qemu) loadvm snap0
(qemu) quit (qemu) quit
@ -105,8 +105,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0 (qemu) savevm snap0
(qemu) info snapshots (qemu) info snapshots
List of snapshots present on all disks: List of snapshots present on all disks:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 -- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
(qemu) loadvm snap0 (qemu) loadvm snap0
(qemu) quit (qemu) quit
@ -119,8 +119,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0 (qemu) savevm snap0
(qemu) info snapshots (qemu) info snapshots
List of snapshots present on all disks: List of snapshots present on all disks:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 -- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
(qemu) loadvm snap0 (qemu) loadvm snap0
(qemu) quit (qemu) quit
@ -134,8 +134,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0 (qemu) savevm snap0
(qemu) info snapshots (qemu) info snapshots
List of snapshots present on all disks: List of snapshots present on all disks:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 -- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
(qemu) loadvm snap0 (qemu) loadvm snap0
(qemu) quit (qemu) quit
@ -145,15 +145,15 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0 (qemu) savevm snap0
(qemu) info snapshots (qemu) info snapshots
List of snapshots present on all disks: List of snapshots present on all disks:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 -- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
(qemu) loadvm snap0 (qemu) loadvm snap0
(qemu) quit (qemu) quit
Internal snapshots on overlay: Internal snapshots on overlay:
Snapshot list: Snapshot list:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
Internal snapshots on backing file: Internal snapshots on backing file:
=== -blockdev with NBD server on the backing file === === -blockdev with NBD server on the backing file ===
@ -166,17 +166,17 @@ QEMU X.Y.Z monitor - type 'help' for more information
(qemu) savevm snap0 (qemu) savevm snap0
(qemu) info snapshots (qemu) info snapshots
List of snapshots present on all disks: List of snapshots present on all disks:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 -- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
(qemu) loadvm snap0 (qemu) loadvm snap0
(qemu) quit (qemu) quit
Internal snapshots on overlay: Internal snapshots on overlay:
Snapshot list: Snapshot list:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
Internal snapshots on backing file: Internal snapshots on backing file:
Snapshot list: Snapshot list:
ID TAG VM SIZE DATE VM CLOCK ID TAG VM SIZE DATE VM CLOCK ICOUNT
1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
*** done *** done