qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH 05/22] Block drivers changes


From: Pavel Dovgaluk
Subject: [Qemu-devel] [RFC PATCH 05/22] Block drivers changes
Date: Tue, 1 Jul 2014 15:21:19 +0400

Modifications of block devices performed to support deterministic replay.

First group of modifications create overlay files for every disk image used
in recording mode. All checkpoints and disk modifications are written into
these overlays and thus replay can start from the same disk state as record did.

Second group of modifications just reuses deterministic bottom halves.

Signed-off-by: Pavel Dovgalyuk <address@hidden>
---

diff --git a/block.c b/block.c
index 6856c18..55cfa38
--- a/block.c
+++ b/block.c
@@ -34,7 +34,9 @@
 #include "block/qapi.h"
 #include "qmp-commands.h"
 #include "qemu/timer.h"
+#include "replay/replay.h"
 #include "qapi-event.h"
+#include "qemu/log.h"
 
 #ifdef CONFIG_BSD
 #include <sys/types.h>
@@ -83,7 +85,8 @@ static BlockDriverAIOCB 
*bdrv_co_aio_rw_vector(BlockDriverState *bs,
                                                BdrvRequestFlags flags,
                                                BlockDriverCompletionFunc *cb,
                                                void *opaque,
-                                               bool is_write);
+                                               bool is_write,
+                                               bool aio_replay);
 static void coroutine_fn bdrv_co_do_rw(void *opaque);
 static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
     int64_t sector_num, int nb_sectors, BdrvRequestFlags flags);
@@ -880,7 +883,7 @@ static void bdrv_assign_node_name(BlockDriverState *bs,
  *
  * Removes all processed options from *options.
  */
-static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
+int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
     QDict *options, int flags, BlockDriver *drv, Error **errp)
 {
     int ret, open_flags;
@@ -1209,7 +1212,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict 
*options, Error **errp)
     assert(bs->backing_hd == NULL);
     ret = bdrv_open(&backing_hd,
                     *backing_filename ? backing_filename : NULL, NULL, options,
-                    bdrv_backing_flags(bs->open_flags), back_drv, &local_err);
+                    bdrv_backing_flags(bs->open_flags), back_drv, &local_err, 
NULL);
     if (ret < 0) {
         bdrv_unref(backing_hd);
         backing_hd = NULL;
@@ -1244,7 +1247,7 @@ free_exit:
  */
 int bdrv_open_image(BlockDriverState **pbs, const char *filename,
                     QDict *options, const char *bdref_key, int flags,
-                    bool allow_none, Error **errp)
+                    bool allow_none, Error **errp, const char *fname_suffix)
 {
     QDict *image_options;
     int ret;
@@ -1271,14 +1274,14 @@ int bdrv_open_image(BlockDriverState **pbs, const char 
*filename,
         goto done;
     }
 
-    ret = bdrv_open(pbs, filename, reference, image_options, flags, NULL, 
errp);
+    ret = bdrv_open(pbs, filename, reference, image_options, flags, NULL, 
errp, fname_suffix);
 
 done:
     qdict_del(options, bdref_key);
     return ret;
 }
 
-int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
+int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp, 
const char
*fname_suffix)
 {
     /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
     char *tmp_filename = g_malloc0(PATH_MAX + 1);
@@ -1303,18 +1306,31 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int 
flags, Error **errp)
     total_size &= BDRV_SECTOR_MASK;
 
     /* Create the temporary image */
-    ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
-    if (ret < 0) {
-        error_setg_errno(errp, -ret, "Could not get temporary filename");
-        goto out;
+    /* We will not delete created file in replay mode */
+    if (replay_mode != REPLAY_NONE && fname_suffix) {
+        ret = snprintf(tmp_filename, PATH_MAX + 1, "%s.%s", bs->filename, 
fname_suffix);
+        if (ret < 0) {
+            return;
+        }
+    } else {
+        ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
+        if (ret < 0) {
+            error_setg_errno(errp, -ret, "Could not get temporary filename");
+            goto out;
+        }
     }
 
     bdrv_qcow2 = bdrv_find_format("qcow2");
     opts = qemu_opts_create(bdrv_qcow2->create_opts, NULL, 0,
                             &error_abort);
     qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size);
