From 059a9447e23ecc366d2305392e6c86edaa8394a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= Date: Tue, 17 Mar 2020 08:55:24 +0100 Subject: [PATCH] add bitmap drive-mirror patches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fabian Grünbichler Signed-off-by: Thomas Lamprecht --- ...d-support-for-sync-bitmap-mode-never.patch | 443 +++ ...-support-for-conditional-and-always-.patch | 83 + ...check-for-bitmap-mode-without-bitmap.patch | 33 + ...-to-bdrv_dirty_bitmap_merge_internal.patch | 45 + ...8-iotests-add-test-for-bitmap-mirror.patch | 3447 +++++++++++++++++ .../0039-mirror-move-some-checks-to-qmp.patch | 275 ++ debian/patches/series | 6 + 7 files changed, 4332 insertions(+) create mode 100644 debian/patches/pve/0034-drive-mirror-add-support-for-sync-bitmap-mode-never.patch create mode 100644 debian/patches/pve/0035-drive-mirror-add-support-for-conditional-and-always-.patch create mode 100644 debian/patches/pve/0036-mirror-add-check-for-bitmap-mode-without-bitmap.patch create mode 100644 debian/patches/pve/0037-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch create mode 100644 debian/patches/pve/0038-iotests-add-test-for-bitmap-mirror.patch create mode 100644 debian/patches/pve/0039-mirror-move-some-checks-to-qmp.patch diff --git a/debian/patches/pve/0034-drive-mirror-add-support-for-sync-bitmap-mode-never.patch b/debian/patches/pve/0034-drive-mirror-add-support-for-sync-bitmap-mode-never.patch new file mode 100644 index 0000000..50229d0 --- /dev/null +++ b/debian/patches/pve/0034-drive-mirror-add-support-for-sync-bitmap-mode-never.patch @@ -0,0 +1,443 @@ +From 1bfdb0492d8b70983342cf96576b294d60172e05 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 9 Jul 2019 21:12:21 -0400 +Subject: [PATCH qemu 34/39] drive-mirror: add support for sync=bitmap + mode=never +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds support for the "BITMAP" sync mode to drive-mirror and +blockdev-mirror. It adds support only for the BitmapSyncMode "never," +because it's the simplest mode. + +This mode simply uses a user-provided bitmap as an initial copy +manifest, and then does not clear any bits in the bitmap at the +conclusion of the operation. + +Any new writes dirtied during the operation are copied out, in contrast +to backup. Note that whether these writes are reflected in the bitmap +at the conclusion of the operation depends on whether that bitmap is +actually recording! + +This patch was originally based on one by Ma Haocong, but it has since +been modified pretty heavily. + +Suggested-by: Ma Haocong +Signed-off-by: Ma Haocong +Signed-off-by: John Snow +Signed-off-by: Fabian Grünbichler +--- + include/block/block_int.h | 4 +- + block/mirror.c | 98 ++++++++++++++++++++++++++++++------- + blockdev.c | 39 +++++++++++++-- + tests/test-block-iothread.c | 4 +- + qapi/block-core.json | 29 +++++++++-- + 5 files changed, 145 insertions(+), 29 deletions(-) + +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 43b00c15ac..bd2e11c4d9 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -1206,7 +1206,9 @@ void mirror_start(const char *job_id, BlockDriverState *bs, + BlockDriverState *target, const char *replaces, + int creation_flags, int64_t speed, + uint32_t granularity, int64_t buf_size, +- MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, ++ MirrorSyncMode mode, BdrvDirtyBitmap *bitmap, ++ BitmapSyncMode bitmap_mode, ++ BlockMirrorBackingMode backing_mode, + bool zero_target, + BlockdevOnError on_source_error, + BlockdevOnError on_target_error, +diff --git a/block/mirror.c b/block/mirror.c +index f0f2d9dff1..fd7f574365 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -49,7 +49,7 @@ typedef struct MirrorBlockJob { + BlockDriverState *to_replace; + /* Used to block operations on the drive-mirror-replace target */ + Error *replace_blocker; +- bool is_none_mode; ++ MirrorSyncMode sync_mode; + BlockMirrorBackingMode backing_mode; + /* Whether the target image requires explicit zero-initialization */ + bool zero_target; +@@ -64,6 +64,8 @@ typedef struct MirrorBlockJob { + size_t buf_size; + int64_t bdev_length; + unsigned long *cow_bitmap; ++ BdrvDirtyBitmap *sync_bitmap; ++ BitmapSyncMode bitmap_mode; + BdrvDirtyBitmap *dirty_bitmap; + BdrvDirtyBitmapIter *dbi; + uint8_t *buf; +@@ -668,7 +670,8 @@ static int mirror_exit_common(Job *job) + bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing, + &error_abort); + if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { +- BlockDriverState *backing = s->is_none_mode ? src : s->base; ++ BlockDriverState *backing; ++ backing = s->sync_mode == MIRROR_SYNC_MODE_NONE ? src : s->base; + if (backing_bs(target_bs) != backing) { + bdrv_set_backing_hd(target_bs, backing, &local_err); + if (local_err) { +@@ -750,6 +753,16 @@ static void mirror_abort(Job *job) + assert(ret == 0); + } + ++/* Always called after commit/abort. */ ++static void mirror_clean(Job *job) ++{ ++ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); ++ ++ if (s->sync_bitmap) { ++ bdrv_dirty_bitmap_set_busy(s->sync_bitmap, false); ++ } ++} ++ + static void coroutine_fn mirror_throttle(MirrorBlockJob *s) + { + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); +@@ -928,7 +941,8 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) + mirror_free_init(s); + + s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); +- if (!s->is_none_mode) { ++ if ((s->sync_mode == MIRROR_SYNC_MODE_TOP) || ++ (s->sync_mode == MIRROR_SYNC_MODE_FULL)) { + ret = mirror_dirty_init(s); + if (ret < 0 || job_is_cancelled(&s->common.job)) { + goto immediate_exit; +@@ -1160,6 +1174,7 @@ static const BlockJobDriver mirror_job_driver = { + .run = mirror_run, + .prepare = mirror_prepare, + .abort = mirror_abort, ++ .clean = mirror_clean, + .pause = mirror_pause, + .complete = mirror_complete, + }, +@@ -1175,6 +1190,7 @@ static const BlockJobDriver commit_active_job_driver = { + .run = mirror_run, + .prepare = mirror_prepare, + .abort = mirror_abort, ++ .clean = mirror_clean, + .pause = mirror_pause, + .complete = mirror_complete, + }, +@@ -1520,7 +1536,10 @@ static BlockJob *mirror_start_job( + BlockCompletionFunc *cb, + void *opaque, + const BlockJobDriver *driver, +- bool is_none_mode, BlockDriverState *base, ++ MirrorSyncMode sync_mode, ++ BdrvDirtyBitmap *bitmap, ++ BitmapSyncMode bitmap_mode, ++ BlockDriverState *base, + bool auto_complete, const char *filter_node_name, + bool is_mirror, MirrorCopyMode copy_mode, + Error **errp) +@@ -1533,10 +1552,39 @@ static BlockJob *mirror_start_job( + Error *local_err = NULL; + int ret; + +- if (granularity == 0) { +- granularity = bdrv_get_default_bitmap_granularity(target); ++ if (sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { ++ error_setg(errp, "Sync mode '%s' not supported", ++ MirrorSyncMode_str(sync_mode)); ++ return NULL; ++ } else if (sync_mode == MIRROR_SYNC_MODE_BITMAP) { ++ if (!bitmap) { ++ error_setg(errp, "Must provide a valid bitmap name for '%s'" ++ " sync mode", ++ MirrorSyncMode_str(sync_mode)); ++ return NULL; ++ } else if (bitmap_mode != BITMAP_SYNC_MODE_NEVER) { ++ error_setg(errp, ++ "Bitmap Sync Mode '%s' is not supported by Mirror", ++ BitmapSyncMode_str(bitmap_mode)); ++ } ++ } else if (bitmap) { ++ error_setg(errp, ++ "sync mode '%s' is not compatible with bitmaps", ++ MirrorSyncMode_str(sync_mode)); ++ return NULL; + } + ++ if (bitmap) { ++ if (granularity) { ++ error_setg(errp, "granularity (%d)" ++ "cannot be specified when a bitmap is provided", ++ granularity); ++ return NULL; ++ } ++ granularity = bdrv_dirty_bitmap_granularity(bitmap); ++ } else if (granularity == 0) { ++ granularity = bdrv_get_default_bitmap_granularity(target); ++ } + assert(is_power_of_2(granularity)); + + if (buf_size < 0) { +@@ -1640,7 +1688,9 @@ static BlockJob *mirror_start_job( + s->replaces = g_strdup(replaces); + s->on_source_error = on_source_error; + s->on_target_error = on_target_error; +- s->is_none_mode = is_none_mode; ++ s->sync_mode = sync_mode; ++ s->sync_bitmap = bitmap; ++ s->bitmap_mode = bitmap_mode; + s->backing_mode = backing_mode; + s->zero_target = zero_target; + s->copy_mode = copy_mode; +@@ -1660,6 +1710,18 @@ static BlockJob *mirror_start_job( + bdrv_disable_dirty_bitmap(s->dirty_bitmap); + } + ++ if (s->sync_bitmap) { ++ bdrv_dirty_bitmap_set_busy(s->sync_bitmap, true); ++ } ++ ++ if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) { ++ bdrv_merge_dirty_bitmap(s->dirty_bitmap, s->sync_bitmap, ++ NULL, &local_err); ++ if (local_err) { ++ goto fail; ++ } ++ } ++ + ret = block_job_add_bdrv(&s->common, "source", bs, 0, + BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE | + BLK_PERM_CONSISTENT_READ, +@@ -1713,6 +1775,9 @@ fail: + if (s->dirty_bitmap) { + bdrv_release_dirty_bitmap(s->dirty_bitmap); + } ++ if (s->sync_bitmap) { ++ bdrv_dirty_bitmap_set_busy(s->sync_bitmap, false); ++ } + job_early_fail(&s->common.job); + } + +@@ -1730,29 +1795,23 @@ void mirror_start(const char *job_id, BlockDriverState *bs, + BlockDriverState *target, const char *replaces, + int creation_flags, int64_t speed, + uint32_t granularity, int64_t buf_size, +- MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, ++ MirrorSyncMode mode, BdrvDirtyBitmap *bitmap, ++ BitmapSyncMode bitmap_mode, ++ BlockMirrorBackingMode backing_mode, + bool zero_target, + BlockdevOnError on_source_error, + BlockdevOnError on_target_error, + bool unmap, const char *filter_node_name, + MirrorCopyMode copy_mode, Error **errp) + { +- bool is_none_mode; + BlockDriverState *base; + +- if ((mode == MIRROR_SYNC_MODE_INCREMENTAL) || +- (mode == MIRROR_SYNC_MODE_BITMAP)) { +- error_setg(errp, "Sync mode '%s' not supported", +- MirrorSyncMode_str(mode)); +- return; +- } +- is_none_mode = mode == MIRROR_SYNC_MODE_NONE; + base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL; + mirror_start_job(job_id, bs, creation_flags, target, replaces, + speed, granularity, buf_size, backing_mode, zero_target, + on_source_error, on_target_error, unmap, NULL, NULL, +- &mirror_job_driver, is_none_mode, base, false, +- filter_node_name, true, copy_mode, errp); ++ &mirror_job_driver, mode, bitmap, bitmap_mode, base, ++ false, filter_node_name, true, copy_mode, errp); + } + + BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, +@@ -1778,7 +1837,8 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, + job_id, bs, creation_flags, base, NULL, speed, 0, 0, + MIRROR_LEAVE_BACKING_CHAIN, false, + on_error, on_error, true, cb, opaque, +- &commit_active_job_driver, false, base, auto_complete, ++ &commit_active_job_driver, MIRROR_SYNC_MODE_FULL, ++ NULL, 0, base, auto_complete, + filter_node_name, false, MIRROR_COPY_MODE_BACKGROUND, + &local_err); + if (local_err) { +diff --git a/blockdev.c b/blockdev.c +index e5310cb939..08285b9e86 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3763,6 +3763,10 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, + BlockDriverState *target, + bool has_replaces, const char *replaces, + enum MirrorSyncMode sync, ++ bool has_bitmap, ++ const char *bitmap_name, ++ bool has_bitmap_mode, ++ BitmapSyncMode bitmap_mode, + BlockMirrorBackingMode backing_mode, + bool zero_target, + bool has_speed, int64_t speed, +@@ -3781,6 +3785,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, + Error **errp) + { + int job_flags = JOB_DEFAULT; ++ BdrvDirtyBitmap *bitmap = NULL; + + if (!has_speed) { + speed = 0; +@@ -3835,6 +3840,29 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, + sync = MIRROR_SYNC_MODE_FULL; + } + ++ if (has_bitmap) { ++ if (granularity) { ++ error_setg(errp, "Granularity and bitmap cannot both be set"); ++ return; ++ } ++ ++ if (!has_bitmap_mode) { ++ error_setg(errp, "bitmap-mode must be specified if" ++ " a bitmap is provided"); ++ return; ++ } ++ ++ bitmap = bdrv_find_dirty_bitmap(bs, bitmap_name); ++ if (!bitmap) { ++ error_setg(errp, "Dirty bitmap '%s' not found", bitmap_name); ++ return; ++ } ++ ++ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { ++ return; ++ } ++ } ++ + if (has_replaces) { + BlockDriverState *to_replace_bs; + AioContext *replace_aio_context; +@@ -3872,8 +3900,8 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, + * and will allow to check whether the node still exist at mirror completion + */ + mirror_start(job_id, bs, target, +- has_replaces ? replaces : NULL, job_flags, +- speed, granularity, buf_size, sync, backing_mode, zero_target, ++ has_replaces ? replaces : NULL, job_flags, speed, granularity, ++ buf_size, sync, bitmap, bitmap_mode, backing_mode, zero_target, + on_source_error, on_target_error, unmap, filter_node_name, + copy_mode, errp); + } +@@ -4003,6 +4031,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) + + blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs, + arg->has_replaces, arg->replaces, arg->sync, ++ arg->has_bitmap, arg->bitmap, ++ arg->has_bitmap_mode, arg->bitmap_mode, + backing_mode, zero_target, + arg->has_speed, arg->speed, + arg->has_granularity, arg->granularity, +@@ -4025,6 +4055,8 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, + const char *device, const char *target, + bool has_replaces, const char *replaces, + MirrorSyncMode sync, ++ bool has_bitmap, const char *bitmap, ++ bool has_bitmap_mode, BitmapSyncMode bitmap_mode, + bool has_speed, int64_t speed, + bool has_granularity, uint32_t granularity, + bool has_buf_size, int64_t buf_size, +@@ -4068,7 +4100,8 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, + } + + blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs, +- has_replaces, replaces, sync, backing_mode, ++ has_replaces, replaces, sync, has_bitmap, ++ bitmap, has_bitmap_mode, bitmap_mode, backing_mode, + zero_target, has_speed, speed, + has_granularity, granularity, + has_buf_size, buf_size, +diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c +index 0c861809f0..da87a67a57 100644 +--- a/tests/test-block-iothread.c ++++ b/tests/test-block-iothread.c +@@ -611,8 +611,8 @@ static void test_propagate_mirror(void) + + /* Start a mirror job */ + mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0, +- MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false, +- BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, ++ MIRROR_SYNC_MODE_NONE, NULL, 0, MIRROR_OPEN_BACKING_CHAIN, ++ false, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, + false, "filter_node", MIRROR_COPY_MODE_BACKGROUND, + &error_abort); + job = job_get("job0"); +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 0b987ad6e3..e2050bab1d 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -2086,10 +2086,19 @@ + # (all the disk, only the sectors allocated in the topmost image, or + # only new I/O). + # ++# @bitmap: The name of a bitmap to use for sync=bitmap mode. This argument must ++# be present for bitmap mode and absent otherwise. The bitmap's ++# granularity is used instead of @granularity (since 4.1). ++# ++# @bitmap-mode: Specifies the type of data the bitmap should contain after ++# the operation concludes. Must be present if sync is "bitmap". ++# Must NOT be present otherwise. (Since 4.1) ++# + # @granularity: granularity of the dirty bitmap, default is 64K + # if the image format doesn't have clusters, 4K if the clusters + # are smaller than that, else the cluster size. Must be a +-# power of 2 between 512 and 64M (since 1.4). ++# power of 2 between 512 and 64M. Must not be specified if ++# @bitmap is present (since 1.4). + # + # @buf-size: maximum amount of data in flight from source to + # target (since 1.4). +@@ -2127,7 +2136,9 @@ + { 'struct': 'DriveMirror', + 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', + '*format': 'str', '*node-name': 'str', '*replaces': 'str', +- 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode', ++ 'sync': 'MirrorSyncMode', '*bitmap': 'str', ++ '*bitmap-mode': 'BitmapSyncMode', ++ '*mode': 'NewImageMode', + '*speed': 'int', '*granularity': 'uint32', + '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', + '*on-target-error': 'BlockdevOnError', +@@ -2394,10 +2405,19 @@ + # (all the disk, only the sectors allocated in the topmost image, or + # only new I/O). + # ++# @bitmap: The name of a bitmap to use for sync=bitmap mode. This argument must ++# be present for bitmap mode and absent otherwise. The bitmap's ++# granularity is used instead of @granularity (since 4.1). ++# ++# @bitmap-mode: Specifies the type of data the bitmap should contain after ++# the operation concludes. Must be present if sync is "bitmap". ++# Must NOT be present otherwise. (Since 4.1) ++# + # @granularity: granularity of the dirty bitmap, default is 64K + # if the image format doesn't have clusters, 4K if the clusters + # are smaller than that, else the cluster size. Must be a +-# power of 2 between 512 and 64M ++# power of 2 between 512 and 64M . Must not be specified if ++# @bitmap is present. + # + # @buf-size: maximum amount of data in flight from source to + # target +@@ -2446,7 +2466,8 @@ + { 'command': 'blockdev-mirror', + 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', + '*replaces': 'str', +- 'sync': 'MirrorSyncMode', ++ 'sync': 'MirrorSyncMode', '*bitmap': 'str', ++ '*bitmap-mode': 'BitmapSyncMode', + '*speed': 'int', '*granularity': 'uint32', + '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', + '*on-target-error': 'BlockdevOnError', +-- +2.20.1 + diff --git a/debian/patches/pve/0035-drive-mirror-add-support-for-conditional-and-always-.patch b/debian/patches/pve/0035-drive-mirror-add-support-for-conditional-and-always-.patch new file mode 100644 index 0000000..3a2e5b9 --- /dev/null +++ b/debian/patches/pve/0035-drive-mirror-add-support-for-conditional-and-always-.patch @@ -0,0 +1,83 @@ +From 4c46f8b0f6fd8efba5e4d0b738b4f01ffcb92d33 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 9 Jul 2019 21:12:30 -0400 +Subject: [PATCH qemu 35/39] drive-mirror: add support for conditional and + always bitmap sync modes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Teach mirror two new tricks for using bitmaps: + +Always: no matter what, we synchronize the copy_bitmap back to the +sync_bitmap. In effect, this allows us resume a failed mirror at a later +date. + +Conditional: On success only, we sync the bitmap. This is akin to +incremental backup modes; we can use this bitmap to later refresh a +successfully created mirror. + +Signed-off-by: Fabian Grünbichler +--- + block/mirror.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index fd7f574365..40d174a625 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -645,8 +645,6 @@ static int mirror_exit_common(Job *job) + bdrv_unfreeze_backing_chain(mirror_top_bs, target_bs); + } + +- bdrv_release_dirty_bitmap(s->dirty_bitmap); +- + /* Make sure that the source BDS doesn't go away during bdrv_replace_node, + * before we can call bdrv_drained_end */ + bdrv_ref(src); +@@ -731,6 +729,18 @@ static int mirror_exit_common(Job *job) + blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort); + blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort); + ++ if (s->sync_bitmap) { ++ if (s->bitmap_mode == BITMAP_SYNC_MODE_ALWAYS || ++ (s->bitmap_mode == BITMAP_SYNC_MODE_ON_SUCCESS && ++ job->ret == 0 && ret == 0)) { ++ /* Success; synchronize copy back to sync. */ ++ bdrv_clear_dirty_bitmap(s->sync_bitmap, NULL); ++ bdrv_merge_dirty_bitmap(s->sync_bitmap, s->dirty_bitmap, ++ NULL, &error_abort); ++ } ++ } ++ bdrv_release_dirty_bitmap(s->dirty_bitmap); ++ + bs_opaque->job = NULL; + + bdrv_drained_end(src); +@@ -1562,10 +1572,6 @@ static BlockJob *mirror_start_job( + " sync mode", + MirrorSyncMode_str(sync_mode)); + return NULL; +- } else if (bitmap_mode != BITMAP_SYNC_MODE_NEVER) { +- error_setg(errp, +- "Bitmap Sync Mode '%s' is not supported by Mirror", +- BitmapSyncMode_str(bitmap_mode)); + } + } else if (bitmap) { + error_setg(errp, +@@ -1582,6 +1588,12 @@ static BlockJob *mirror_start_job( + return NULL; + } + granularity = bdrv_dirty_bitmap_granularity(bitmap); ++ ++ if (bitmap_mode != BITMAP_SYNC_MODE_NEVER) { ++ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) { ++ return NULL; ++ } ++ } + } else if (granularity == 0) { + granularity = bdrv_get_default_bitmap_granularity(target); + } +-- +2.20.1 + diff --git a/debian/patches/pve/0036-mirror-add-check-for-bitmap-mode-without-bitmap.patch b/debian/patches/pve/0036-mirror-add-check-for-bitmap-mode-without-bitmap.patch new file mode 100644 index 0000000..879e516 --- /dev/null +++ b/debian/patches/pve/0036-mirror-add-check-for-bitmap-mode-without-bitmap.patch @@ -0,0 +1,33 @@ +From daec2f64e120a23a8d263f7d058bd84c48397bc8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= +Date: Mon, 17 Feb 2020 11:59:20 +0100 +Subject: [PATCH qemu 36/39] mirror: add check for bitmap-mode without bitmap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +as one without the other does not make much sense with the current set +of modes. + +Signed-off-by: Fabian Grünbichler +--- + blockdev.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/blockdev.c b/blockdev.c +index 08285b9e86..768a0b0fd4 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3861,6 +3861,9 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, + if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { + return; + } ++ } else if (has_bitmap_mode) { ++ error_setg(errp, "Cannot specify bitmap sync mode without a bitmap"); ++ return; + } + + if (has_replaces) { +-- +2.20.1 + diff --git a/debian/patches/pve/0037-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch b/debian/patches/pve/0037-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch new file mode 100644 index 0000000..40d36e8 --- /dev/null +++ b/debian/patches/pve/0037-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch @@ -0,0 +1,45 @@ +From 31ea5889c25012189aabe51157b32cfbe87a63be Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= +Date: Mon, 17 Feb 2020 10:43:22 +0100 +Subject: [PATCH qemu 37/39] mirror: switch to bdrv_dirty_bitmap_merge_internal +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +since sync_bitmap is busy at the point of merging, and we checked access +beforehand. + +Signed-off-by: Fabian Grünbichler +--- + block/mirror.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index 40d174a625..d6aca2874e 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -735,8 +735,8 @@ static int mirror_exit_common(Job *job) + job->ret == 0 && ret == 0)) { + /* Success; synchronize copy back to sync. */ + bdrv_clear_dirty_bitmap(s->sync_bitmap, NULL); +- bdrv_merge_dirty_bitmap(s->sync_bitmap, s->dirty_bitmap, +- NULL, &error_abort); ++ bdrv_dirty_bitmap_merge_internal(s->sync_bitmap, s->dirty_bitmap, ++ NULL, true); + } + } + bdrv_release_dirty_bitmap(s->dirty_bitmap); +@@ -1727,8 +1727,8 @@ static BlockJob *mirror_start_job( + } + + if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) { +- bdrv_merge_dirty_bitmap(s->dirty_bitmap, s->sync_bitmap, +- NULL, &local_err); ++ bdrv_dirty_bitmap_merge_internal(s->dirty_bitmap, s->sync_bitmap, ++ NULL, true); + if (local_err) { + goto fail; + } +-- +2.20.1 + diff --git a/debian/patches/pve/0038-iotests-add-test-for-bitmap-mirror.patch b/debian/patches/pve/0038-iotests-add-test-for-bitmap-mirror.patch new file mode 100644 index 0000000..112250e --- /dev/null +++ b/debian/patches/pve/0038-iotests-add-test-for-bitmap-mirror.patch @@ -0,0 +1,3447 @@ +From 145eea36a4a34919e2551cc14774c47dfb32ac3c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= +Date: Mon, 17 Feb 2020 10:47:07 +0100 +Subject: [PATCH qemu 38/39] iotests: add test for bitmap mirror +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +heavily based on/practically forked off iotest 257 for bitmap backups, +but: + +- no writes to filter node 'mirror-top' between completion and +finalization, as those seem to deadlock? +- no inclusion of not-yet-available full/top sync modes in combination +with bitmaps +- extra set of reference/test mirrors to verify that writes in parallel +with active mirror work + +intentionally keeping copyright and ownership of original test case to +honor provenance. + +Signed-off-by: Fabian Grünbichler +--- + tests/qemu-iotests/284 | 547 +++++++ + tests/qemu-iotests/284.out | 2846 ++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 3394 insertions(+) + create mode 100755 tests/qemu-iotests/284 + create mode 100644 tests/qemu-iotests/284.out + +diff --git a/tests/qemu-iotests/284 b/tests/qemu-iotests/284 +new file mode 100755 +index 0000000000..b04a8e651a +--- /dev/null ++++ b/tests/qemu-iotests/284 +@@ -0,0 +1,547 @@ ++#!/usr/bin/env python3 ++# ++# Test bitmap-sync mirrors (incremental, differential, and partials) ++# ++# Copyright (c) 2019 John Snow for Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# owner=jsnow@redhat.com ++ ++import math ++import os ++ ++import iotests ++from iotests import log, qemu_img ++ ++SIZE = 64 * 1024 * 1024 ++GRANULARITY = 64 * 1024 ++ ++ ++class Pattern: ++ def __init__(self, byte, offset, size=GRANULARITY): ++ self.byte = byte ++ self.offset = offset ++ self.size = size ++ ++ def bits(self, granularity): ++ lower = self.offset // granularity ++ upper = (self.offset + self.size - 1) // granularity ++ return set(range(lower, upper + 1)) ++ ++ ++class PatternGroup: ++ """Grouping of Pattern objects. Initialize with an iterable of Patterns.""" ++ def __init__(self, patterns): ++ self.patterns = patterns ++ ++ def bits(self, granularity): ++ """Calculate the unique bits dirtied by this pattern grouping""" ++ res = set() ++ for pattern in self.patterns: ++ res |= pattern.bits(granularity) ++ return res ++ ++ ++GROUPS = [ ++ PatternGroup([ ++ # Batch 0: 4 clusters ++ Pattern('0x49', 0x0000000), ++ Pattern('0x6c', 0x0100000), # 1M ++ Pattern('0x6f', 0x2000000), # 32M ++ Pattern('0x76', 0x3ff0000)]), # 64M - 64K ++ PatternGroup([ ++ # Batch 1: 6 clusters (3 new) ++ Pattern('0x65', 0x0000000), # Full overwrite ++ Pattern('0x77', 0x00f8000), # Partial-left (1M-32K) ++ Pattern('0x72', 0x2008000), # Partial-right (32M+32K) ++ Pattern('0x69', 0x3fe0000)]), # Adjacent-left (64M - 128K) ++ PatternGroup([ ++ # Batch 2: 7 clusters (3 new) ++ Pattern('0x74', 0x0010000), # Adjacent-right ++ Pattern('0x69', 0x00e8000), # Partial-left (1M-96K) ++ Pattern('0x6e', 0x2018000), # Partial-right (32M+96K) ++ Pattern('0x67', 0x3fe0000, ++ 2*GRANULARITY)]), # Overwrite [(64M-128K)-64M) ++ PatternGroup([ ++ # Batch 3: 8 clusters (5 new) ++ # Carefully chosen such that nothing re-dirties the one cluster ++ # that copies out successfully before failure in Group #1. ++ Pattern('0xaa', 0x0010000, ++ 3*GRANULARITY), # Overwrite and 2x Adjacent-right ++ Pattern('0xbb', 0x00d8000), # Partial-left (1M-160K) ++ Pattern('0xcc', 0x2028000), # Partial-right (32M+160K) ++ Pattern('0xdd', 0x3fc0000)]), # New; leaving a gap to the right ++] ++ ++ ++class EmulatedBitmap: ++ def __init__(self, granularity=GRANULARITY): ++ self._bits = set() ++ self.granularity = granularity ++ ++ def dirty_bits(self, bits): ++ self._bits |= set(bits) ++ ++ def dirty_group(self, n): ++ self.dirty_bits(GROUPS[n].bits(self.granularity)) ++ ++ def clear(self): ++ self._bits = set() ++ ++ def clear_bits(self, bits): ++ self._bits -= set(bits) ++ ++ def clear_bit(self, bit): ++ self.clear_bits({bit}) ++ ++ def clear_group(self, n): ++ self.clear_bits(GROUPS[n].bits(self.granularity)) ++ ++ @property ++ def first_bit(self): ++ return sorted(self.bits)[0] ++ ++ @property ++ def bits(self): ++ return self._bits ++ ++ @property ++ def count(self): ++ return len(self.bits) ++ ++ def compare(self, qmp_bitmap): ++ """ ++ Print a nice human-readable message checking that a bitmap as reported ++ by the QMP interface has as many bits set as we expect it to. ++ """ ++ ++ name = qmp_bitmap.get('name', '(anonymous)') ++ log("= Checking Bitmap {:s} =".format(name)) ++ ++ want = self.count ++ have = qmp_bitmap['count'] // qmp_bitmap['granularity'] ++ ++ log("expecting {:d} dirty sectors; have {:d}. {:s}".format( ++ want, have, "OK!" if want == have else "ERROR!")) ++ log('') ++ ++ ++class Drive: ++ """Represents, vaguely, a drive attached to a VM. ++ Includes format, graph, and device information.""" ++ ++ def __init__(self, path, vm=None): ++ self.path = path ++ self.vm = vm ++ self.fmt = None ++ self.size = None ++ self.node = None ++ ++ def img_create(self, fmt, size): ++ self.fmt = fmt ++ self.size = size ++ iotests.qemu_img_create('-f', self.fmt, self.path, str(self.size)) ++ ++ def create_target(self, name, fmt, size): ++ basename = os.path.basename(self.path) ++ file_node_name = "file_{}".format(basename) ++ vm = self.vm ++ ++ log(vm.command('blockdev-create', job_id='bdc-file-job', ++ options={ ++ 'driver': 'file', ++ 'filename': self.path, ++ 'size': 0, ++ })) ++ vm.run_job('bdc-file-job') ++ log(vm.command('blockdev-add', driver='file', ++ node_name=file_node_name, filename=self.path)) ++ ++ log(vm.command('blockdev-create', job_id='bdc-fmt-job', ++ options={ ++ 'driver': fmt, ++ 'file': file_node_name, ++ 'size': size, ++ })) ++ vm.run_job('bdc-fmt-job') ++ log(vm.command('blockdev-add', driver=fmt, ++ node_name=name, ++ file=file_node_name)) ++ self.fmt = fmt ++ self.size = size ++ self.node = name ++ ++def blockdev_mirror(vm, device, target, sync, **kwargs): ++ # Strip any arguments explicitly nulled by the caller: ++ kwargs = {key: val for key, val in kwargs.items() if val is not None} ++ result = vm.qmp_log('blockdev-mirror', ++ device=device, ++ target=target, ++ sync=sync, ++ filter_node_name='mirror-top', ++ **kwargs) ++ return result ++ ++def blockdev_mirror_mktarget(drive, target_id, filepath, sync, **kwargs): ++ target_drive = Drive(filepath, vm=drive.vm) ++ target_drive.create_target(target_id, drive.fmt, drive.size) ++ blockdev_mirror(drive.vm, drive.node, target_id, sync, **kwargs) ++ ++def reference_mirror(drive, n, filepath): ++ log("--- Reference mirror #{:d} ---\n".format(n)) ++ target_id = "ref_target_{:d}".format(n) ++ job_id = "ref_mirror_{:d}".format(n) ++ blockdev_mirror_mktarget(drive, target_id, filepath, "full", ++ job_id=job_id) ++ drive.vm.run_job(job_id, auto_dismiss=True) ++ log('') ++ ++def mirror(drive, n, filepath, sync, **kwargs): ++ log("--- Test mirror #{:d} ---\n".format(n)) ++ target_id = "mirror_target_{:d}".format(n) ++ job_id = "mirror_{:d}".format(n) ++ kwargs.setdefault('auto-finalize', False) ++ blockdev_mirror_mktarget(drive, target_id, filepath, sync, ++ job_id=job_id, **kwargs) ++ return job_id ++ ++def perform_writes(drive, n, filter_node_name=None): ++ log("--- Write #{:d} ---\n".format(n)) ++ for pattern in GROUPS[n].patterns: ++ cmd = "write -P{:s} 0x{:07x} 0x{:x}".format( ++ pattern.byte, ++ pattern.offset, ++ pattern.size) ++ log(cmd) ++ log(drive.vm.hmp_qemu_io(filter_node_name or drive.node, cmd)) ++ bitmaps = drive.vm.query_bitmaps() ++ log({'bitmaps': bitmaps}, indent=2) ++ log('') ++ return bitmaps ++ ++ ++def compare_images(image, reference, baseimg=None, expected_match=True): ++ """ ++ Print a nice human-readable message comparing these images. ++ """ ++ expected_ret = 0 if expected_match else 1 ++ if baseimg: ++ assert qemu_img("rebase", "-u", "-b", baseimg, image) == 0 ++ ret = qemu_img("compare", image, reference) ++ log('qemu_img compare "{:s}" "{:s}" ==> {:s}, {:s}'.format( ++ image, reference, ++ "Identical" if ret == 0 else "Mismatch", ++ "OK!" if ret == expected_ret else "ERROR!"), ++ filters=[iotests.filter_testfiles]) ++ ++def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None): ++ """ ++ Test bitmap mirror routines. ++ ++ :param bsync_mode: Is the Bitmap Sync mode, and can be any of: ++ - on-success: This is the "incremental" style mode. Bitmaps are ++ synchronized to what was copied out only on success. ++ (Partial images must be discarded.) ++ - never: This is the "differential" style mode. ++ Bitmaps are never synchronized. ++ - always: This is a "best effort" style mode. ++ Bitmaps are always synchronized, regardless of failure. ++ (Partial images must be kept.) ++ ++ :param msync_mode: The mirror sync mode to use for the first mirror. ++ Can be any one of: ++ - bitmap: mirrors based on bitmap manifest. ++ - full: Full mirrors. ++ - top: Full mirrors of the top layer only. ++ ++ :param failure: Is the (optional) failure mode, and can be any of: ++ - None: No failure. Test the normative path. Default. ++ - simulated: Cancel the job right before it completes. ++ This also tests writes "during" the job. ++ - intermediate: This tests a job that fails mid-process and produces ++ an incomplete mirror. Testing limitations prevent ++ testing competing writes. ++ """ ++ with iotests.FilePaths(['img', 'bsync1', 'bsync2', 'bsync3', ++ 'fmirror0', 'fmirror1', 'fmirror2', 'fmirror3']) as \ ++ (img_path, bsync1, bsync2, bsync3, ++ fmirror0, fmirror1, fmirror2, fmirror3), \ ++ iotests.VM() as vm: ++ ++ mode = "Mode {:s}; Bitmap Sync {:s}".format(msync_mode, bsync_mode) ++ preposition = "with" if failure else "without" ++ cond = "{:s} {:s}".format(preposition, ++ "{:s} failure".format(failure) if failure ++ else "failure") ++ log("\n=== {:s} {:s} ===\n".format(mode, cond)) ++ ++ log('--- Preparing image & VM ---\n') ++ drive0 = Drive(img_path, vm=vm) ++ drive0.img_create(iotests.imgfmt, SIZE) ++ vm.add_device("{},id=scsi0".format(iotests.get_virtio_scsi_device())) ++ vm.launch() ++ ++ file_config = { ++ 'driver': 'file', ++ 'filename': drive0.path ++ } ++ ++ if failure == 'intermediate': ++ file_config = { ++ 'driver': 'blkdebug', ++ 'image': file_config, ++ 'set-state': [{ ++ 'event': 'flush_to_disk', ++ 'state': 1, ++ 'new_state': 2 ++ }, { ++ 'event': 'read_aio', ++ 'state': 2, ++ 'new_state': 3 ++ }, { ++ 'event': 'read_aio', ++ 'state': 3, ++ 'new_state': 4 ++ }], ++ 'inject-error': [{ ++ 'event': 'read_aio', ++ 'errno': 5, ++ 'state': 3, ++ 'immediately': False, ++ 'once': True ++ }, { ++ 'event': 'read_aio', ++ 'errno': 5, ++ 'state': 4, ++ 'immediately': False, ++ 'once': True ++ }] ++ } ++ ++ drive0.node = 'drive0' ++ vm.qmp_log('blockdev-add', ++ filters=[iotests.filter_qmp_testfiles], ++ node_name=drive0.node, ++ driver=drive0.fmt, ++ file=file_config) ++ log('') ++ ++ # 0 - Writes and Reference mirror ++ perform_writes(drive0, 0) ++ reference_mirror(drive0, 0, fmirror0) ++ log('--- Add Bitmap ---\n') ++ vm.qmp_log("block-dirty-bitmap-add", node=drive0.node, ++ name="bitmap0", granularity=GRANULARITY) ++ log('') ++ ebitmap = EmulatedBitmap() ++ ++ # 1 - Writes and Reference mirror ++ bitmaps = perform_writes(drive0, 1) ++ ebitmap.dirty_group(1) ++ bitmap = vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps) ++ ebitmap.compare(bitmap) ++ reference_mirror(drive0, 1, fmirror1) ++ ++ # 1 - Test mirror (w/ Optional induced failure) ++ if failure == 'intermediate': ++ # Activate blkdebug induced failure for second-to-next read ++ log(vm.hmp_qemu_io(drive0.node, 'flush')) ++ log('') ++ job = mirror(drive0, 1, bsync1, msync_mode, ++ bitmap="bitmap0", bitmap_mode=bsync_mode) ++ ++ vm.run_job(job, auto_dismiss=True, auto_finalize=False, ++ cancel=(failure == 'simulated')) ++ bitmaps = vm.query_bitmaps() ++ log({'bitmaps': bitmaps}, indent=2) ++ log('') ++ ++ if bsync_mode == 'always': ++ if failure == 'intermediate': ++ # We manage to copy one sector (one bit) before the error. ++ ebitmap.clear_bit(ebitmap.first_bit) ++ else: ++ # successful mirror / cancelled complete mirror ++ ebitmap.clear() ++ ++ if bsync_mode == 'on-success' and not failure: ++ ebitmap.clear() ++ ++ ebitmap.compare(vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps)) ++ ++ # 2 - Reference mirror ++ reference_mirror(drive0, 2, fmirror2) ++ ++ # 2 - Bitmap mirror with writes before completion ++ job = mirror(drive0, 2, bsync2, "bitmap", ++ bitmap="bitmap0", bitmap_mode=bsync_mode) ++ ++ bitmaps = perform_writes(drive0, 2) ++ ebitmap.dirty_group(2) ++ ebitmap.compare(vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps)) ++ ++ # don't use run_job as that logs too much even with use_log=False ++ events = [('JOB_STATUS_CHANGE', {'data': {'id': job}})] ++ while True: ++ ev = iotests.filter_qmp_event(vm.events_wait(events, timeout=10)) ++ status = ev['data']['status'] ++ if status == 'ready': ++ vm.qmp('job-complete', id=job) ++ elif status == 'standby': ++ vm.qmp('job-resume', id=job) ++ elif status == 'pending': ++ vm.qmp('job-finalize', id=job) ++ elif status == 'null': ++ break ++ ++ if bsync_mode != 'never': ++ ebitmap.clear() ++ ++ bitmaps = vm.query_bitmaps() ++ ebitmap.compare(vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps)) ++ ++ # 3 - Writes and Reference mirror ++ bitmaps = perform_writes(drive0, 3) ++ ebitmap.dirty_group(3) ++ ebitmap.compare(vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps)) ++ reference_mirror(drive0, 3, fmirror3) ++ ++ # 3 - Bitmap mirror (In failure modes, this is a recovery.) ++ job = mirror(drive0, 3, bsync3, "bitmap", ++ bitmap="bitmap0", bitmap_mode=bsync_mode) ++ ++ vm.run_job(job, auto_dismiss=True, auto_finalize=False) ++ bitmaps = vm.query_bitmaps() ++ ++ log({'bitmaps': bitmaps}, indent=2) ++ log('') ++ if bsync_mode != 'never': ++ ebitmap.clear() ++ ebitmap.compare(vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps)) ++ ++ log('--- Cleanup ---\n') ++ vm.qmp_log("block-dirty-bitmap-remove", ++ node=drive0.node, name="bitmap0") ++ bitmaps = vm.query_bitmaps() ++ log({'bitmaps': bitmaps}, indent=2) ++ vm.shutdown() ++ log('') ++ ++ log('--- Verification ---\n') ++ compare_images(bsync1, fmirror1, baseimg=fmirror0, ++ expected_match=failure != 'intermediate') ++ if not failure or bsync_mode == 'always': ++ # Always keep the last mirror on success or when using 'always' ++ base = bsync1 ++ else: ++ base = fmirror1 ++ ++ compare_images(bsync2, fmirror2, baseimg=base, expected_match=0) ++ compare_images(bsync3, fmirror3, baseimg=bsync2) ++ compare_images(img_path, fmirror3) ++ log('') ++ ++def test_mirror_api(): ++ """ ++ Test malformed and prohibited invocations of the mirror API. ++ """ ++ with iotests.FilePaths(['img', 'bsync1']) as \ ++ (img_path, mirror_path), \ ++ iotests.VM() as vm: ++ ++ log("\n=== API failure tests ===\n") ++ log('--- Preparing image & VM ---\n') ++ drive0 = Drive(img_path, vm=vm) ++ drive0.img_create(iotests.imgfmt, SIZE) ++ vm.add_device("{},id=scsi0".format(iotests.get_virtio_scsi_device())) ++ vm.launch() ++ ++ file_config = { ++ 'driver': 'file', ++ 'filename': drive0.path ++ } ++ ++ drive0.node = 'drive0' ++ vm.qmp_log('blockdev-add', ++ filters=[iotests.filter_qmp_testfiles], ++ node_name=drive0.node, ++ driver=drive0.fmt, ++ file=file_config) ++ log('') ++ ++ target0 = Drive(mirror_path, vm=vm) ++ target0.create_target("mirror_target", drive0.fmt, drive0.size) ++ log('') ++ ++ vm.qmp_log("block-dirty-bitmap-add", node=drive0.node, ++ name="bitmap0", granularity=GRANULARITY) ++ log('') ++ ++ log('-- Testing invalid QMP commands --\n') ++ ++ error_cases = { ++ 'incremental': { ++ None: ['on-success', 'always', 'never', None], ++ 'bitmap404': ['on-success', 'always', 'never', None], ++ 'bitmap0': ['always', 'never'] ++ }, ++ 'bitmap': { ++ None: ['on-success', 'always', 'never', None], ++ 'bitmap404': ['on-success', 'always', 'never', None], ++ 'bitmap0': [None], ++ }, ++ 'full': { ++ None: ['on-success', 'always', 'never'], ++ 'bitmap404': ['on-success', 'always', 'never', None], ++ 'bitmap0': ['on-success', 'always', 'never', None], ++ }, ++ 'top': { ++ None: ['on-success', 'always', 'never'], ++ 'bitmap404': ['on-success', 'always', 'never', None], ++ 'bitmap0': ['on-success', 'always', 'never', None], ++ }, ++ 'none': { ++ None: ['on-success', 'always', 'never'], ++ 'bitmap404': ['on-success', 'always', 'never', None], ++ 'bitmap0': ['on-success', 'always', 'never', None], ++ } ++ } ++ ++ # Dicts, as always, are not stably-ordered prior to 3.7, so use tuples: ++ for sync_mode in ('incremental', 'bitmap', 'full', 'top', 'none'): ++ log("-- Sync mode {:s} tests --\n".format(sync_mode)) ++ for bitmap in (None, 'bitmap404', 'bitmap0'): ++ for policy in error_cases[sync_mode][bitmap]: ++ blockdev_mirror(drive0.vm, drive0.node, "mirror_target", ++ sync_mode, job_id='api_job', ++ bitmap=bitmap, bitmap_mode=policy) ++ log('') ++ ++ ++def main(): ++ for bsync_mode in ("never", "on-success", "always"): ++ for failure in ("simulated", "intermediate", None): ++ test_bitmap_sync(bsync_mode, "bitmap", failure) ++ ++# for sync_mode in ('full', 'top'): ++# for bsync_mode in ('on-success', 'always'): ++# for failure in ('simulated', 'intermediate', None): ++# test_bitmap_sync(bsync_mode, sync_mode, failure) ++ ++ test_mirror_api() ++ ++if __name__ == '__main__': ++ iotests.script_main(main, supported_fmts=['qcow2'], ++ supported_protocols=['file']) +diff --git a/tests/qemu-iotests/284.out b/tests/qemu-iotests/284.out +new file mode 100644 +index 0000000000..9b7408b6d6 +--- /dev/null ++++ b/tests/qemu-iotests/284.out +@@ -0,0 +1,2846 @@ ++ ++=== Mode bitmap; Bitmap Sync never with simulated failure === ++ ++--- Preparing image & VM --- ++ ++{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-img"}, "node-name": "drive0"}} ++{"return": {}} ++ ++--- Write #0 --- ++ ++write -P0x49 0x0000000 0x10000 ++{"return": ""} ++write -P0x6c 0x0100000 0x10000 ++{"return": ""} ++write -P0x6f 0x2000000 0x10000 ++{"return": ""} ++write -P0x76 0x3ff0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": {} ++} ++ ++--- Reference mirror #0 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_0", "sync": "full", "target": "ref_target_0"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_0"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Add Bitmap --- ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++ ++--- Write #1 --- ++ ++write -P0x65 0x0000000 0x10000 ++{"return": ""} ++write -P0x77 0x00f8000 0x10000 ++{"return": ""} ++write -P0x72 0x2008000 0x10000 ++{"return": ""} ++write -P0x69 0x3fe0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_1", "sync": "full", "target": "ref_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_1"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_1", "sync": "bitmap", "target": "mirror_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-cancel", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"id": "mirror_1", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_2", "sync": "full", "target": "ref_target_2"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_2"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_2", "sync": "bitmap", "target": "mirror_target_2"}} ++{"return": {}} ++--- Write #2 --- ++ ++write -P0x74 0x0010000 0x10000 ++{"return": ""} ++write -P0x69 0x00e8000 0x10000 ++{"return": ""} ++write -P0x6e 0x2018000 0x10000 ++{"return": ""} ++write -P0x67 0x3fe0000 0x20000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 262144, ++ "granularity": 65536, ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": true, ++ "count": 655360, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "locked" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 10 dirty sectors; have 10. OK! ++ ++= Checking Bitmap bitmap0 = ++expecting 10 dirty sectors; have 10. OK! ++ ++--- Write #3 --- ++ ++write -P0xaa 0x0010000 0x30000 ++{"return": ""} ++write -P0xbb 0x00d8000 0x10000 ++{"return": ""} ++write -P0xcc 0x2028000 0x10000 ++{"return": ""} ++write -P0xdd 0x3fc0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 983040, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 15 dirty sectors; have 15. OK! ++ ++--- Reference mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_3", "sync": "full", "target": "ref_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_3"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_3", "sync": "bitmap", "target": "mirror_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"device": "mirror_3", "len": 983040, "offset": 983040, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"id": "mirror_3", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_3", "len": 983040, "offset": 983040, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 983040, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 15 dirty sectors; have 15. OK! ++ ++--- Cleanup --- ++ ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++{ ++ "bitmaps": {} ++} ++ ++--- Verification --- ++ ++qemu_img compare "TEST_DIR/PID-bsync1" "TEST_DIR/PID-fmirror1" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-bsync2" "TEST_DIR/PID-fmirror2" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync3" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++ ++ ++=== Mode bitmap; Bitmap Sync never with intermediate failure === ++ ++--- Preparing image & VM --- ++ ++{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "blkdebug", "image": {"driver": "file", "filename": "TEST_DIR/PID-img"}, "inject-error": [{"errno": 5, "event": "read_aio", "immediately": false, "once": true, "state": 3}, {"errno": 5, "event": "read_aio", "immediately": false, "once": true, "state": 4}], "set-state": [{"event": "flush_to_disk", "new-state": 2, "state": 1}, {"event": "read_aio", "new-state": 3, "state": 2}, {"event": "read_aio", "new-state": 4, "state": 3}]}, "node-name": "drive0"}} ++{"return": {}} ++ ++--- Write #0 --- ++ ++write -P0x49 0x0000000 0x10000 ++{"return": ""} ++write -P0x6c 0x0100000 0x10000 ++{"return": ""} ++write -P0x6f 0x2000000 0x10000 ++{"return": ""} ++write -P0x76 0x3ff0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": {} ++} ++ ++--- Reference mirror #0 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_0", "sync": "full", "target": "ref_target_0"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_0"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Add Bitmap --- ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++ ++--- Write #1 --- ++ ++write -P0x65 0x0000000 0x10000 ++{"return": ""} ++write -P0x77 0x00f8000 0x10000 ++{"return": ""} ++write -P0x72 0x2008000 0x10000 ++{"return": ""} ++write -P0x69 0x3fe0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_1", "sync": "full", "target": "ref_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_1"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++{"return": ""} ++ ++--- Test mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_1", "sync": "bitmap", "target": "mirror_target_1"}} ++{"return": {}} ++{"data": {"action": "report", "device": "mirror_1", "operation": "read"}, "event": "BLOCK_JOB_ERROR", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"action": "report", "device": "mirror_1", "operation": "read"}, "event": "BLOCK_JOB_ERROR", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_1", "error": "Input/output error", "len": 393216, "offset": 65536, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_2", "sync": "full", "target": "ref_target_2"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_2"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_2", "sync": "bitmap", "target": "mirror_target_2"}} ++{"return": {}} ++--- Write #2 --- ++ ++write -P0x74 0x0010000 0x10000 ++{"return": ""} ++write -P0x69 0x00e8000 0x10000 ++{"return": ""} ++write -P0x6e 0x2018000 0x10000 ++{"return": ""} ++write -P0x67 0x3fe0000 0x20000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 262144, ++ "granularity": 65536, ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": true, ++ "count": 655360, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "locked" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 10 dirty sectors; have 10. OK! ++ ++= Checking Bitmap bitmap0 = ++expecting 10 dirty sectors; have 10. OK! ++ ++--- Write #3 --- ++ ++write -P0xaa 0x0010000 0x30000 ++{"return": ""} ++write -P0xbb 0x00d8000 0x10000 ++{"return": ""} ++write -P0xcc 0x2028000 0x10000 ++{"return": ""} ++write -P0xdd 0x3fc0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 983040, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 15 dirty sectors; have 15. OK! ++ ++--- Reference mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_3", "sync": "full", "target": "ref_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_3"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_3", "sync": "bitmap", "target": "mirror_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"device": "mirror_3", "len": 983040, "offset": 983040, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"id": "mirror_3", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_3", "len": 983040, "offset": 983040, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 983040, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 15 dirty sectors; have 15. OK! ++ ++--- Cleanup --- ++ ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++{ ++ "bitmaps": {} ++} ++ ++--- Verification --- ++ ++qemu_img compare "TEST_DIR/PID-bsync1" "TEST_DIR/PID-fmirror1" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync2" "TEST_DIR/PID-fmirror2" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync3" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++ ++ ++=== Mode bitmap; Bitmap Sync never without failure === ++ ++--- Preparing image & VM --- ++ ++{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-img"}, "node-name": "drive0"}} ++{"return": {}} ++ ++--- Write #0 --- ++ ++write -P0x49 0x0000000 0x10000 ++{"return": ""} ++write -P0x6c 0x0100000 0x10000 ++{"return": ""} ++write -P0x6f 0x2000000 0x10000 ++{"return": ""} ++write -P0x76 0x3ff0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": {} ++} ++ ++--- Reference mirror #0 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_0", "sync": "full", "target": "ref_target_0"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_0"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Add Bitmap --- ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++ ++--- Write #1 --- ++ ++write -P0x65 0x0000000 0x10000 ++{"return": ""} ++write -P0x77 0x00f8000 0x10000 ++{"return": ""} ++write -P0x72 0x2008000 0x10000 ++{"return": ""} ++write -P0x69 0x3fe0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_1", "sync": "full", "target": "ref_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_1"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_1", "sync": "bitmap", "target": "mirror_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"id": "mirror_1", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_2", "sync": "full", "target": "ref_target_2"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_2"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_2", "sync": "bitmap", "target": "mirror_target_2"}} ++{"return": {}} ++--- Write #2 --- ++ ++write -P0x74 0x0010000 0x10000 ++{"return": ""} ++write -P0x69 0x00e8000 0x10000 ++{"return": ""} ++write -P0x6e 0x2018000 0x10000 ++{"return": ""} ++write -P0x67 0x3fe0000 0x20000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 262144, ++ "granularity": 65536, ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": true, ++ "count": 655360, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "locked" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 10 dirty sectors; have 10. OK! ++ ++= Checking Bitmap bitmap0 = ++expecting 10 dirty sectors; have 10. OK! ++ ++--- Write #3 --- ++ ++write -P0xaa 0x0010000 0x30000 ++{"return": ""} ++write -P0xbb 0x00d8000 0x10000 ++{"return": ""} ++write -P0xcc 0x2028000 0x10000 ++{"return": ""} ++write -P0xdd 0x3fc0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 983040, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 15 dirty sectors; have 15. OK! ++ ++--- Reference mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_3", "sync": "full", "target": "ref_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_3"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_3", "sync": "bitmap", "target": "mirror_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"device": "mirror_3", "len": 983040, "offset": 983040, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"id": "mirror_3", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_3", "len": 983040, "offset": 983040, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 983040, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 15 dirty sectors; have 15. OK! ++ ++--- Cleanup --- ++ ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++{ ++ "bitmaps": {} ++} ++ ++--- Verification --- ++ ++qemu_img compare "TEST_DIR/PID-bsync1" "TEST_DIR/PID-fmirror1" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-bsync2" "TEST_DIR/PID-fmirror2" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync3" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++ ++ ++=== Mode bitmap; Bitmap Sync on-success with simulated failure === ++ ++--- Preparing image & VM --- ++ ++{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-img"}, "node-name": "drive0"}} ++{"return": {}} ++ ++--- Write #0 --- ++ ++write -P0x49 0x0000000 0x10000 ++{"return": ""} ++write -P0x6c 0x0100000 0x10000 ++{"return": ""} ++write -P0x6f 0x2000000 0x10000 ++{"return": ""} ++write -P0x76 0x3ff0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": {} ++} ++ ++--- Reference mirror #0 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_0", "sync": "full", "target": "ref_target_0"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_0"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Add Bitmap --- ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++ ++--- Write #1 --- ++ ++write -P0x65 0x0000000 0x10000 ++{"return": ""} ++write -P0x77 0x00f8000 0x10000 ++{"return": ""} ++write -P0x72 0x2008000 0x10000 ++{"return": ""} ++write -P0x69 0x3fe0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_1", "sync": "full", "target": "ref_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_1"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_1", "sync": "bitmap", "target": "mirror_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-cancel", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"id": "mirror_1", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_2", "sync": "full", "target": "ref_target_2"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_2"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_2", "sync": "bitmap", "target": "mirror_target_2"}} ++{"return": {}} ++--- Write #2 --- ++ ++write -P0x74 0x0010000 0x10000 ++{"return": ""} ++write -P0x69 0x00e8000 0x10000 ++{"return": ""} ++write -P0x6e 0x2018000 0x10000 ++{"return": ""} ++write -P0x67 0x3fe0000 0x20000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 262144, ++ "granularity": 65536, ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": true, ++ "count": 655360, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "locked" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 10 dirty sectors; have 10. OK! ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Write #3 --- ++ ++write -P0xaa 0x0010000 0x30000 ++{"return": ""} ++write -P0xbb 0x00d8000 0x10000 ++{"return": ""} ++write -P0xcc 0x2028000 0x10000 ++{"return": ""} ++write -P0xdd 0x3fc0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 524288, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 8 dirty sectors; have 8. OK! ++ ++--- Reference mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_3", "sync": "full", "target": "ref_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_3"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_3", "sync": "bitmap", "target": "mirror_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"id": "mirror_3", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Cleanup --- ++ ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++{ ++ "bitmaps": {} ++} ++ ++--- Verification --- ++ ++qemu_img compare "TEST_DIR/PID-bsync1" "TEST_DIR/PID-fmirror1" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-bsync2" "TEST_DIR/PID-fmirror2" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync3" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++ ++ ++=== Mode bitmap; Bitmap Sync on-success with intermediate failure === ++ ++--- Preparing image & VM --- ++ ++{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "blkdebug", "image": {"driver": "file", "filename": "TEST_DIR/PID-img"}, "inject-error": [{"errno": 5, "event": "read_aio", "immediately": false, "once": true, "state": 3}, {"errno": 5, "event": "read_aio", "immediately": false, "once": true, "state": 4}], "set-state": [{"event": "flush_to_disk", "new-state": 2, "state": 1}, {"event": "read_aio", "new-state": 3, "state": 2}, {"event": "read_aio", "new-state": 4, "state": 3}]}, "node-name": "drive0"}} ++{"return": {}} ++ ++--- Write #0 --- ++ ++write -P0x49 0x0000000 0x10000 ++{"return": ""} ++write -P0x6c 0x0100000 0x10000 ++{"return": ""} ++write -P0x6f 0x2000000 0x10000 ++{"return": ""} ++write -P0x76 0x3ff0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": {} ++} ++ ++--- Reference mirror #0 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_0", "sync": "full", "target": "ref_target_0"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_0"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Add Bitmap --- ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++ ++--- Write #1 --- ++ ++write -P0x65 0x0000000 0x10000 ++{"return": ""} ++write -P0x77 0x00f8000 0x10000 ++{"return": ""} ++write -P0x72 0x2008000 0x10000 ++{"return": ""} ++write -P0x69 0x3fe0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_1", "sync": "full", "target": "ref_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_1"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++{"return": ""} ++ ++--- Test mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_1", "sync": "bitmap", "target": "mirror_target_1"}} ++{"return": {}} ++{"data": {"action": "report", "device": "mirror_1", "operation": "read"}, "event": "BLOCK_JOB_ERROR", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"action": "report", "device": "mirror_1", "operation": "read"}, "event": "BLOCK_JOB_ERROR", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_1", "error": "Input/output error", "len": 393216, "offset": 65536, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_2", "sync": "full", "target": "ref_target_2"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_2"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_2", "sync": "bitmap", "target": "mirror_target_2"}} ++{"return": {}} ++--- Write #2 --- ++ ++write -P0x74 0x0010000 0x10000 ++{"return": ""} ++write -P0x69 0x00e8000 0x10000 ++{"return": ""} ++write -P0x6e 0x2018000 0x10000 ++{"return": ""} ++write -P0x67 0x3fe0000 0x20000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 262144, ++ "granularity": 65536, ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": true, ++ "count": 655360, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "locked" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 10 dirty sectors; have 10. OK! ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Write #3 --- ++ ++write -P0xaa 0x0010000 0x30000 ++{"return": ""} ++write -P0xbb 0x00d8000 0x10000 ++{"return": ""} ++write -P0xcc 0x2028000 0x10000 ++{"return": ""} ++write -P0xdd 0x3fc0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 524288, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 8 dirty sectors; have 8. OK! ++ ++--- Reference mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_3", "sync": "full", "target": "ref_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_3"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_3", "sync": "bitmap", "target": "mirror_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"id": "mirror_3", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Cleanup --- ++ ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++{ ++ "bitmaps": {} ++} ++ ++--- Verification --- ++ ++qemu_img compare "TEST_DIR/PID-bsync1" "TEST_DIR/PID-fmirror1" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync2" "TEST_DIR/PID-fmirror2" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync3" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++ ++ ++=== Mode bitmap; Bitmap Sync on-success without failure === ++ ++--- Preparing image & VM --- ++ ++{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-img"}, "node-name": "drive0"}} ++{"return": {}} ++ ++--- Write #0 --- ++ ++write -P0x49 0x0000000 0x10000 ++{"return": ""} ++write -P0x6c 0x0100000 0x10000 ++{"return": ""} ++write -P0x6f 0x2000000 0x10000 ++{"return": ""} ++write -P0x76 0x3ff0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": {} ++} ++ ++--- Reference mirror #0 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_0", "sync": "full", "target": "ref_target_0"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_0"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Add Bitmap --- ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++ ++--- Write #1 --- ++ ++write -P0x65 0x0000000 0x10000 ++{"return": ""} ++write -P0x77 0x00f8000 0x10000 ++{"return": ""} ++write -P0x72 0x2008000 0x10000 ++{"return": ""} ++write -P0x69 0x3fe0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_1", "sync": "full", "target": "ref_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_1"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_1", "sync": "bitmap", "target": "mirror_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"id": "mirror_1", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Reference mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_2", "sync": "full", "target": "ref_target_2"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_2"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_2", "sync": "bitmap", "target": "mirror_target_2"}} ++{"return": {}} ++--- Write #2 --- ++ ++write -P0x74 0x0010000 0x10000 ++{"return": ""} ++write -P0x69 0x00e8000 0x10000 ++{"return": ""} ++write -P0x6e 0x2018000 0x10000 ++{"return": ""} ++write -P0x67 0x3fe0000 0x20000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 458752, ++ "granularity": 65536, ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": true, ++ "count": 458752, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "locked" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 7 dirty sectors; have 7. OK! ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Write #3 --- ++ ++write -P0xaa 0x0010000 0x30000 ++{"return": ""} ++write -P0xbb 0x00d8000 0x10000 ++{"return": ""} ++write -P0xcc 0x2028000 0x10000 ++{"return": ""} ++write -P0xdd 0x3fc0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 524288, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 8 dirty sectors; have 8. OK! ++ ++--- Reference mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_3", "sync": "full", "target": "ref_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_3"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_3", "sync": "bitmap", "target": "mirror_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"id": "mirror_3", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Cleanup --- ++ ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++{ ++ "bitmaps": {} ++} ++ ++--- Verification --- ++ ++qemu_img compare "TEST_DIR/PID-bsync1" "TEST_DIR/PID-fmirror1" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-bsync2" "TEST_DIR/PID-fmirror2" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync3" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++ ++ ++=== Mode bitmap; Bitmap Sync always with simulated failure === ++ ++--- Preparing image & VM --- ++ ++{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-img"}, "node-name": "drive0"}} ++{"return": {}} ++ ++--- Write #0 --- ++ ++write -P0x49 0x0000000 0x10000 ++{"return": ""} ++write -P0x6c 0x0100000 0x10000 ++{"return": ""} ++write -P0x6f 0x2000000 0x10000 ++{"return": ""} ++write -P0x76 0x3ff0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": {} ++} ++ ++--- Reference mirror #0 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_0", "sync": "full", "target": "ref_target_0"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_0"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Add Bitmap --- ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++ ++--- Write #1 --- ++ ++write -P0x65 0x0000000 0x10000 ++{"return": ""} ++write -P0x77 0x00f8000 0x10000 ++{"return": ""} ++write -P0x72 0x2008000 0x10000 ++{"return": ""} ++write -P0x69 0x3fe0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_1", "sync": "full", "target": "ref_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_1"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_1", "sync": "bitmap", "target": "mirror_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-cancel", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"id": "mirror_1", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Reference mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_2", "sync": "full", "target": "ref_target_2"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_2"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_2", "sync": "bitmap", "target": "mirror_target_2"}} ++{"return": {}} ++--- Write #2 --- ++ ++write -P0x74 0x0010000 0x10000 ++{"return": ""} ++write -P0x69 0x00e8000 0x10000 ++{"return": ""} ++write -P0x6e 0x2018000 0x10000 ++{"return": ""} ++write -P0x67 0x3fe0000 0x20000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 458752, ++ "granularity": 65536, ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": true, ++ "count": 458752, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "locked" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 7 dirty sectors; have 7. OK! ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Write #3 --- ++ ++write -P0xaa 0x0010000 0x30000 ++{"return": ""} ++write -P0xbb 0x00d8000 0x10000 ++{"return": ""} ++write -P0xcc 0x2028000 0x10000 ++{"return": ""} ++write -P0xdd 0x3fc0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 524288, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 8 dirty sectors; have 8. OK! ++ ++--- Reference mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_3", "sync": "full", "target": "ref_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_3"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_3", "sync": "bitmap", "target": "mirror_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"id": "mirror_3", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Cleanup --- ++ ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++{ ++ "bitmaps": {} ++} ++ ++--- Verification --- ++ ++qemu_img compare "TEST_DIR/PID-bsync1" "TEST_DIR/PID-fmirror1" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-bsync2" "TEST_DIR/PID-fmirror2" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync3" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++ ++ ++=== Mode bitmap; Bitmap Sync always with intermediate failure === ++ ++--- Preparing image & VM --- ++ ++{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "blkdebug", "image": {"driver": "file", "filename": "TEST_DIR/PID-img"}, "inject-error": [{"errno": 5, "event": "read_aio", "immediately": false, "once": true, "state": 3}, {"errno": 5, "event": "read_aio", "immediately": false, "once": true, "state": 4}], "set-state": [{"event": "flush_to_disk", "new-state": 2, "state": 1}, {"event": "read_aio", "new-state": 3, "state": 2}, {"event": "read_aio", "new-state": 4, "state": 3}]}, "node-name": "drive0"}} ++{"return": {}} ++ ++--- Write #0 --- ++ ++write -P0x49 0x0000000 0x10000 ++{"return": ""} ++write -P0x6c 0x0100000 0x10000 ++{"return": ""} ++write -P0x6f 0x2000000 0x10000 ++{"return": ""} ++write -P0x76 0x3ff0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": {} ++} ++ ++--- Reference mirror #0 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_0", "sync": "full", "target": "ref_target_0"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_0"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Add Bitmap --- ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++ ++--- Write #1 --- ++ ++write -P0x65 0x0000000 0x10000 ++{"return": ""} ++write -P0x77 0x00f8000 0x10000 ++{"return": ""} ++write -P0x72 0x2008000 0x10000 ++{"return": ""} ++write -P0x69 0x3fe0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_1", "sync": "full", "target": "ref_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_1"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++{"return": ""} ++ ++--- Test mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_1", "sync": "bitmap", "target": "mirror_target_1"}} ++{"return": {}} ++{"data": {"action": "report", "device": "mirror_1", "operation": "read"}, "event": "BLOCK_JOB_ERROR", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"action": "report", "device": "mirror_1", "operation": "read"}, "event": "BLOCK_JOB_ERROR", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_1", "error": "Input/output error", "len": 393216, "offset": 65536, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 327680, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 5 dirty sectors; have 5. OK! ++ ++--- Reference mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_2", "sync": "full", "target": "ref_target_2"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_2"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_2", "sync": "bitmap", "target": "mirror_target_2"}} ++{"return": {}} ++--- Write #2 --- ++ ++write -P0x74 0x0010000 0x10000 ++{"return": ""} ++write -P0x69 0x00e8000 0x10000 ++{"return": ""} ++write -P0x6e 0x2018000 0x10000 ++{"return": ""} ++write -P0x67 0x3fe0000 0x20000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 262144, ++ "granularity": 65536, ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": true, ++ "count": 589824, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "locked" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 9 dirty sectors; have 9. OK! ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Write #3 --- ++ ++write -P0xaa 0x0010000 0x30000 ++{"return": ""} ++write -P0xbb 0x00d8000 0x10000 ++{"return": ""} ++write -P0xcc 0x2028000 0x10000 ++{"return": ""} ++write -P0xdd 0x3fc0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 524288, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 8 dirty sectors; have 8. OK! ++ ++--- Reference mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_3", "sync": "full", "target": "ref_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_3"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_3", "sync": "bitmap", "target": "mirror_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"id": "mirror_3", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Cleanup --- ++ ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++{ ++ "bitmaps": {} ++} ++ ++--- Verification --- ++ ++qemu_img compare "TEST_DIR/PID-bsync1" "TEST_DIR/PID-fmirror1" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync2" "TEST_DIR/PID-fmirror2" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync3" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++ ++ ++=== Mode bitmap; Bitmap Sync always without failure === ++ ++--- Preparing image & VM --- ++ ++{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-img"}, "node-name": "drive0"}} ++{"return": {}} ++ ++--- Write #0 --- ++ ++write -P0x49 0x0000000 0x10000 ++{"return": ""} ++write -P0x6c 0x0100000 0x10000 ++{"return": ""} ++write -P0x6f 0x2000000 0x10000 ++{"return": ""} ++write -P0x76 0x3ff0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": {} ++} ++ ++--- Reference mirror #0 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_0", "sync": "full", "target": "ref_target_0"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_0"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Add Bitmap --- ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++ ++--- Write #1 --- ++ ++write -P0x65 0x0000000 0x10000 ++{"return": ""} ++write -P0x77 0x00f8000 0x10000 ++{"return": ""} ++write -P0x72 0x2008000 0x10000 ++{"return": ""} ++write -P0x69 0x3fe0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 6 dirty sectors; have 6. OK! ++ ++--- Reference mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_1", "sync": "full", "target": "ref_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_1"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #1 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_1", "sync": "bitmap", "target": "mirror_target_1"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_1"}} ++{"return": {}} ++{"data": {"id": "mirror_1", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_1", "len": 393216, "offset": 393216, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Reference mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_2", "sync": "full", "target": "ref_target_2"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_2"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #2 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_2", "sync": "bitmap", "target": "mirror_target_2"}} ++{"return": {}} ++--- Write #2 --- ++ ++write -P0x74 0x0010000 0x10000 ++{"return": ""} ++write -P0x69 0x00e8000 0x10000 ++{"return": ""} ++write -P0x6e 0x2018000 0x10000 ++{"return": ""} ++write -P0x67 0x3fe0000 0x20000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 458752, ++ "granularity": 65536, ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": true, ++ "count": 458752, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "locked" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 7 dirty sectors; have 7. OK! ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Write #3 --- ++ ++write -P0xaa 0x0010000 0x30000 ++{"return": ""} ++write -P0xbb 0x00d8000 0x10000 ++{"return": ""} ++write -P0xcc 0x2028000 0x10000 ++{"return": ""} ++write -P0xdd 0x3fc0000 0x10000 ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 524288, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 8 dirty sectors; have 8. OK! ++ ++--- Reference mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "ref_mirror_3", "sync": "full", "target": "ref_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "ref_mirror_3"}} ++{"return": {}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "ref_mirror_3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++ ++--- Test mirror #3 --- ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++{"execute": "blockdev-mirror", "arguments": {"auto-finalize": false, "bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "mirror_3", "sync": "bitmap", "target": "mirror_target_3"}} ++{"return": {}} ++{"execute": "job-complete", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"execute": "job-finalize", "arguments": {"id": "mirror_3"}} ++{"return": {}} ++{"data": {"id": "mirror_3", "type": "mirror"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"device": "mirror_3", "len": 524288, "offset": 524288, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "bitmap0", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++= Checking Bitmap bitmap0 = ++expecting 0 dirty sectors; have 0. OK! ++ ++--- Cleanup --- ++ ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++{ ++ "bitmaps": {} ++} ++ ++--- Verification --- ++ ++qemu_img compare "TEST_DIR/PID-bsync1" "TEST_DIR/PID-fmirror1" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-bsync2" "TEST_DIR/PID-fmirror2" ==> Mismatch, OK! ++qemu_img compare "TEST_DIR/PID-bsync3" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! ++ ++ ++=== API failure tests === ++ ++--- Preparing image & VM --- ++ ++{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-img"}, "node-name": "drive0"}} ++{"return": {}} ++ ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-file-job"}} ++{"return": {}} ++{} ++{} ++{"execute": "job-dismiss", "arguments": {"id": "bdc-fmt-job"}} ++{"return": {}} ++{} ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmap0", "node": "drive0"}} ++{"return": {}} ++ ++-- Testing invalid QMP commands -- ++ ++-- Sync mode incremental tests -- ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'incremental' not supported"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'incremental' not supported"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'incremental' not supported"}} ++ ++-- Sync mode bitmap tests -- ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Must provide a valid bitmap name for 'bitmap' sync mode"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++ ++-- Sync mode full tests -- ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++ ++-- Sync mode top tests -- ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++ ++-- Sync mode none tests -- ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "sync mode 'none' is not compatible with bitmaps"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "sync mode 'none' is not compatible with bitmaps"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "sync mode 'none' is not compatible with bitmaps"}} ++ ++{"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} ++{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++ +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 6b10a6a762..a4db887d5d 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -286,3 +286,4 @@ + 272 rw + 273 backing quick + 277 rw quick ++284 rw +-- +2.20.1 + diff --git a/debian/patches/pve/0039-mirror-move-some-checks-to-qmp.patch b/debian/patches/pve/0039-mirror-move-some-checks-to-qmp.patch new file mode 100644 index 0000000..4f18849 --- /dev/null +++ b/debian/patches/pve/0039-mirror-move-some-checks-to-qmp.patch @@ -0,0 +1,275 @@ +From 1beb9c370adff5e8c674d57e7a17672c0a8eaa2a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= +Date: Mon, 10 Feb 2020 10:15:16 +0100 +Subject: [PATCH qemu 39/39] mirror: move some checks to qmp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +and assert the passing conditions in block/mirror.c. while incremental +mode was never available for drive-mirror, it makes the interface more +uniform w.r.t. backup block jobs. + +Signed-off-by: Fabian Grünbichler +--- + block/mirror.c | 28 +++------------ + blockdev.c | 29 +++++++++++++++ + tests/qemu-iotests/284.out | 72 +++++++++++++++++++------------------- + 3 files changed, 70 insertions(+), 59 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index d6aca2874e..7a3373fca7 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -1562,31 +1562,13 @@ static BlockJob *mirror_start_job( + Error *local_err = NULL; + int ret; + +- if (sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { +- error_setg(errp, "Sync mode '%s' not supported", +- MirrorSyncMode_str(sync_mode)); +- return NULL; +- } else if (sync_mode == MIRROR_SYNC_MODE_BITMAP) { +- if (!bitmap) { +- error_setg(errp, "Must provide a valid bitmap name for '%s'" +- " sync mode", +- MirrorSyncMode_str(sync_mode)); +- return NULL; +- } +- } else if (bitmap) { +- error_setg(errp, +- "sync mode '%s' is not compatible with bitmaps", +- MirrorSyncMode_str(sync_mode)); +- return NULL; +- } ++ /* QMP interface protects us from these cases */ ++ assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL); ++ assert((bitmap && sync_mode == MIRROR_SYNC_MODE_BITMAP) || ++ (!bitmap && sync_mode != MIRROR_SYNC_MODE_BITMAP)); ++ assert(!(bitmap && granularity)); + + if (bitmap) { +- if (granularity) { +- error_setg(errp, "granularity (%d)" +- "cannot be specified when a bitmap is provided", +- granularity); +- return NULL; +- } + granularity = bdrv_dirty_bitmap_granularity(bitmap); + + if (bitmap_mode != BITMAP_SYNC_MODE_NEVER) { +diff --git a/blockdev.c b/blockdev.c +index 768a0b0fd4..4b196a2785 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3840,7 +3840,36 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, + sync = MIRROR_SYNC_MODE_FULL; + } + ++ if ((sync == MIRROR_SYNC_MODE_BITMAP) || ++ (sync == MIRROR_SYNC_MODE_INCREMENTAL)) { ++ /* done before desugaring 'incremental' to print the right message */ ++ if (!has_bitmap) { ++ error_setg(errp, "Must provide a valid bitmap name for " ++ "'%s' sync mode", MirrorSyncMode_str(sync)); ++ return; ++ } ++ } ++ ++ if (sync == MIRROR_SYNC_MODE_INCREMENTAL) { ++ if (has_bitmap_mode && ++ bitmap_mode != BITMAP_SYNC_MODE_ON_SUCCESS) { ++ error_setg(errp, "Bitmap sync mode must be '%s' " ++ "when using sync mode '%s'", ++ BitmapSyncMode_str(BITMAP_SYNC_MODE_ON_SUCCESS), ++ MirrorSyncMode_str(sync)); ++ return; ++ } ++ has_bitmap_mode = true; ++ sync = MIRROR_SYNC_MODE_BITMAP; ++ bitmap_mode = BITMAP_SYNC_MODE_ON_SUCCESS; ++ } ++ + if (has_bitmap) { ++ if (sync != MIRROR_SYNC_MODE_BITMAP) { ++ error_setg(errp, "Sync mode '%s' not supported with bitmap.", ++ MirrorSyncMode_str(sync)); ++ return; ++ } + if (granularity) { + error_setg(errp, "Granularity and bitmap cannot both be set"); + return; +diff --git a/tests/qemu-iotests/284.out b/tests/qemu-iotests/284.out +index 9b7408b6d6..06a2e29058 100644 +--- a/tests/qemu-iotests/284.out ++++ b/tests/qemu-iotests/284.out +@@ -2681,45 +2681,45 @@ qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! + -- Sync mode incremental tests -- + + {"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++{"error": {"class": "GenericError", "desc": "Must provide a valid bitmap name for 'incremental' sync mode"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++{"error": {"class": "GenericError", "desc": "Must provide a valid bitmap name for 'incremental' sync mode"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++{"error": {"class": "GenericError", "desc": "Must provide a valid bitmap name for 'incremental' sync mode"}} + + {"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Sync mode 'incremental' not supported"}} ++{"error": {"class": "GenericError", "desc": "Must provide a valid bitmap name for 'incremental' sync mode"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} + {"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++{"error": {"class": "GenericError", "desc": "Bitmap sync mode must be 'on-success' when using sync mode 'incremental'"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++{"error": {"class": "GenericError", "desc": "Bitmap sync mode must be 'on-success' when using sync mode 'incremental'"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Sync mode 'incremental' not supported"}} ++{"error": {"class": "GenericError", "desc": "Bitmap sync mode must be 'on-success' when using sync mode 'incremental'"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "incremental", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Sync mode 'incremental' not supported"}} ++{"error": {"class": "GenericError", "desc": "Bitmap sync mode must be 'on-success' when using sync mode 'incremental'"}} + + -- Sync mode bitmap tests -- + + {"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++{"error": {"class": "GenericError", "desc": "Must provide a valid bitmap name for 'bitmap' sync mode"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++{"error": {"class": "GenericError", "desc": "Must provide a valid bitmap name for 'bitmap' sync mode"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} ++{"error": {"class": "GenericError", "desc": "Must provide a valid bitmap name for 'bitmap' sync mode"}} + + {"execute": "blockdev-mirror", "arguments": {"device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "bitmap", "target": "mirror_target"}} + {"error": {"class": "GenericError", "desc": "Must provide a valid bitmap name for 'bitmap' sync mode"}} +@@ -2751,28 +2751,28 @@ qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! + {"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "full", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + -- Sync mode top tests -- + +@@ -2786,28 +2786,28 @@ qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! + {"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "sync mode 'full' is not compatible with bitmaps"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "top", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'full' not supported with bitmap."}} + + -- Sync mode none tests -- + +@@ -2821,26 +2821,26 @@ qemu_img compare "TEST_DIR/PID-img" "TEST_DIR/PID-fmirror3" ==> Identical, OK! + {"error": {"class": "GenericError", "desc": "Cannot specify bitmap sync mode without a bitmap"}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'none' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'none' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap404' not found"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'none' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap404", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'none' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "on-success", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "sync mode 'none' is not compatible with bitmaps"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'none' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "always", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "sync mode 'none' is not compatible with bitmaps"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'none' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "bitmap-mode": "never", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "sync mode 'none' is not compatible with bitmaps"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'none' not supported with bitmap."}} + + {"execute": "blockdev-mirror", "arguments": {"bitmap": "bitmap0", "device": "drive0", "filter-node-name": "mirror-top", "job-id": "api_job", "sync": "none", "target": "mirror_target"}} +-{"error": {"class": "GenericError", "desc": "bitmap-mode must be specified if a bitmap is provided"}} ++{"error": {"class": "GenericError", "desc": "Sync mode 'none' not supported with bitmap."}} + +-- +2.20.1 + diff --git a/debian/patches/series b/debian/patches/series index 627dff6..908213c 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -30,6 +30,12 @@ pve/0030-PVE-Backup-add-backup-dump-block-driver.patch pve/0031-PVE-Backup-proxmox-backup-patches-for-qemu.patch pve/0032-PVE-Backup-pbs-restore-new-command-to-restore-from-p.patch pve/0033-PVE-Backup-aquire-aio_context-before-calling-backup_.patch +pve/0034-drive-mirror-add-support-for-sync-bitmap-mode-never.patch +pve/0035-drive-mirror-add-support-for-conditional-and-always-.patch +pve/0036-mirror-add-check-for-bitmap-mode-without-bitmap.patch +pve/0037-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch +pve/0038-iotests-add-test-for-bitmap-mirror.patch +pve/0039-mirror-move-some-checks-to-qmp.patch security/0001-util-add-slirp_fmt-helpers.patch security/0002-tcp_emu-fix-unsafe-snprintf-usages.patch security/0003-ip_reass-Fix-use-after-free.patch