From patchwork Mon Jan 21 16:09:48 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 214201 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 22D312C0084 for ; Tue, 22 Jan 2013 03:10:55 +1100 (EST) Received: from localhost ([::1]:58998 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TxJxU-000179-UM for incoming@patchwork.ozlabs.org; Mon, 21 Jan 2013 11:10:52 -0500 Received: from eggs.gnu.org ([208.118.235.92]:44970) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TxJx3-0000qi-VW for qemu-devel@nongnu.org; Mon, 21 Jan 2013 11:10:28 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TxJwx-0000Lv-In for qemu-devel@nongnu.org; Mon, 21 Jan 2013 11:10:25 -0500 Received: from mail-ee0-f48.google.com ([74.125.83.48]:61424) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TxJwx-0000Lf-9J for qemu-devel@nongnu.org; Mon, 21 Jan 2013 11:10:19 -0500 Received: by mail-ee0-f48.google.com with SMTP id t10so2898199eei.7 for ; Mon, 21 Jan 2013 08:10:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:sender:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references; bh=19w9/7gQlPPcGW0a6wguSRJL1xDbHDvN2fwBbHdH7ag=; b=LBPO2S/HZ68b0+K/rYje/1B7TGF5+I3u3KBgfbbxeisrOHdtIVOVhxWBAFaPS5o/bZ V2PlOPwKa7UVYJqlKV9+l/jMjKhwHoBpaegUaO+UfP3tzxwFhoyYtkG0yaH/JrOrNfkt E83ue2Hw8HC1V6WkloVnAJQDWV6WcuDNX9T4e/QOjfwQHAbdirxUw72/+3rLsaAChhxV JlAVNL/DgF/c5qIHvaskRTNlc0RzwLa/GQrEOq/dflraffLO391a0BDtTgeWl5PmPGXR YAgLCfhaM88ZidCn8hXhTj5aao3clMsubtOGnrrvmzzcZ6RsHLWeOdNs9uxbIM3Oj1Xw aUCw== X-Received: by 10.14.3.195 with SMTP id 43mr61459239eeh.36.1358784618516; Mon, 21 Jan 2013 08:10:18 -0800 (PST) Received: from yakj.lan (93-34-179-137.ip50.fastwebnet.it. [93.34.179.137]) by mx.google.com with ESMTPS id q5sm7892408eeo.17.2013.01.21.08.10.16 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 21 Jan 2013 08:10:17 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2013 17:09:48 +0100 Message-Id: <1358784590-16288-11-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.1 In-Reply-To: <1358784590-16288-1-git-send-email-pbonzini@redhat.com> References: <1358784590-16288-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 74.125.83.48 Cc: kwolf@redhat.com, stefanha@redhat.com Subject: [Qemu-devel] [PATCH v3 10/12] mirror: add buf-size argument to drive-mirror X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This makes sense when the next commit starts using the extra buffer space to perform many I/O operations asynchronously. Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini --- v2->v3: Add "since 1.4" notes to qapi-schema.json [Eric]. Add MAX when updating s->buf_size in the COW case (new because the "if" now tests s->granularity, it used to test s->buf_size). block/mirror.c | 8 ++++---- blockdev.c | 9 ++++++++- hmp.c | 2 +- include/block/block_int.h | 5 +++-- qapi-schema.json | 5 ++++- qmp-commands.hx | 4 +++- roms/seabios | 2 +- tests/qemu-iotests/041 | 31 +++++++++++++++++++++++++++++++ tests/qemu-iotests/041.out | 4 ++-- 9 files changed, 57 insertions(+), 13 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index da5a714..0582415 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -205,7 +205,7 @@ static void coroutine_fn mirror_run(void *opaque) if (backing_filename[0] && !s->target->backing_hd) { bdrv_get_info(s->target, &bdi); if (s->granularity < bdi.cluster_size) { - s->buf_size = bdi.cluster_size; + s->buf_size = MAX(s->buf_size, bdi.cluster_size); length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity; s->cow_bitmap = bitmap_new(length); } @@ -414,8 +414,8 @@ static BlockJobType mirror_job_type = { }; void mirror_start(BlockDriverState *bs, BlockDriverState *target, - int64_t speed, int64_t granularity, MirrorSyncMode mode, - BlockdevOnError on_source_error, + int64_t speed, int64_t granularity, int64_t buf_size, + MirrorSyncMode mode, BlockdevOnError on_source_error, BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp) @@ -453,7 +453,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, s->target = target; s->mode = mode; s->granularity = granularity; - s->buf_size = granularity; + s->buf_size = MAX(buf_size, granularity); bdrv_set_dirty_tracking(bs, granularity); bdrv_set_enable_write_cache(s->target, true); diff --git a/blockdev.c b/blockdev.c index 07fd327..ad25b9b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1188,12 +1188,15 @@ void qmp_block_commit(const char *device, drive_get_ref(drive_get_by_blockdev(bs)); } +#define DEFAULT_MIRROR_BUF_SIZE (10 << 20) + void qmp_drive_mirror(const char *device, const char *target, bool has_format, const char *format, enum MirrorSyncMode sync, bool has_mode, enum NewImageMode mode, bool has_speed, int64_t speed, bool has_granularity, uint32_t granularity, + bool has_buf_size, int64_t buf_size, bool has_on_source_error, BlockdevOnError on_source_error, bool has_on_target_error, BlockdevOnError on_target_error, Error **errp) @@ -1222,6 +1225,10 @@ void qmp_drive_mirror(const char *device, const char *target, if (!has_granularity) { granularity = 0; } + if (!has_buf_size) { + buf_size = DEFAULT_MIRROR_BUF_SIZE; + } + if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) { error_set(errp, QERR_INVALID_PARAMETER, device); return; @@ -1311,7 +1318,7 @@ void qmp_drive_mirror(const char *device, const char *target, return; } - mirror_start(bs, target_bs, speed, granularity, sync, + mirror_start(bs, target_bs, speed, granularity, buf_size, sync, on_source_error, on_target_error, block_job_cb, bs, &local_err); if (local_err != NULL) { diff --git a/hmp.c b/hmp.c index 0f3347d..99fd892 100644 --- a/hmp.c +++ b/hmp.c @@ -796,7 +796,7 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict) qmp_drive_mirror(device, filename, !!format, format, full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP, - true, mode, false, 0, false, 0, + true, mode, false, 0, false, 0, false, 0, false, 0, false, 0, &errp); hmp_handle_error(mon, &errp); } diff --git a/include/block/block_int.h b/include/block/block_int.h index 1165339..f7279b9 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -345,6 +345,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, * @target: Block device to write to. * @speed: The maximum speed, in bytes per second, or 0 for unlimited. * @granularity: The chosen granularity for the dirty bitmap. + * @buf_size: The amount of data that can be in flight at one time. * @mode: Whether to collapse all images in the chain to the target. * @on_source_error: The action to take upon error reading from the source. * @on_target_error: The action to take upon error writing to the target. @@ -358,8 +359,8 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, * @bs will be switched to read from @target. */ void mirror_start(BlockDriverState *bs, BlockDriverState *target, - int64_t speed, int64_t granularity, MirrorSyncMode mode, - BlockdevOnError on_source_error, + int64_t speed, int64_t granularity, int64_t buf_size, + MirrorSyncMode mode, BlockdevOnError on_source_error, BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp); diff --git a/qapi-schema.json b/qapi-schema.json index fd5ec93..ba75c4d 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1641,6 +1641,9 @@ # are smaller than that, else the cluster size. Must be a # power of 2 between 512 and 64M (since 1.4). # +# @buf-size: #optional maximum amount of data in flight from source to +# target (since 1.4). +# # @on-source-error: #optional the action to take on an error on the source, # default 'report'. 'stop' and 'enospc' can only be used # if the block device supports io-status (see BlockInfo). @@ -1658,7 +1661,7 @@ 'data': { 'device': 'str', 'target': 'str', '*format': 'str', 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode', '*speed': 'int', '*granularity': 'uint32', - '*on-source-error': 'BlockdevOnError', + '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError' } } ## diff --git a/qmp-commands.hx b/qmp-commands.hx index 835ea26..273b4a6 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -939,7 +939,7 @@ EQMP .name = "drive-mirror", .args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?," "on-source-error:s?,on-target-error:s?," - "granularity:i?", + "granularity:i?,buf-size:i?", .mhandler.cmd_new = qmp_marshal_input_drive_mirror, }, @@ -964,6 +964,8 @@ Arguments: - "speed": maximum speed of the streaming job, in bytes per second (json-int) - "granularity": granularity of the dirty bitmap, in bytes (json-int, optional) +- "buf_size": maximum amount of data in flight from source to target, in bytes + (json-int, default 10M) - "sync": what parts of the disk image should be copied to the destination; possibilities include "full" for all the disk, "top" for only the sectors allocated in the topmost image, or "none" to only replicate new I/O diff --git a/roms/seabios b/roms/seabios index a810e4e..e8a76b0 160000 --- a/roms/seabios +++ b/roms/seabios @@ -1 +1 @@ -Subproject commit a810e4e72a0d42c7bc04eda57382f8e019add901 +Subproject commit e8a76b0f225bba5ba9d63ab227e0a37b3beb1059 diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index a1299b3..b040820 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -207,6 +207,37 @@ class TestSingleDrive(ImageMirroringTestCase): self.assertTrue(self.compare_images(test_img, target_img), 'target image does not match source after mirroring') + def test_small_buffer(self): + self.assert_no_active_mirrors() + + # A small buffer is rounded up automatically + result = self.vm.qmp('drive-mirror', device='drive0', sync='full', + buf_size=4096, target=target_img) + self.assert_qmp(result, 'return', {}) + + self.complete_and_wait() + result = self.vm.qmp('query-block') + self.assert_qmp(result, 'return[0]/inserted/file', target_img) + self.vm.shutdown() + self.assertTrue(self.compare_images(test_img, target_img), + 'target image does not match source after mirroring') + + def test_small_buffer2(self): + self.assert_no_active_mirrors() + + qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d' + % (TestSingleDrive.image_len, TestSingleDrive.image_len), target_img) + result = self.vm.qmp('drive-mirror', device='drive0', sync='full', + buf_size=65536, mode='existing', target=target_img) + self.assert_qmp(result, 'return', {}) + + self.complete_and_wait() + result = self.vm.qmp('query-block') + self.assert_qmp(result, 'return[0]/inserted/file', target_img) + self.vm.shutdown() + self.assertTrue(self.compare_images(test_img, target_img), + 'target image does not match source after mirroring') + def test_large_cluster(self): self.assert_no_active_mirrors() diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out index 3a89159..84bfd63 100644 --- a/tests/qemu-iotests/041.out +++ b/tests/qemu-iotests/041.out @@ -1,5 +1,5 @@ -.................... +...................... ---------------------------------------------------------------------- -Ran 20 tests +Ran 22 tests OK