-    ret = bdrv_create(bdrv_qcow2, tmp_filename, opts, &local_err);
+    if (replay_mode == REPLAY_PLAY) {
+        ret = 0;
+    } else {
+        ret = bdrv_create(bdrv_qcow2, tmp_filename, opts, &local_err);
+    }
     qemu_opts_del(opts);
+
     if (ret < 0) {
         error_setg_errno(errp, -ret, "Could not create temporary overlay "
                          "'%s': %s", tmp_filename,
@@ -1333,7 +1349,7 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int 
flags, Error **errp)
     bs_snapshot = bdrv_new("", &error_abort);
 
     ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
-                    flags, bdrv_qcow2, &local_err);
+                    flags, bdrv_qcow2, &local_err, NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         goto out;
@@ -1363,7 +1379,7 @@ out:
  */
 int bdrv_open(BlockDriverState **pbs, const char *filename,
               const char *reference, QDict *options, int flags,
-              BlockDriver *drv, Error **errp)
+              BlockDriver *drv, Error **errp, const char *fname_suffix)
 {
     int ret;
     BlockDriverState *file = NULL, *bs;
@@ -1444,13 +1460,16 @@ int bdrv_open(BlockDriverState **pbs, const char 
*filename,
         }
         if (flags & BDRV_O_SNAPSHOT) {
             snapshot_flags = bdrv_temp_snapshot_flags(flags);
+        if ((flags & BDRV_O_REPLAY_PLAY) || (flags & BDRV_O_REPLAY_SAVE)) {
+            snapshot_flags &= ~BDRV_O_TEMPORARY;
+        }
             flags = bdrv_backing_flags(flags);
         }
 
         assert(file == NULL);
         ret = bdrv_open_image(&file, filename, options, "file",
                               bdrv_inherited_flags(flags),
-                              true, &local_err);
+                              true, &local_err, NULL);
         if (ret < 0) {
             goto fail;
         }
@@ -1493,7 +1512,7 @@ int bdrv_open(BlockDriverState **pbs, const char 
*filename,
     /* For snapshot=on, create a temporary qcow2 overlay. bs points to the
      * temporary snapshot afterwards. */
     if (snapshot_flags) {
-        ret = bdrv_append_temp_snapshot(bs, snapshot_flags, &local_err);
+        ret = bdrv_append_temp_snapshot(bs, snapshot_flags, &local_err, 
fname_suffix);
         if (local_err) {
             goto close_and_fail;
         }
@@ -1896,8 +1915,12 @@ void bdrv_drain_all(void)
     /* Always run first iteration so any pending completion BHs run */
     bool busy = true;
     BlockDriverState *bs;
-
+    bool play = replay_mode == REPLAY_PLAY && replay_get_play_submode() != 
REPLAY_PLAY_CHANGED;
     while (busy) {
+        if (!replay_checkpoint(8)) {
+            // Do not wait anymore, we stopped at some place in the middle of 
execution during
replay
+            return;
+        }
         busy = false;
 
         QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
@@ -1909,10 +1932,14 @@ void bdrv_drain_all(void)
             bs_busy = bdrv_requests_pending(bs);
             bs_busy |= aio_poll(aio_context, bs_busy);
             aio_context_release(aio_context);
-
             busy |= bs_busy;
         }
     }
+    if (play) {
+        while (replay_checkpoint(8)) {
+            /* Nothing */
+        }
+    }
 }
 
 /* make a BlockDriverState anonymous by removing from bdrv_state and
@@ -2821,7 +2848,7 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags 
flags)
     int64_t target_size;
     int64_t ret, nb_sectors, sector_num = 0;
     int n;
-
+    
     target_size = bdrv_getlength(bs);
     if (target_size < 0) {
         return target_size;
@@ -4352,7 +4379,17 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, 
int64_t sector_num,
     trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
 
     return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
-                                 cb, opaque, false);
+                                 cb, opaque, false, false);
+}
+
+BlockDriverAIOCB *bdrv_aio_readv_replay(BlockDriverState *bs, int64_t 
sector_num,
+                                 QEMUIOVector *qiov, int nb_sectors,
+                                 BlockDriverCompletionFunc *cb, void *opaque)
+{
+    trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
+
+    return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
+                                 cb, opaque, false, true);
 }
 
 BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
@@ -4362,7 +4399,17 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, 
int64_t sector_num,
     trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
 
     return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
-                                 cb, opaque, true);
+                                 cb, opaque, true, false);
+}
+
+BlockDriverAIOCB *bdrv_aio_writev_replay(BlockDriverState *bs, int64_t 
sector_num,
+                                  QEMUIOVector *qiov, int nb_sectors,
+                                  BlockDriverCompletionFunc *cb, void *opaque)
+{
+    trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
+
+    return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
+                                 cb, opaque, true, true);
 }
 
 BlockDriverAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs,
@@ -4373,10 +4420,12 @@ BlockDriverAIOCB 
*bdrv_aio_write_zeroes(BlockDriverState *bs,
 
     return bdrv_co_aio_rw_vector(bs, sector_num, NULL, nb_sectors,
                                  BDRV_REQ_ZERO_WRITE | flags,
-                                 cb, opaque, true);
+                                 cb, opaque, true, true);
 }
 
 
+
+
 typedef struct MultiwriteCB {
     int error;
     int num_requests;
@@ -4509,7 +4558,7 @@ static int multiwrite_merge(BlockDriverState *bs, 
BlockRequest *reqs,
  * requests. However, the fields opaque and error are left unmodified as they
  * are used to signal failure for a single request to the caller.
  */
