@@ -14,12 +14,69 @@
#include "block/block_int.h"
#include "sysemu/replay.h"
#include "qapi/error.h"
+#include "qapi/qmp/qstring.h"
typedef struct Request {
Coroutine *co;
QEMUBH *bh;
} Request;
+static BlockDriverState *blkreplay_append_snapshot(BlockDriverState *bs,
+ Error **errp)
+{
+ int ret;
+ BlockDriverState *bs_snapshot;
+ int64_t total_size;
+ QemuOpts *opts = NULL;
+ char tmp_filename[PATH_MAX + 1];
+ QDict *snapshot_options = qdict_new();
+
+ /* Prepare options QDict for the overlay file */
+ qdict_put(snapshot_options, "file.driver", qstring_from_str("file"));
+ qdict_put(snapshot_options, "driver", qstring_from_str("qcow2"));
+
+ /* Create temporary file */
+ ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not get temporary filename");
+ goto out;
+ }
+ qdict_put(snapshot_options, "file.filename",
+ qstring_from_str(tmp_filename));
+
+ /* Get the required size from the image */
+ total_size = bdrv_getlength(bs);
+ if (total_size < 0) {
+ error_setg_errno(errp, -total_size, "Could not get image size");
+ goto out;
+ }
+
+ opts = qemu_opts_create(bdrv_qcow2.create_opts, NULL, 0, &error_abort);
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size, &error_abort);
+ ret = bdrv_create(&bdrv_qcow2, tmp_filename, opts, errp);
+ qemu_opts_del(opts);
+ if (ret < 0) {
+ error_prepend(errp, "Could not create temporary overlay '%s': ",
+ tmp_filename);
+ goto out;
+ }
+
+ bs_snapshot = bdrv_open(NULL, NULL, snapshot_options,
+ BDRV_O_RDWR | BDRV_O_TEMPORARY, errp);
+ snapshot_options = NULL;
+ if (!bs_snapshot) {
+ goto out;
+ }
+
+ bdrv_append(bs_snapshot, bs, errp);
+
+ return bs_snapshot;
+
+out:
+ QDECREF(snapshot_options);
+ return NULL;
+}
+
static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
@@ -35,6 +92,14 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
+ /* Add temporary snapshot to preserve the image */
+ if (!replay_snapshot
+ && !blkreplay_append_snapshot(bs->file->bs, &local_err)) {
+ ret = -EINVAL;
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
ret = 0;
fail:
if (ret < 0) {
@@ -3,6 +3,7 @@
#include "sysemu/sysemu.h"
ReplayMode replay_mode;
+char *replay_snapshot;
int64_t replay_save_clock(unsigned int kind, int64_t clock)
{
@@ -4492,7 +4492,7 @@ int main(int argc, char **argv, char **envp)
qapi_free_BlockdevOptions(bdo->bdo);
g_free(bdo);
}
- if (snapshot || replay_mode != REPLAY_MODE_NONE) {
+ if (snapshot) {
qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot,
NULL, NULL);
}
This patch allows using '-snapshot' behavior in record/replay mode. blkreplay layer creates temporary overlays on top of underlaying disk images. It is needed, because creating an overlay over blkreplay breaks the determinism. This patch creates similar temporary overlay (when it is needed) under the blkreplay driver. Therefore all block operations are controlled by blkreplay. Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> --- block/blkreplay.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++ stubs/replay.c | 1 + vl.c | 2 +- 3 files changed, 67 insertions(+), 1 deletion(-)