From patchwork Fri Jun 3 14:05:11 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Sementsov-Ogievskiy X-Patchwork-Id: 9153169 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 67E366074E for ; Fri, 3 Jun 2016 14:06:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 581A02780C for ; Fri, 3 Jun 2016 14:06:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4C2202832F; Fri, 3 Jun 2016 14:06:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 200102780C for ; Fri, 3 Jun 2016 14:06:13 +0000 (UTC) Received: from localhost ([::1]:55754 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b8pjo-0000eZ-A8 for patchwork-qemu-devel@patchwork.kernel.org; Fri, 03 Jun 2016 10:06:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47725) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b8pjQ-0000bs-2k for qemu-devel@nongnu.org; Fri, 03 Jun 2016 10:05:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1b8pjL-00071R-PN for qemu-devel@nongnu.org; Fri, 03 Jun 2016 10:05:46 -0400 Received: from mailhub.sw.ru ([195.214.232.25]:42781 helo=relay.sw.ru) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b8pjK-00071N-UA for qemu-devel@nongnu.org; Fri, 03 Jun 2016 10:05:43 -0400 Received: from s180.qa.sw.ru ([10.94.3.55]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id u53E5K9p001057; Fri, 3 Jun 2016 17:05:22 +0300 (MSK) From: Vladimir Sementsov-Ogievskiy To: qemu-devel@nongnu.org Date: Fri, 3 Jun 2016 17:05:11 +0300 Message-Id: <1464962711-617992-1-git-send-email-vsementsov@virtuozzo.com> X-Mailer: git-send-email 1.8.3.1 X-detected-operating-system: by eggs.gnu.org: OpenBSD 3.x X-Received-From: 195.214.232.25 Subject: [Qemu-devel] [PATCH] mirror: add target-zeroed flag X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, Vladimir Sementsov-Ogievskiy , den@virtuozzo.com, qemu-block@nongnu.org, jcody@redhat.com, armbru@redhat.com, mreitz@redhat.com, lcapitulino@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Add target-zeroed flag to allow user specify that target is already zeroed. With this flag set zeroes which was in source before mirror start will not be copyed. Without this libvirt migration of empty disk takes too long time. Signed-off-by: Vladimir Sementsov-Ogievskiy --- I've tested it with time virsh migrate --live test qemu+ssh://other_node/system --copy-storage-all Without 'target-zeroed' libvirt migration of vm with empty qcow2 disk of 400Mb to another node takes for me more than 5 minutes. Migration of 5Gb disk was not finished in 28 minutes. With new flag on, migration of 16Tb empty disk takes about a minute. block/mirror.c | 16 +++++++++++----- blockdev.c | 9 ++++++++- hmp.c | 2 +- include/block/block_int.h | 2 +- qapi/block-core.json | 5 ++++- qmp-commands.hx | 4 +++- 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 80fd3c7..9604cae 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -65,6 +65,8 @@ typedef struct MirrorBlockJob { bool waiting_for_io; int target_cluster_sectors; int max_iov; + + bool target_zeroed; } MirrorBlockJob; typedef struct MirrorOp { @@ -570,7 +572,9 @@ static void coroutine_fn mirror_run(void *opaque) if (!s->is_none_mode) { /* First part, loop on the sectors and initialize the dirty bitmap. */ BlockDriverState *base = s->base; - bool mark_all_dirty = s->base == NULL && !bdrv_has_zero_init(target_bs); + + bool mark_all_dirty = s->base == NULL && + !(s->target_zeroed || bdrv_has_zero_init(target_bs)); for (sector_num = 0; sector_num < end; ) { /* Just to make sure we are not exceeding int limit. */ @@ -801,7 +805,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, int64_t buf_size, BlockdevOnError on_source_error, BlockdevOnError on_target_error, - bool unmap, + bool unmap, bool target_zeroed, BlockCompletionFunc *cb, void *opaque, Error **errp, const BlockJobDriver *driver, @@ -840,6 +844,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, s->granularity = granularity; s->buf_size = ROUND_UP(buf_size, granularity); s->unmap = unmap; + s->target_zeroed = target_zeroed; s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp); if (!s->dirty_bitmap) { @@ -861,7 +866,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, int64_t speed, uint32_t granularity, int64_t buf_size, MirrorSyncMode mode, BlockdevOnError on_source_error, BlockdevOnError on_target_error, - bool unmap, + bool unmap, bool target_zeroed, BlockCompletionFunc *cb, void *opaque, Error **errp) { @@ -876,7 +881,8 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL; mirror_start_job(bs, target, replaces, speed, granularity, buf_size, - on_source_error, on_target_error, unmap, cb, opaque, errp, + on_source_error, on_target_error, unmap, target_zeroed, + cb, opaque, errp, &mirror_job_driver, is_none_mode, base); } @@ -923,7 +929,7 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base, } mirror_start_job(bs, base, NULL, speed, 0, 0, - on_error, on_error, false, cb, opaque, &local_err, + on_error, on_error, false, false, cb, opaque, &local_err, &commit_active_job_driver, false, base); if (local_err) { error_propagate(errp, local_err); diff --git a/blockdev.c b/blockdev.c index 717785e..f70fb1d 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3418,6 +3418,7 @@ static void blockdev_mirror_common(BlockDriverState *bs, bool has_on_target_error, BlockdevOnError on_target_error, bool has_unmap, bool unmap, + bool has_target_zeroed, bool target_zeroed, Error **errp) { @@ -3439,6 +3440,9 @@ static void blockdev_mirror_common(BlockDriverState *bs, if (!has_unmap) { unmap = true; } + if (!has_target_zeroed) { + target_zeroed = false; + } if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "granularity", @@ -3468,7 +3472,7 @@ static void blockdev_mirror_common(BlockDriverState *bs, mirror_start(bs, target, has_replaces ? replaces : NULL, speed, granularity, buf_size, sync, - on_source_error, on_target_error, unmap, + on_source_error, on_target_error, unmap, target_zeroed, block_job_cb, bs, errp); } @@ -3484,6 +3488,7 @@ void qmp_drive_mirror(const char *device, const char *target, bool has_on_source_error, BlockdevOnError on_source_error, bool has_on_target_error, BlockdevOnError on_target_error, bool has_unmap, bool unmap, + bool has_target_zeroed, bool target_zeroed, Error **errp) { BlockDriverState *bs; @@ -3618,6 +3623,7 @@ void qmp_drive_mirror(const char *device, const char *target, has_on_source_error, on_source_error, has_on_target_error, on_target_error, has_unmap, unmap, + has_target_zeroed, target_zeroed, &local_err); bdrv_unref(target_bs); if (local_err) { @@ -3675,6 +3681,7 @@ void qmp_blockdev_mirror(const char *device, const char *target, has_on_source_error, on_source_error, has_on_target_error, on_target_error, true, true, + true, false, &local_err); if (local_err) { error_propagate(errp, local_err); diff --git a/hmp.c b/hmp.c index a4b1d3d..5574dad 100644 --- a/hmp.c +++ b/hmp.c @@ -1097,7 +1097,7 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict) false, NULL, false, NULL, full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP, true, mode, false, 0, false, 0, false, 0, - false, 0, false, 0, false, true, &err); + false, 0, false, 0, false, true, false, false, &err); hmp_handle_error(mon, &err); } diff --git a/include/block/block_int.h b/include/block/block_int.h index 30a9717..f19ff88 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -687,7 +687,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, int64_t speed, uint32_t granularity, int64_t buf_size, MirrorSyncMode mode, BlockdevOnError on_source_error, BlockdevOnError on_target_error, - bool unmap, + bool unmap, bool target_zeroed, BlockCompletionFunc *cb, void *opaque, Error **errp); diff --git a/qapi/block-core.json b/qapi/block-core.json index 98a20d2..a2b3706 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1154,6 +1154,9 @@ # written. Both will result in identical contents. # Default is true. (Since 2.4) # +# @target-zeroed: #optional Whether target is already zeroed, so most of zeroes +# should not be transferred. (Since 2.7) +# # Returns: nothing on success # If @device is not a valid block device, DeviceNotFound # @@ -1166,7 +1169,7 @@ '*speed': 'int', '*granularity': 'uint32', '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError', - '*unmap': 'bool' } } + '*unmap': 'bool', '*target-zeroed': 'bool' } } ## # @BlockDirtyBitmap diff --git a/qmp-commands.hx b/qmp-commands.hx index 28801a2..1c1d454 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1632,7 +1632,7 @@ EQMP .args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?," "node-name:s?,replaces:s?," "on-source-error:s?,on-target-error:s?," - "unmap:b?," + "unmap:b?,target-zeroed:b?" "granularity:i?,buf-size:i?", .mhandler.cmd_new = qmp_marshal_drive_mirror, }, @@ -1674,6 +1674,8 @@ Arguments: (BlockdevOnError, default 'report') - "unmap": whether the target sectors should be discarded where source has only zeroes. (json-bool, optional, default true) +- "target-zeroed": whether target is already zeroed, so most of zeroes should + not be transferred. (json-bool, optional, default false) The default value of the granularity is the image cluster size clamped between 4096 and 65536, if the image format defines one. If the format