-int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
+int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int 
num_reqs, bool replay)
 {
     MultiwriteCB *mcb;
     int i;
@@ -4547,7 +4596,7 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, 
BlockRequest *reqs, int
num_reqs)
         bdrv_co_aio_rw_vector(bs, reqs[i].sector, reqs[i].qiov,
                               reqs[i].nb_sectors, reqs[i].flags,
                               multiwrite_cb, mcb,
-                              true);
+                              true, replay);
     }
 
     return 0;
@@ -4696,7 +4745,11 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque)
             acb->req.nb_sectors, acb->req.qiov, acb->req.flags);
     }
 
-    acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
+    if (acb->common.replay) {
+        acb->bh = aio_bh_new_replay(bdrv_get_aio_context(bs), bdrv_co_em_bh, 
acb,
acb->common.replay_step);
+    } else {
+        acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
+    }
     qemu_bh_schedule(acb->bh);
 }
 
@@ -4707,7 +4760,8 @@ static BlockDriverAIOCB 
*bdrv_co_aio_rw_vector(BlockDriverState *bs,
                                                BdrvRequestFlags flags,
                                                BlockDriverCompletionFunc *cb,
                                                void *opaque,
-                                               bool is_write)
+                                               bool is_write,
+                                               bool aio_replay)
 {
     Coroutine *co;
     BlockDriverAIOCBCoroutine *acb;
@@ -4719,6 +4773,10 @@ static BlockDriverAIOCB 
*bdrv_co_aio_rw_vector(BlockDriverState *bs,
     acb->req.flags = flags;
     acb->is_write = is_write;
     acb->done = NULL;
+    acb->common.replay = aio_replay;
+    if (aio_replay) {
+        acb->common.replay_step = replay_get_current_step();
+    }
 
     co = qemu_coroutine_create(bdrv_co_do_rw);
     qemu_coroutine_enter(co, acb);
@@ -4732,7 +4790,12 @@ static void coroutine_fn bdrv_aio_flush_co_entry(void 
*opaque)
     BlockDriverState *bs = acb->common.bs;
 
     acb->req.error = bdrv_co_flush(bs);
-    acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
+    if (acb->common.replay) {
+        acb->bh = aio_bh_new_replay(bdrv_get_aio_context(bs), bdrv_co_em_bh, 
acb,
acb->common.replay_step);
+    }
+    else
+        acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
+
     qemu_bh_schedule(acb->bh);
 }
 
@@ -4753,6 +4816,25 @@ BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
     return &acb->common;
 }
 
