mirror: add buf-size argument to drive-mirror

This makes sense when the next commit starts using the extra buffer space
to perform many I/O operations asynchronously.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Paolo Bonzini 2013-01-22 09:03:13 +01:00 committed by Kevin Wolf
parent bd48bde8f0
commit 08e4ed6cde
8 changed files with 56 additions and 12 deletions

View File

@ -207,7 +207,7 @@ static void coroutine_fn mirror_run(void *opaque)
if (backing_filename[0] && !s->target->backing_hd) { if (backing_filename[0] && !s->target->backing_hd) {
bdrv_get_info(s->target, &bdi); bdrv_get_info(s->target, &bdi);
if (s->granularity < bdi.cluster_size) { 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; length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity;
s->cow_bitmap = bitmap_new(length); s->cow_bitmap = bitmap_new(length);
} }
@ -416,8 +416,8 @@ static BlockJobType mirror_job_type = {
}; };
void mirror_start(BlockDriverState *bs, BlockDriverState *target, void mirror_start(BlockDriverState *bs, BlockDriverState *target,
int64_t speed, int64_t granularity, MirrorSyncMode mode, int64_t speed, int64_t granularity, int64_t buf_size,
BlockdevOnError on_source_error, MirrorSyncMode mode, BlockdevOnError on_source_error,
BlockdevOnError on_target_error, BlockdevOnError on_target_error,
BlockDriverCompletionFunc *cb, BlockDriverCompletionFunc *cb,
void *opaque, Error **errp) void *opaque, Error **errp)
@ -455,7 +455,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
s->target = target; s->target = target;
s->mode = mode; s->mode = mode;
s->granularity = granularity; s->granularity = granularity;
s->buf_size = granularity; s->buf_size = MAX(buf_size, granularity);
bdrv_set_dirty_tracking(bs, granularity); bdrv_set_dirty_tracking(bs, granularity);
bdrv_set_enable_write_cache(s->target, true); bdrv_set_enable_write_cache(s->target, true);

View File

@ -1188,12 +1188,15 @@ void qmp_block_commit(const char *device,
drive_get_ref(drive_get_by_blockdev(bs)); 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, void qmp_drive_mirror(const char *device, const char *target,
bool has_format, const char *format, bool has_format, const char *format,
enum MirrorSyncMode sync, enum MirrorSyncMode sync,
bool has_mode, enum NewImageMode mode, bool has_mode, enum NewImageMode mode,
bool has_speed, int64_t speed, bool has_speed, int64_t speed,
bool has_granularity, uint32_t granularity, 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_source_error, BlockdevOnError on_source_error,
bool has_on_target_error, BlockdevOnError on_target_error, bool has_on_target_error, BlockdevOnError on_target_error,
Error **errp) Error **errp)
@ -1222,6 +1225,10 @@ void qmp_drive_mirror(const char *device, const char *target,
if (!has_granularity) { if (!has_granularity) {
granularity = 0; granularity = 0;
} }
if (!has_buf_size) {
buf_size = DEFAULT_MIRROR_BUF_SIZE;
}
if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) { if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {
error_set(errp, QERR_INVALID_PARAMETER, device); error_set(errp, QERR_INVALID_PARAMETER, device);
return; return;
@ -1311,7 +1318,7 @@ void qmp_drive_mirror(const char *device, const char *target,
return; 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, on_source_error, on_target_error,
block_job_cb, bs, &local_err); block_job_cb, bs, &local_err);
if (local_err != NULL) { if (local_err != NULL) {

2
hmp.c
View File

@ -796,7 +796,7 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
qmp_drive_mirror(device, filename, !!format, format, qmp_drive_mirror(device, filename, !!format, format,
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP, 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); false, 0, false, 0, &errp);
hmp_handle_error(mon, &errp); hmp_handle_error(mon, &errp);
} }

View File

@ -345,6 +345,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
* @target: Block device to write to. * @target: Block device to write to.
* @speed: The maximum speed, in bytes per second, or 0 for unlimited. * @speed: The maximum speed, in bytes per second, or 0 for unlimited.
* @granularity: The chosen granularity for the dirty bitmap. * @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. * @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_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. * @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. * @bs will be switched to read from @target.
*/ */
void mirror_start(BlockDriverState *bs, BlockDriverState *target, void mirror_start(BlockDriverState *bs, BlockDriverState *target,
int64_t speed, int64_t granularity, MirrorSyncMode mode, int64_t speed, int64_t granularity, int64_t buf_size,
BlockdevOnError on_source_error, MirrorSyncMode mode, BlockdevOnError on_source_error,
BlockdevOnError on_target_error, BlockdevOnError on_target_error,
BlockDriverCompletionFunc *cb, BlockDriverCompletionFunc *cb,
void *opaque, Error **errp); void *opaque, Error **errp);

View File

@ -1641,6 +1641,9 @@
# are smaller than that, else the cluster size. Must be a # 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 (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, # @on-source-error: #optional the action to take on an error on the source,
# default 'report'. 'stop' and 'enospc' can only be used # default 'report'. 'stop' and 'enospc' can only be used
# if the block device supports io-status (see BlockInfo). # if the block device supports io-status (see BlockInfo).
@ -1658,7 +1661,7 @@
'data': { 'device': 'str', 'target': 'str', '*format': 'str', 'data': { 'device': 'str', 'target': 'str', '*format': 'str',
'sync': 'MirrorSyncMode', '*mode': 'NewImageMode', 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode',
'*speed': 'int', '*granularity': 'uint32', '*speed': 'int', '*granularity': 'uint32',
'*on-source-error': 'BlockdevOnError', '*buf-size': 'int', '*on-source-error': 'BlockdevOnError',
'*on-target-error': 'BlockdevOnError' } } '*on-target-error': 'BlockdevOnError' } }
## ##

View File

@ -939,7 +939,7 @@ EQMP
.name = "drive-mirror", .name = "drive-mirror",
.args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?," .args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?,"
"on-source-error:s?,on-target-error:s?," "on-source-error:s?,on-target-error:s?,"
"granularity:i?", "granularity:i?,buf-size:i?",
.mhandler.cmd_new = qmp_marshal_input_drive_mirror, .mhandler.cmd_new = qmp_marshal_input_drive_mirror,
}, },
@ -964,6 +964,8 @@ Arguments:
- "speed": maximum speed of the streaming job, in bytes per second - "speed": maximum speed of the streaming job, in bytes per second
(json-int) (json-int)
- "granularity": granularity of the dirty bitmap, in bytes (json-int, optional) - "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; - "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 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 allocated in the topmost image, or "none" to only replicate new I/O

View File

@ -207,6 +207,37 @@ class TestSingleDrive(ImageMirroringTestCase):
self.assertTrue(self.compare_images(test_img, target_img), self.assertTrue(self.compare_images(test_img, target_img),
'target image does not match source after mirroring') '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): def test_large_cluster(self):
self.assert_no_active_mirrors() self.assert_no_active_mirrors()

View File

@ -1,5 +1,5 @@
.................... ......................
---------------------------------------------------------------------- ----------------------------------------------------------------------
Ran 20 tests Ran 22 tests
OK OK