From patchwork Tue Feb 18 10:07:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= X-Patchwork-Id: 11388167 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 08DCC17EF for ; Tue, 18 Feb 2020 10:19:54 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CDAB621D56 for ; Tue, 18 Feb 2020 10:19:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CDAB621D56 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=proxmox.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:60076 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zyr-0001qv-1z for patchwork-qemu-devel@patchwork.kernel.org; Tue, 18 Feb 2020 05:19:53 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:48923) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zvD-000372-Bx for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1j3zvA-0007vH-Vq for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:07 -0500 Received: from proxmox-new.maurer-it.com ([212.186.127.180]:9013) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1j3zv4-0007re-Gk; Tue, 18 Feb 2020 05:15:58 -0500 Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id DBD3E41AA3; Tue, 18 Feb 2020 11:08:06 +0100 (CET) From: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= To: qemu-devel@nongnu.org Subject: [RFC qemu 1/6] drive-mirror: add support for sync=bitmap mode=never Date: Tue, 18 Feb 2020 11:07:35 +0100 Message-Id: <20200218100740.2228521-2-f.gruenbichler@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> References: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.186.127.180 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , qemu-block@nongnu.org, Ma Haocong , John Snow , Markus Armbruster , Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: John Snow 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 --- Note: this is just rebased, and broken - see patch #4 I intentionally kept those separate as initial RFC, they will be squashed in the next iteration! 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 640fb82c78..f0b747b09b 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -1175,7 +1175,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 c6a727cca9..8f7b7ba5eb 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3770,6 +3770,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, @@ -3788,6 +3792,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; @@ -3842,6 +3847,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; @@ -3879,8 +3907,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); } @@ -4021,6 +4049,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, @@ -4043,6 +4073,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, @@ -4093,7 +4125,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 13dad62f44..c63708e830 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1976,10 +1976,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). @@ -2017,7 +2026,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', @@ -2284,10 +2295,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 @@ -2336,7 +2356,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', From patchwork Tue Feb 18 10:07:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= X-Patchwork-Id: 11388161 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6A21B17EF for ; Tue, 18 Feb 2020 10:18:29 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4B5D921D56 for ; Tue, 18 Feb 2020 10:18:29 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4B5D921D56 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=proxmox.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:60052 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zxU-0008I8-Cp for patchwork-qemu-devel@patchwork.kernel.org; Tue, 18 Feb 2020 05:18:28 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:48875) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zv7-0002y0-SB for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:02 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1j3zv6-0007tU-Kv for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:01 -0500 Received: from proxmox-new.maurer-it.com ([212.186.127.180]:22125) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1j3zv3-0007qL-97; Tue, 18 Feb 2020 05:15:57 -0500 Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 7513D40B57; Tue, 18 Feb 2020 11:08:07 +0100 (CET) From: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= To: qemu-devel@nongnu.org Subject: [RFC qemu 2/6] drive-mirror: add support for conditional and always bitmap sync modes Date: Tue, 18 Feb 2020 11:07:36 +0100 Message-Id: <20200218100740.2228521-3-f.gruenbichler@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> References: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.186.127.180 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , qemu-block@nongnu.org, John Snow , Markus Armbruster , Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: John Snow 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. --- Note: original commit by John Snow , but missing SOB - please ACK/reply and I'll add it. This is also broken without patch #4, since it's fairly straight-forward we might even squash all three into a single commit? 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); } From patchwork Tue Feb 18 10:07:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= X-Patchwork-Id: 11388153 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6978217EF for ; Tue, 18 Feb 2020 10:16:56 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 48B86207FD for ; Tue, 18 Feb 2020 10:16:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 48B86207FD Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=proxmox.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:60022 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zvz-0004eM-Av for patchwork-qemu-devel@patchwork.kernel.org; Tue, 18 Feb 2020 05:16:55 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:48863) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zv7-0002xu-EQ for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:02 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1j3zv6-0007tE-E1 for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:01 -0500 Received: from proxmox-new.maurer-it.com ([212.186.127.180]:44942) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1j3zv3-0007qN-8f; Tue, 18 Feb 2020 05:15:57 -0500 Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 4722E41A82; Tue, 18 Feb 2020 11:08:08 +0100 (CET) From: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= To: qemu-devel@nongnu.org Subject: [RFC qemu 3/6] mirror: add check for bitmap-mode without bitmap Date: Tue, 18 Feb 2020 11:07:37 +0100 Message-Id: <20200218100740.2228521-4-f.gruenbichler@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> References: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.186.127.180 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , qemu-block@nongnu.org, John Snow , Markus Armbruster , Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" 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 8f7b7ba5eb..23df9f76ba 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3868,6 +3868,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) { From patchwork Tue Feb 18 10:07:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= X-Patchwork-Id: 11388163 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0E79A14E3 for ; Tue, 18 Feb 2020 10:18:34 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E26FF207FD for ; Tue, 18 Feb 2020 10:18:33 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E26FF207FD Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=proxmox.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:60056 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zxZ-0008Ph-4A for patchwork-qemu-devel@patchwork.kernel.org; Tue, 18 Feb 2020 05:18:33 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:48870) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zv7-0002xx-KW for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:02 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1j3zv6-0007tZ-Kk for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:01 -0500 Received: from proxmox-new.maurer-it.com ([212.186.127.180]:25357) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1j3zv3-0007qM-98; Tue, 18 Feb 2020 05:15:57 -0500 Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 486FA41CAA; Tue, 18 Feb 2020 11:08:09 +0100 (CET) From: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= To: qemu-devel@nongnu.org Subject: [RFC qemu 4/6] mirror: switch to bdrv_dirty_bitmap_merge_internal Date: Tue, 18 Feb 2020 11:07:38 +0100 Message-Id: <20200218100740.2228521-5-f.gruenbichler@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> References: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.186.127.180 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , qemu-block@nongnu.org, John Snow , Markus Armbruster , Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" 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; } From patchwork Tue Feb 18 10:07:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= X-Patchwork-Id: 11388157 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 36DBE17EF for ; Tue, 18 Feb 2020 10:17:32 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D986A207FD for ; Tue, 18 Feb 2020 10:17:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D986A207FD Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=proxmox.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:60026 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zwZ-0006JF-1R for patchwork-qemu-devel@patchwork.kernel.org; Tue, 18 Feb 2020 05:17:31 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:48949) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zvb-0003xd-Tn for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:42 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1j3zvR-00080M-66 for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:31 -0500 Received: from proxmox-new.maurer-it.com ([212.186.127.180]:21467) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1j3zv5-0007rg-HX; Tue, 18 Feb 2020 05:16:00 -0500 Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 5FAD441FEA; Tue, 18 Feb 2020 11:08:14 +0100 (CET) From: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= To: qemu-devel@nongnu.org Subject: [RFC qemu 5/6] iotests: add test for bitmap mirror Date: Tue, 18 Feb 2020 11:07:39 +0100 Message-Id: <20200218100740.2228521-6-f.gruenbichler@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> References: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.186.127.180 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , qemu-block@nongnu.org, John Snow , Markus Armbruster , Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" 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 as expected 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 1904223020..818380a8f0 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -290,3 +290,4 @@ 280 rw migration quick 281 rw quick 283 auto quick +284 rw From patchwork Tue Feb 18 10:07:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= X-Patchwork-Id: 11388155 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4E64117EF for ; Tue, 18 Feb 2020 10:16:57 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1F446207FD for ; Tue, 18 Feb 2020 10:16:57 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1F446207FD Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=proxmox.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:60024 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zw0-0004gw-6Q for patchwork-qemu-devel@patchwork.kernel.org; Tue, 18 Feb 2020 05:16:56 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:48915) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j3zvB-00035f-So for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:08 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1j3zv9-0007uc-8m for qemu-devel@nongnu.org; Tue, 18 Feb 2020 05:16:05 -0500 Received: from proxmox-new.maurer-it.com ([212.186.127.180]:58770) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1j3zv3-0007qI-Jm; Tue, 18 Feb 2020 05:15:57 -0500 Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id B7E91436DF; Tue, 18 Feb 2020 11:08:12 +0100 (CET) From: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= To: qemu-devel@nongnu.org Subject: [RFC qemu 6/6] mirror: move some checks to QMP Date: Tue, 18 Feb 2020 11:07:40 +0100 Message-Id: <20200218100740.2228521-7-f.gruenbichler@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> References: <20200218100740.2228521-1-f.gruenbichler@proxmox.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.186.127.180 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , qemu-block@nongnu.org, John Snow , Markus Armbruster , Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" 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 23df9f76ba..87bde0a4f4 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3847,7 +3847,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."}}