+BlockDriverAIOCB *bdrv_aio_flush_replay(BlockDriverState *bs,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    trace_bdrv_aio_flush(bs, opaque);
+
+    Coroutine *co;
+    BlockDriverAIOCBCoroutine *acb;
+
+    acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
+    acb->done = NULL;
+    acb->common.replay = true;
+    acb->common.replay_step = replay_get_current_step();
+
+    co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
+    qemu_coroutine_enter(co, acb);
+
+    return &acb->common;
+}
+
 static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque)
 {
     BlockDriverAIOCBCoroutine *acb = opaque;
@@ -4776,6 +4858,7 @@ BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
     acb->req.sector = sector_num;
     acb->req.nb_sectors = nb_sectors;
     acb->done = NULL;
+    
     co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
     qemu_coroutine_enter(co, acb);
 
@@ -4803,6 +4886,8 @@ void *qemu_aio_get(const AIOCBInfo *aiocb_info, 
BlockDriverState *bs,
     acb->bs = bs;
     acb->cb = cb;
     acb->opaque = opaque;
+    acb->replay_step = 0;
+    acb->replay = false;
     return acb;
 }
 
@@ -5582,7 +5667,7 @@ void bdrv_img_create(const char *filename, const char 
*fmt,
 
             bs = NULL;
             ret = bdrv_open(&bs, backing_file, NULL, NULL, back_flags,
-                            backing_drv, &local_err);
+                            backing_drv, &local_err, NULL);
             if (ret < 0) {
                 error_setg_errno(errp, -ret, "Could not open '%s': %s",
                                  backing_file,
diff --git a/block/blkdebug.c b/block/blkdebug.c
index f51407d..151538a 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -412,7 +412,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict 
*options, int flags,
     /* Open the backing file */
     assert(bs->file == NULL);
     ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, 
"image",
-                          flags | BDRV_O_PROTOCOL, false, &local_err);
+                          flags | BDRV_O_PROTOCOL, false, &local_err, NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         goto out;
diff --git a/block/blkverify.c b/block/blkverify.c
index 621b785..94d7db7
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -138,7 +138,7 @@ static int blkverify_open(BlockDriverState *bs, QDict 
*options, int flags,
     /* Open the raw file */
     assert(bs->file == NULL);
     ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-raw"), options,
-                          "raw", flags | BDRV_O_PROTOCOL, false, &local_err);
+                          "raw", flags | BDRV_O_PROTOCOL, false, &local_err, 
NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         goto fail;
@@ -147,7 +147,7 @@ static int blkverify_open(BlockDriverState *bs, QDict 
*options, int flags,
     /* Open the test file */
     assert(s->test_file == NULL);
     ret = bdrv_open_image(&s->test_file, qemu_opt_get(opts, "x-image"), 
options,
-                          "test", flags, false, &local_err);
+                          "test", flags, false, &local_err, NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         s->test_file = NULL;
diff --git a/block/cow.c b/block/cow.c
index 8f81ee6..0efe03c 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -346,7 +346,7 @@ static int cow_create(const char *filename, QemuOpts *opts, 
Error **errp)
 
     cow_bs = NULL;
     ret = bdrv_open(&cow_bs, filename, NULL, NULL,
-                    BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
+                    BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err, NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         goto exit;
diff --git a/block/qcow.c b/block/qcow.c
index a874056..6e21cea 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -720,7 +720,7 @@ static int qcow_create(const char *filename, QemuOpts 
*opts, Error **errp)
 
     qcow_bs = NULL;
     ret = bdrv_open(&qcow_bs, filename, NULL, NULL,
-                    BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
+                    BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err, NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         goto cleanup;
diff --git a/block/qcow2.c b/block/qcow2.c
index 67e55c9..1e767bb
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -31,7 +31,9 @@
 #include "qapi/qmp/qerror.h"
 #include "qapi/qmp/qbool.h"
 #include "trace.h"
+#include "replay/replay.h"
 #include "qemu/option_int.h"
+#include "qemu/log.h"
 
 /*
   Differences with QCOW:
@@ -988,9 +990,10 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState 
*bs, int64_t
sector_num,
     uint8_t *cluster_data = NULL;
 
     qemu_iovec_init(&hd_qiov, qiov->niov);
+    hd_qiov.replay = qiov->replay;
+    hd_qiov.replay_step = qiov->replay_step;
 
     qemu_co_mutex_lock(&s->lock);
-
     while (remaining_sectors != 0) {
 
         /* prepare next request */
@@ -1131,6 +1134,8 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState 
*bs,
                                  remaining_sectors);
 
     qemu_iovec_init(&hd_qiov, qiov->niov);
+    hd_qiov.replay = qiov->replay;
+    hd_qiov.replay_step = qiov->replay_step;
 
     s->cluster_cache_offset = -1; /* disable compressed cache */
 
@@ -1635,7 +1640,7 @@ static int qcow2_create2(const char *filename, int64_t 
total_size,
 
     bs = NULL;
     ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
-                    NULL, &local_err);
+                    NULL, &local_err, NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         return ret;
@@ -1697,7 +1702,7 @@ static int qcow2_create2(const char *filename, int64_t 
total_size,
     BlockDriver* drv = bdrv_find_format("qcow2");
     assert(drv != NULL);
     ret = bdrv_open(&bs, filename, NULL, NULL,
-        BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv, &local_err);
+        BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv, &local_err, 
NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         goto out;
@@ -1749,7 +1754,7 @@ static int qcow2_create2(const char *filename, int64_t 
total_size,
     /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */
     ret = bdrv_open(&bs, filename, NULL, NULL,
                     BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING,
-                    drv, &local_err);
+                    drv, &local_err, NULL);
     if (local_err) {
         error_propagate(errp, local_err);
         goto out;
diff --git a/block/qed.c b/block/qed.c
index eddae92..4cbd2f0 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -595,7 +595,7 @@ static int qed_create(const char *filename, uint32_t 
cluster_size,
     bs = NULL;
     ret = bdrv_open(&bs, filename, NULL, NULL,
                     BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, NULL,
-                    &local_err);
+                    &local_err, NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         return ret;
diff --git a/block/raw-posix.c b/block/raw-posix.c
index dacf4fb..49c3e37 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1022,7 +1022,8 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState 
*bs, int fd,
 
     trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
     pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
-    return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
+    return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque, 
+            qiov ? qiov->replay : false, qiov ? qiov->replay_step : 0);
 }
 
 static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
@@ -1779,7 +1780,7 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState 
*bs,
     acb->aio_ioctl_buf = buf;
     acb->aio_ioctl_cmd = req;
     pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
-    return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
+    return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque, false, 0);
 }
 
 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
diff --git a/block/raw-win32.c b/block/raw-win32.c
index 902eab6..239fde0 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -31,6 +31,8 @@
 #include "qemu/iov.h"
 #include <windows.h>
 #include <winioctl.h>
+#include "qemu/log.h"
+#include "replay/replay.h"
 
 #define FTYPE_FILE 0
 #define FTYPE_CD     1
@@ -144,11 +146,10 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState 
*bs, HANDLE hfile,
 {
     RawWin32AIOData *acb = g_slice_new(RawWin32AIOData);
     ThreadPool *pool;
-
     acb->bs = bs;
     acb->hfile = hfile;
     acb->aio_type = type;
-
+    
     if (qiov) {
         acb->aio_iov = qiov->iov;
         acb->aio_niov = qiov->niov;
@@ -158,7 +159,8 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, 
HANDLE hfile,
 
     trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
     pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
-    return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
+    return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque, 
+            qiov ? qiov->replay : false, qiov ? qiov->replay_step : 0);
 }
 
 int qemu_ftruncate64(int fd, int64_t length)
diff --git a/block/vmdk.c b/block/vmdk.c
index d0de019..26ae9c0
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -809,7 +809,7 @@ static int vmdk_parse_extents(const char *desc, 
BlockDriverState *bs,
                 desc_file_path, fname);
         extent_file = NULL;
         ret = bdrv_open(&extent_file, extent_path, NULL, NULL,
-                        bs->open_flags | BDRV_O_PROTOCOL, NULL, errp);
+                        bs->open_flags | BDRV_O_PROTOCOL, NULL, errp, NULL);
         if (ret) {
             return ret;
         }
@@ -1547,7 +1547,7 @@ static int vmdk_create_extent(const char *filename, 
int64_t filesize,
 
     assert(bs == NULL);
     ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
-                    NULL, &local_err);
+                    NULL, &local_err, NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         goto exit;
@@ -1805,7 +1805,7 @@ static int vmdk_create(const char *filename, QemuOpts 
*opts, Error **errp)
     if (backing_file) {
         BlockDriverState *bs = NULL;
         ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_NO_BACKING, NULL,
-                        errp);
+                        errp, NULL);
         if (ret != 0) {
             goto exit;
         }
@@ -1881,7 +1881,7 @@ static int vmdk_create(const char *filename, QemuOpts 
*opts, Error **errp)
     }
     assert(new_bs == NULL);
     ret = bdrv_open(&new_bs, filename, NULL, NULL,
-                    BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
+                    BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err, NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         goto exit;
diff --git a/block/vvfat.c b/block/vvfat.c
index 70176b1..2d09eca
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -971,7 +971,6 @@ static int init_directories(BDRVVVFATState* s,
     bootsector->u.fat16.current_head=0;
     bootsector->u.fat16.signature=0x29;
     bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
-
     memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
     memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   
":s->fat_type==16?"FAT16   ":"FAT32
"),8);
     bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
@@ -2939,7 +2938,7 @@ static int enable_write_target(BDRVVVFATState *s, Error 
**errp)
     s->qcow = NULL;
     ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, NULL,
                     BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
-                    bdrv_qcow, errp);
+                    bdrv_qcow, errp, NULL);
     if (ret < 0) {
         goto err;
     }
