aboutsummaryrefslogtreecommitdiff
path: root/blockdev.c
diff options
context:
space:
mode:
authorFam Zheng <famz@redhat.com>2015-12-24 12:45:05 +0800
committerMax Reitz <mreitz@redhat.com>2016-01-07 21:30:18 +0100
commitdf92562e68d6676a52faeaf20e87526ceaa28003 (patch)
tree2e9ccdcd2a48a581be67f04f694fa90d040e1392 /blockdev.c
parente40e5027f6b0b7e981c4f1844180fb0e7947d1cd (diff)
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>
Diffstat (limited to 'blockdev.c')
-rw-r--r--blockdev.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/blockdev.c b/blockdev.c
index f42e1713e9..2df0c6d366 100644
--- a/blockdev.c
+++ b/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)