mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-07-08 20:17:27 +00:00
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)) {
|
||||
return;
|
||||
}
|
||||
if (target->blk) {
|
||||
error_setg(errp, "Cannot mirror to an attached block device");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bs->backing && sync == MIRROR_SYNC_MODE_TOP) {
|
||||
sync = MIRROR_SYNC_MODE_FULL;
|
||||
|
@ -3518,6 +3522,64 @@ out:
|
|||
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 */
|
||||
static BlockJob *find_block_job(const char *device, AioContext **aio_context,
|
||||
Error **errp)
|
||||
|
|
|
@ -1183,6 +1183,54 @@
|
|||
{ 'command': 'block-dirty-bitmap-clear',
|
||||
'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:
|
||||
#
|
||||
|
|
|
@ -1635,7 +1635,7 @@ 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
|
||||
- "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
|
||||
|
@ -1664,6 +1664,54 @@ Example:
|
|||
|
||||
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",
|
||||
.args_type = "device:s,image-node-name:s,backing-file:s",
|
||||
|
|
Loading…
Reference in New Issue
Block a user