diff --git a/block/win32-aio.c b/block/win32-aio.c
index 8e417f7..8ebdbb5 100644
--- a/block/win32-aio.c
+++ b/block/win32-aio.c
@@ -31,6 +31,8 @@
 #include "qemu/iov.h"
 #include <windows.h>
 #include <winioctl.h>
+#include "replay/replay.h"
+#include "qemu/log.h"
 
 #define FTYPE_FILE 0
 #define FTYPE_CD     1
diff --git a/blockdev.c b/blockdev.c
index 69b7c2a..8d8c04d
--- a/blockdev.c
+++ b/blockdev.c
@@ -44,6 +44,7 @@
 #include "qmp-commands.h"
 #include "trace.h"
 #include "sysemu/arch_init.h"
+#include "replay/replay.h"
 
 static QTAILQ_HEAD(drivelist, DriveInfo) drives = 
QTAILQ_HEAD_INITIALIZER(drives);
 
@@ -519,8 +520,16 @@ static DriveInfo *blockdev_init(const char *file, QDict 
*bs_opts,
 
     bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
 
+    /* Setup replay parameters */
+    /* Use current file as backing file */
+    if (replay_mode == REPLAY_PLAY) {
+        bdrv_flags |= BDRV_O_REPLAY_PLAY;
+    } else if (replay_mode == REPLAY_SAVE) {
+        bdrv_flags |= BDRV_O_REPLAY_SAVE;
+    }
+
     QINCREF(bs_opts);
-    ret = bdrv_open(&dinfo->bdrv, file, NULL, bs_opts, bdrv_flags, drv, 
&error);
+    ret = bdrv_open(&dinfo->bdrv, file, NULL, bs_opts, bdrv_flags, drv, &error,
replay_image_suffix);
 
     if (ret < 0) {
         error_setg(errp, "could not open disk image %s: %s",
@@ -880,7 +889,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType 
block_default_type)
         qdict_put(bs_opts, "id", qstring_from_str(new_id));
         g_free(new_id);
     }
-
+    
     /* Add virtio block device */
     devaddr = qemu_opt_get(legacy_opts, "addr");
     if (devaddr && type != IF_VIRTIO) {
@@ -952,7 +961,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType 
block_default_type)
     dinfo->bus = bus_id;
     dinfo->unit = unit_id;
     dinfo->devaddr = devaddr;
-
+    
     dinfo->serial = g_strdup(serial);
 
     switch(type) {
@@ -1367,7 +1376,7 @@ static void external_snapshot_prepare(BlkTransactionState 
*common,
      * extended QMP command? */
     assert(state->new_bs == NULL);
     ret = bdrv_open(&state->new_bs, new_image_file, NULL, options,
-                    flags | BDRV_O_NO_BACKING, drv, &local_err);
+                    flags | BDRV_O_NO_BACKING, drv, &local_err, NULL);
     /* We will manually add the backing_hd field to the bs later */
     if (ret != 0) {
         error_propagate(errp, local_err);
@@ -1616,7 +1625,7 @@ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, 
const char
*filename,
     Error *local_err = NULL;
     int ret;
 
-    ret = bdrv_open(&bs, filename, NULL, NULL, bdrv_flags, drv, &local_err);
+    ret = bdrv_open(&bs, filename, NULL, NULL, bdrv_flags, drv, &local_err, 
NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         return;
@@ -2075,7 +2084,7 @@ void qmp_drive_backup(const char *device, const char 
*target,
     }
 
     target_bs = NULL;
-    ret = bdrv_open(&target_bs, target, NULL, NULL, flags, drv, &local_err);
+    ret = bdrv_open(&target_bs, target, NULL, NULL, flags, drv, &local_err, 
NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         return;
@@ -2249,7 +2258,7 @@ void qmp_drive_mirror(const char *device, const char 
*target,
      */
     target_bs = NULL;
     ret = bdrv_open(&target_bs, target, NULL, options,
-                    flags | BDRV_O_NO_BACKING, drv, &local_err);
+                    flags | BDRV_O_NO_BACKING, drv, &local_err, NULL);
     if (ret < 0) {
         error_propagate(errp, local_err);
         return;

diff --git a/include/block/block.h b/include/block/block.h
index 7e92f54..f1f897d
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -110,6 +110,8 @@ typedef enum {
 #define BDRV_O_PROTOCOL    0x8000  /* if no block driver is explicitly given:
                                       select an appropriate protocol driver,
                                       ignoring the format layer */
+#define BDRV_O_REPLAY_SAVE 0x10000 /* record mode */
+#define BDRV_O_REPLAY_PLAY 0x20000 /* replay mode */
 
 #define BDRV_O_CACHE_MASK  (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
 
@@ -207,17 +209,20 @@ BlockDriverState *bdrv_new(const char *device_name, Error 
**errp);
 void bdrv_make_anon(BlockDriverState *bs);
 void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old);
 void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
+void extract_subqdict(QDict *src, QDict **dst, const char *start);
+int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
+    QDict *options, int flags, BlockDriver *drv, Error **errp);
 int bdrv_parse_cache_flags(const char *mode, int *flags);
 int bdrv_parse_discard_flags(const char *mode, int *flags);
 int bdrv_open_image(BlockDriverState **pbs, const char *filename,
                     QDict *options, const char *bdref_key, int flags,
-                    bool allow_none, Error **errp);
+                    bool allow_none, Error **errp, const char *fname_suffix);
 void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
 int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
-int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp);
+int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp, 
const char
*fname_suffix);
 int bdrv_open(BlockDriverState **pbs, const char *filename,
               const char *reference, QDict *options, int flags,
-              BlockDriver *drv, Error **errp);
+              BlockDriver *drv, Error **errp, const char *fname_suffix);
 BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
                                     BlockDriverState *bs, int flags);
 int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
