mirror of https://github.com/xemu-project/xemu.git
qmp: Add blockdev-mirror command
This will start a mirror job from a named device to another named device, its relation with drive-mirror is similar with blockdev-backup to drive-backup. In blockdev-mirror, the target node should be prepared by blockdev-add, which will be responsible for assigning a name to the new node, so we don't have 'node-name' parameter. Signed-off-by: Fam Zheng <famz@redhat.com> Acked-by: Markus Armbruster <armbru@redhat.com> Message-id: 1450932306-13717-5-git-send-email-famz@redhat.com Reviewed-by: Max Reitz <mreitz@redhat.com> Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
e40e5027f6
commit
df92562e68
62
blockdev.c
62
blockdev.c
|
@ -3345,6 +3345,10 @@ static void blockdev_mirror_common(BlockDriverState *bs,
|
||||||
if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_MIRROR_TARGET, errp)) {
|
if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_MIRROR_TARGET, errp)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (target->blk) {
|
||||||
|
error_setg(errp, "Cannot mirror to an attached block device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!bs->backing && sync == MIRROR_SYNC_MODE_TOP) {
|
if (!bs->backing && sync == MIRROR_SYNC_MODE_TOP) {
|
||||||
sync = MIRROR_SYNC_MODE_FULL;
|
sync = MIRROR_SYNC_MODE_FULL;
|
||||||
|
@ -3518,6 +3522,64 @@ out:
|
||||||
aio_context_release(aio_context);
|
aio_context_release(aio_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qmp_blockdev_mirror(const char *device, const char *target,
|
||||||
|
bool has_replaces, const char *replaces,
|
||||||
|
MirrorSyncMode sync,
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
BlockDriverState *bs;
|
||||||
|
BlockBackend *blk;
|
||||||
|
BlockDriverState *target_bs;
|
||||||
|
AioContext *aio_context;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
blk = blk_by_name(device);
|
||||||
|
if (!blk) {
|
||||||
|
error_setg(errp, "Device '%s' not found", device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bs = blk_bs(blk);
|
||||||
|
|
||||||
|
if (!bs) {
|
||||||
|
error_setg(errp, "Device '%s' has no media", device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_bs = bdrv_lookup_bs(target, target, errp);
|
||||||
|
if (!target_bs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
|
bdrv_ref(target_bs);
|
||||||
|
bdrv_set_aio_context(target_bs, aio_context);
|
||||||
|
|
||||||
|
blockdev_mirror_common(bs, target_bs,
|
||||||
|
has_replaces, replaces, sync,
|
||||||
|
has_speed, speed,
|
||||||
|
has_granularity, granularity,
|
||||||
|
has_buf_size, buf_size,
|
||||||
|
has_on_source_error, on_source_error,
|
||||||
|
has_on_target_error, on_target_error,
|
||||||
|
true, true,
|
||||||
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
bdrv_unref(target_bs);
|
||||||
|
}
|
||||||
|
|
||||||
|
aio_context_release(aio_context);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the block job for a given device name and acquire its AioContext */
|
/* Get the block job for a given device name and acquire its AioContext */
|
||||||
static BlockJob *find_block_job(const char *device, AioContext **aio_context,
|
static BlockJob *find_block_job(const char *device, AioContext **aio_context,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
|
|
|
@ -1183,6 +1183,54 @@
|
||||||
{ 'command': 'block-dirty-bitmap-clear',
|
{ 'command': 'block-dirty-bitmap-clear',
|
||||||
'data': 'BlockDirtyBitmap' }
|
'data': 'BlockDirtyBitmap' }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @blockdev-mirror
|
||||||
|
#
|
||||||
|
# Start mirroring a block device's writes to a new destination.
|
||||||
|
#
|
||||||
|
# @device: the name of the device whose writes should be mirrored.
|
||||||
|
#
|
||||||
|
# @target: the id or node-name of the block device to mirror to. This mustn't be
|
||||||
|
# attached to guest.
|
||||||
|
#
|
||||||
|
# @replaces: #optional with sync=full graph node name to be replaced by the new
|
||||||
|
# image when a whole image copy is done. This can be used to repair
|
||||||
|
# broken Quorum files.
|
||||||
|
#
|
||||||
|
# @speed: #optional the maximum speed, in bytes per second
|
||||||
|
#
|
||||||
|
# @sync: what parts of the disk image should be copied to the destination
|
||||||
|
# (all the disk, only the sectors allocated in the topmost image, or
|
||||||
|
# only new I/O).
|
||||||
|
#
|
||||||
|
# @granularity: #optional 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
|
||||||
|
#
|
||||||
|
# @buf-size: #optional maximum amount of data in flight from source to
|
||||||
|
# target
|
||||||
|
#
|
||||||
|
# @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).
|
||||||
|
#
|
||||||
|
# @on-target-error: #optional the action to take on an error on the target,
|
||||||
|
# default 'report' (no limitations, since this applies to
|
||||||
|
# a different block device than @device).
|
||||||
|
#
|
||||||
|
# Returns: nothing on success.
|
||||||
|
#
|
||||||
|
# Since 2.6
|
||||||
|
##
|
||||||
|
{ 'command': 'blockdev-mirror',
|
||||||
|
'data': { 'device': 'str', 'target': 'str',
|
||||||
|
'*replaces': 'str',
|
||||||
|
'sync': 'MirrorSyncMode',
|
||||||
|
'*speed': 'int', '*granularity': 'uint32',
|
||||||
|
'*buf-size': 'int', '*on-source-error': 'BlockdevOnError',
|
||||||
|
'*on-target-error': 'BlockdevOnError' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block_set_io_throttle:
|
# @block_set_io_throttle:
|
||||||
#
|
#
|
||||||
|
|
|
@ -1635,7 +1635,7 @@ 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
|
- "buf-size": maximum amount of data in flight from source to target, in bytes
|
||||||
(json-int, default 10M)
|
(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
|
||||||
|
@ -1664,6 +1664,54 @@ Example:
|
||||||
|
|
||||||
EQMP
|
EQMP
|
||||||
|
|
||||||
|
{
|
||||||
|
.name = "blockdev-mirror",
|
||||||
|
.args_type = "sync:s,device:B,target:B,replaces:s?,speed:i?,"
|
||||||
|
"on-source-error:s?,on-target-error:s?,"
|
||||||
|
"granularity:i?,buf-size:i?",
|
||||||
|
.mhandler.cmd_new = qmp_marshal_blockdev_mirror,
|
||||||
|
},
|
||||||
|
|
||||||
|
SQMP
|
||||||
|
blockdev-mirror
|
||||||
|
------------
|
||||||
|
|
||||||
|
Start mirroring a block device's writes to another block device. target
|
||||||
|
specifies the target of mirror operation.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
- "device": device name to operate on (json-string)
|
||||||
|
- "target": device name to mirror to (json-string)
|
||||||
|
- "replaces": the block driver node name to replace when finished
|
||||||
|
(json-string, optional)
|
||||||
|
- "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
|
||||||
|
(MirrorSyncMode).
|
||||||
|
- "on-source-error": the action to take on an error on the source
|
||||||
|
(BlockdevOnError, default 'report')
|
||||||
|
- "on-target-error": the action to take on an error on the target
|
||||||
|
(BlockdevOnError, default 'report')
|
||||||
|
|
||||||
|
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
|
||||||
|
does not define a cluster size, the default value of the granularity
|
||||||
|
is 65536.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
-> { "execute": "blockdev-mirror", "arguments": { "device": "ide-hd0",
|
||||||
|
"target": "target0",
|
||||||
|
"sync": "full" } }
|
||||||
|
<- { "return": {} }
|
||||||
|
|
||||||
|
EQMP
|
||||||
{
|
{
|
||||||
.name = "change-backing-file",
|
.name = "change-backing-file",
|
||||||
.args_type = "device:s,image-node-name:s,backing-file:s",
|
.args_type = "device:s,image-node-name:s,backing-file:s",
|
||||||
|
|
Loading…
Reference in New Issue