提交 08e4ed6c 编写于 作者: P Paolo Bonzini 提交者: Kevin Wolf

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: NPaolo Bonzini <pbonzini@redhat.com>
Signed-off-by: NKevin Wolf <kwolf@redhat.com>
上级 bd48bde8
...@@ -207,7 +207,7 @@ static void coroutine_fn mirror_run(void *opaque) ...@@ -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 = { ...@@ -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, ...@@ -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);
......
...@@ -1188,12 +1188,15 @@ void qmp_block_commit(const char *device, ...@@ -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, ...@@ -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, ...@@ -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) {
......
...@@ -796,7 +796,7 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict) ...@@ -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);
} }
......
...@@ -345,6 +345,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, ...@@ -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, ...@@ -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);
......
...@@ -1641,6 +1641,9 @@ ...@@ -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 @@ ...@@ -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' } }
## ##
......
...@@ -939,7 +939,7 @@ EQMP ...@@ -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: ...@@ -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
......
...@@ -207,6 +207,37 @@ class TestSingleDrive(ImageMirroringTestCase): ...@@ -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()
......
.................... ......................
---------------------------------------------------------------------- ----------------------------------------------------------------------
Ran 20 tests Ran 22 tests
OK OK
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册