@@ -324,11 +329,19 @@ typedef void BlockDriverDirtyHandler(BlockDriverState 
*bs, int64_t sector,
 BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
                                  QEMUIOVector *iov, int nb_sectors,
                                  BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_readv_replay(BlockDriverState *bs, int64_t 
sector_num,
+                                 QEMUIOVector *iov, int nb_sectors,
+                                 BlockDriverCompletionFunc *cb, void *opaque);
 BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
                                   QEMUIOVector *iov, int nb_sectors,
                                   BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_writev_replay(BlockDriverState *bs, int64_t 
sector_num,
+                                  QEMUIOVector *iov, int nb_sectors,
+                                  BlockDriverCompletionFunc *cb, void *opaque);
 BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
                                  BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_flush_replay(BlockDriverState *bs,
+                                 BlockDriverCompletionFunc *cb, void *opaque);
 BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
                                    int64_t sector_num, int nb_sectors,
                                    BlockDriverCompletionFunc *cb, void 
*opaque);
@@ -348,7 +361,7 @@ typedef struct BlockRequest {
 } BlockRequest;
 
 int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs,
-    int num_reqs);
+    int num_reqs, bool replay);
 
 /* sg packet commands */
 int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);

diff --git a/qemu-img.c b/qemu-img.c
index c98896b..d38c398
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -321,7 +321,7 @@ static BlockDriverState *bdrv_new_open(const char *id,
         drv = NULL;
     }
 
-    ret = bdrv_open(&bs, filename, NULL, NULL, flags, drv, &local_err);
+    ret = bdrv_open(&bs, filename, NULL, NULL, flags, drv, &local_err, NULL);
     if (ret < 0) {
         error_report("Could not open '%s': %s", filename,
                      error_get_pretty(local_err));
@@ -2384,7 +2384,7 @@ static int img_rebase(int argc, char **argv)
         bs_old_backing = bdrv_new("old_backing", &error_abort);
         bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
         ret = bdrv_open(&bs_old_backing, backing_name, NULL, NULL, 
BDRV_O_FLAGS,
-                        old_backing_drv, &local_err);
+                        old_backing_drv, &local_err, NULL);
         if (ret) {
             error_report("Could not open old backing file '%s': %s",
                          backing_name, error_get_pretty(local_err));
@@ -2394,7 +2394,7 @@ static int img_rebase(int argc, char **argv)
         if (out_baseimg[0]) {
             bs_new_backing = bdrv_new("new_backing", &error_abort);
             ret = bdrv_open(&bs_new_backing, out_baseimg, NULL, NULL,
-                            BDRV_O_FLAGS, new_backing_drv, &local_err);
+                            BDRV_O_FLAGS, new_backing_drv, &local_err, NULL);
             if (ret) {
                 error_report("Could not open new backing file '%s': %s",
                              out_baseimg, error_get_pretty(local_err));
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 60c1ceb..f8a809a 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -592,7 +592,7 @@ static int do_aio_multiwrite(BlockDriverState *bs, 
BlockRequest* reqs,
         *total += reqs[i].qiov->size;
     }
 
-    ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
+    ret = bdrv_aio_multiwrite(bs, reqs, num_reqs, false);
     if (ret < 0) {
         return ret;
     }
diff --git a/qemu-io.c b/qemu-io.c
index b55a550..849067d
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -60,7 +60,7 @@ static int openfile(char *name, int flags, int growable, 
QDict *opts)
 
     if (growable) {
         if (bdrv_open(&qemuio_bs, name, NULL, opts, flags | BDRV_O_PROTOCOL,
-                      NULL, &local_err))
+                      NULL, &local_err, NULL))
         {
             fprintf(stderr, "%s: can't open%s%s: %s\n", progname,
                     name ? " device " : "", name ?: "",
@@ -71,7 +71,7 @@ static int openfile(char *name, int flags, int growable, 
QDict *opts)
     } else {
         qemuio_bs = bdrv_new("hda", &error_abort);
 
-        if (bdrv_open(&qemuio_bs, name, NULL, opts, flags, NULL, &local_err)
+        if (bdrv_open(&qemuio_bs, name, NULL, opts, flags, NULL, &local_err, 
NULL)
             < 0)
         {
             fprintf(stderr, "%s: can't open%s%s: %s\n", progname,
diff --git a/qemu-nbd.c b/qemu-nbd.c
index ba60436..636ee97f
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -662,7 +662,7 @@ int main(int argc, char **argv)
     bs = bdrv_new("hda", &error_abort);
 
     srcpath = argv[optind];
-    ret = bdrv_open(&bs, srcpath, NULL, NULL, flags, drv, &local_err);
+    ret = bdrv_open(&bs, srcpath, NULL, NULL, flags, drv, &local_err, NULL);
     if (ret < 0) {
         errno = -ret;
         err(EXIT_FAILURE, "Failed to bdrv_open '%s': %s", argv[optind],




reply via email to

[Prev in Thread] Current Thread [Next in Thread]