* [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror
@ 2015-12-24 4:45 Fam Zheng
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 1/5] block: Rename BLOCK_OP_TYPE_MIRROR to BLOCK_OP_TYPE_MIRROR_SOURCE Fam Zheng
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Fam Zheng @ 2015-12-24 4:45 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, qemu-block, Jeff Cody, Markus Armbruster, mreitz,
Stefan Hajnoczi, pbonzini
v4: 02: Add Max's rev-by.
04: buf_size -> buf-size.
Add Markus' Ack-by.
05: 'node1' -> qmp_target.
Fix double quotes.
Add Max's Rev-by.
v3: Rebase to master.
v2: 01: Move bdrv_op_block_all down. [Max]
02, 04: Add Max's rev-by.
03: Check has_mode and fix "return;". [Max]
05: Check target->blk.
Drop superfluous whitespace. [Max]
06: Drop superfluous whitespace hunk and add Max's rev-by. [Max]
This is the counterpart of blockdev-backup. The biggest value of this command
is to allow full flexibility on target image open options, via blockdev-add.
For example this could help solve the target provisioning issue in:
http://lists.gnu.org/archive/html/qemu-devel/2015-06/msg02139.html
Fam Zheng (5):
block: Rename BLOCK_OP_TYPE_MIRROR to BLOCK_OP_TYPE_MIRROR_SOURCE
block: Extract blockdev part of qmp_drive_mirror
block: Add check on mirror target
qmp: Add blockdev-mirror command
iotests: Add test cases for blockdev-mirror
blockdev.c | 179 ++++++++++++++++++++++++++++++----------
hw/block/dataplane/virtio-blk.c | 2 +-
include/block/block.h | 3 +-
qapi/block-core.json | 48 +++++++++++
qmp-commands.hx | 50 ++++++++++-
tests/qemu-iotests/041 | 100 ++++++++++++++++------
tests/qemu-iotests/041.out | 4 +-
7 files changed, 316 insertions(+), 70 deletions(-)
--
2.4.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v4 1/5] block: Rename BLOCK_OP_TYPE_MIRROR to BLOCK_OP_TYPE_MIRROR_SOURCE
2015-12-24 4:45 [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror Fam Zheng
@ 2015-12-24 4:45 ` Fam Zheng
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 2/5] block: Extract blockdev part of qmp_drive_mirror Fam Zheng
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Fam Zheng @ 2015-12-24 4:45 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, qemu-block, Jeff Cody, Markus Armbruster, mreitz,
Stefan Hajnoczi, pbonzini
It's necessary to distinguish source and target before we can add
blockdev-mirror, because we would want a concrete type of operation to
check on target bs before starting.
Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 2 +-
hw/block/dataplane/virtio-blk.c | 2 +-
include/block/block.h | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 64dbfeb..bd6f68e 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3368,7 +3368,7 @@ void qmp_drive_mirror(const char *device, const char *target,
format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
}
- if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) {
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR_SOURCE, errp)) {
goto out;
}
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index c57f293..a2529b2 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -195,7 +195,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, s->blocker);
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_MIRROR, s->blocker);
+ blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_MIRROR_SOURCE, s->blocker);
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker);
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker);
diff --git a/include/block/block.h b/include/block/block.h
index db8e096..8ea12fa 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -169,7 +169,7 @@ typedef enum BlockOpType {
BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
BLOCK_OP_TYPE_INTERNAL_SNAPSHOT,
BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
- BLOCK_OP_TYPE_MIRROR,
+ BLOCK_OP_TYPE_MIRROR_SOURCE,
BLOCK_OP_TYPE_RESIZE,
BLOCK_OP_TYPE_STREAM,
BLOCK_OP_TYPE_REPLACE,
--
2.4.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v4 2/5] block: Extract blockdev part of qmp_drive_mirror
2015-12-24 4:45 [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror Fam Zheng
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 1/5] block: Rename BLOCK_OP_TYPE_MIRROR to BLOCK_OP_TYPE_MIRROR_SOURCE Fam Zheng
@ 2015-12-24 4:45 ` Fam Zheng
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 3/5] block: Add check on mirror target Fam Zheng
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Fam Zheng @ 2015-12-24 4:45 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, qemu-block, Jeff Cody, Markus Armbruster, mreitz,
Stefan Hajnoczi, pbonzini
This is the part that will be reused by blockdev-mirror.
Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 146 +++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 88 insertions(+), 58 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index bd6f68e..22e06ba 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3291,29 +3291,23 @@ void qmp_blockdev_backup(const char *device, const char *target,
NULL, errp);
}
-void qmp_drive_mirror(const char *device, const char *target,
- bool has_format, const char *format,
- bool has_node_name, const char *node_name,
- bool has_replaces, const char *replaces,
- enum MirrorSyncMode sync,
- bool has_mode, enum NewImageMode mode,
- 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,
- bool has_unmap, bool unmap,
- Error **errp)
+/* Parameter check and block job starting for drive mirroring.
+ * Caller should hold @device and @target's aio context (must be the same).
+ **/
+static void blockdev_mirror_common(BlockDriverState *bs,
+ BlockDriverState *target,
+ bool has_replaces, const char *replaces,
+ enum 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,
+ bool has_unmap, bool unmap,
+ Error **errp)
{
- BlockBackend *blk;
- BlockDriverState *bs;
- BlockDriverState *source, *target_bs;
- AioContext *aio_context;
- Error *local_err = NULL;
- QDict *options;
- int flags;
- int64_t size;
- int ret;
if (!has_speed) {
speed = 0;
@@ -3324,9 +3318,6 @@ void qmp_drive_mirror(const char *device, const char *target,
if (!has_on_target_error) {
on_target_error = BLOCKDEV_ON_ERROR_REPORT;
}
- if (!has_mode) {
- mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
- }
if (!has_granularity) {
granularity = 0;
}
@@ -3348,29 +3339,70 @@ void qmp_drive_mirror(const char *device, const char *target,
return;
}
- blk = blk_by_name(device);
- if (!blk) {
- error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", device);
- return;
- }
-
- aio_context = blk_get_aio_context(blk);
- aio_context_acquire(aio_context);
-
- if (!blk_is_available(blk)) {
- error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
- goto out;
- }
- bs = blk_bs(blk);
-
- if (!has_format) {
- format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
- }
-
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR_SOURCE, errp)) {
+ return;
+ }
+
+ if (!bs->backing && sync == MIRROR_SYNC_MODE_TOP) {
+ sync = MIRROR_SYNC_MODE_FULL;
+ }
+
+ /* pass the node name to replace to mirror start since it's loose coupling
+ * and will allow to check whether the node still exist at mirror completion
+ */
+ mirror_start(bs, target,
+ has_replaces ? replaces : NULL,
+ speed, granularity, buf_size, sync,
+ on_source_error, on_target_error, unmap,
+ block_job_cb, bs, errp);
+}
+
+void qmp_drive_mirror(const char *device, const char *target,
+ bool has_format, const char *format,
+ bool has_node_name, const char *node_name,
+ bool has_replaces, const char *replaces,
+ enum MirrorSyncMode sync,
+ bool has_mode, enum NewImageMode mode,
+ 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,
+ bool has_unmap, bool unmap,
+ Error **errp)
+{
+ BlockDriverState *bs;
+ BlockBackend *blk;
+ BlockDriverState *source, *target_bs;
+ AioContext *aio_context;
+ Error *local_err = NULL;
+ QDict *options = NULL;
+ int flags;
+ int64_t size;
+ int ret;
+
+ blk = blk_by_name(device);
+ if (!blk) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
+ return;
+ }
+
+ aio_context = blk_get_aio_context(blk);
+ aio_context_acquire(aio_context);
+
+ if (!blk_is_available(blk)) {
+ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
goto out;
}
+ bs = blk_bs(blk);
+ if (!has_mode) {
+ mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
+ }
+
+ if (!has_format) {
+ format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
+ }
flags = bs->open_flags | BDRV_O_RDWR;
source = backing_bs(bs);
@@ -3466,21 +3498,19 @@ void qmp_drive_mirror(const char *device, const char *target,
bdrv_set_aio_context(target_bs, aio_context);
- /* pass the node name to replace to mirror start since it's loose coupling
- * and will allow to check whether the node still exist at mirror completion
- */
- mirror_start(bs, target_bs,
- has_replaces ? replaces : NULL,
- speed, granularity, buf_size, sync,
- on_source_error, on_target_error,
- unmap,
- block_job_cb, bs, &local_err);
- if (local_err != NULL) {
- bdrv_unref(target_bs);
+ 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,
+ has_unmap, unmap,
+ &local_err);
+ if (local_err) {
error_propagate(errp, local_err);
- goto out;
+ bdrv_unref(target_bs);
}
-
out:
aio_context_release(aio_context);
}
--
2.4.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v4 3/5] block: Add check on mirror target
2015-12-24 4:45 [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror Fam Zheng
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 1/5] block: Rename BLOCK_OP_TYPE_MIRROR to BLOCK_OP_TYPE_MIRROR_SOURCE Fam Zheng
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 2/5] block: Extract blockdev part of qmp_drive_mirror Fam Zheng
@ 2015-12-24 4:45 ` Fam Zheng
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 4/5] qmp: Add blockdev-mirror command Fam Zheng
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Fam Zheng @ 2015-12-24 4:45 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, qemu-block, Jeff Cody, Markus Armbruster, mreitz,
Stefan Hajnoczi, pbonzini
Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 3 +++
include/block/block.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/blockdev.c b/blockdev.c
index 22e06ba..f42e171 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3342,6 +3342,9 @@ static void blockdev_mirror_common(BlockDriverState *bs,
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR_SOURCE, errp)) {
return;
}
+ if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_MIRROR_TARGET, errp)) {
+ return;
+ }
if (!bs->backing && sync == MIRROR_SYNC_MODE_TOP) {
sync = MIRROR_SYNC_MODE_FULL;
diff --git a/include/block/block.h b/include/block/block.h
index 8ea12fa..c96923d 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -170,6 +170,7 @@ typedef enum BlockOpType {
BLOCK_OP_TYPE_INTERNAL_SNAPSHOT,
BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
BLOCK_OP_TYPE_MIRROR_SOURCE,
+ BLOCK_OP_TYPE_MIRROR_TARGET,
BLOCK_OP_TYPE_RESIZE,
BLOCK_OP_TYPE_STREAM,
BLOCK_OP_TYPE_REPLACE,
--
2.4.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v4 4/5] qmp: Add blockdev-mirror command
2015-12-24 4:45 [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror Fam Zheng
` (2 preceding siblings ...)
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 3/5] block: Add check on mirror target Fam Zheng
@ 2015-12-24 4:45 ` Fam Zheng
2016-01-04 20:02 ` Max Reitz
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 5/5] iotests: Add test cases for blockdev-mirror Fam Zheng
2016-01-06 18:03 ` [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror Max Reitz
5 siblings, 1 reply; 8+ messages in thread
From: Fam Zheng @ 2015-12-24 4:45 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, qemu-block, Jeff Cody, Markus Armbruster, mreitz,
Stefan Hajnoczi, pbonzini
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>
---
blockdev.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++
qapi/block-core.json | 48 ++++++++++++++++++++++++++++++++++++++++
qmp-commands.hx | 50 +++++++++++++++++++++++++++++++++++++++++-
3 files changed, 159 insertions(+), 1 deletion(-)
diff --git a/blockdev.c b/blockdev.c
index f42e171..2df0c6d 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)
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 1a5d9ce..0a915ed 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1184,6 +1184,54 @@
'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:
#
# Change I/O throttle limits for a block drive.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7b235ee..db072a6 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -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
@@ -1665,6 +1665,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",
.mhandler.cmd_new = qmp_marshal_change_backing_file,
--
2.4.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v4 5/5] iotests: Add test cases for blockdev-mirror
2015-12-24 4:45 [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror Fam Zheng
` (3 preceding siblings ...)
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 4/5] qmp: Add blockdev-mirror command Fam Zheng
@ 2015-12-24 4:45 ` Fam Zheng
2016-01-06 18:03 ` [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror Max Reitz
5 siblings, 0 replies; 8+ messages in thread
From: Fam Zheng @ 2015-12-24 4:45 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, qemu-block, Jeff Cody, Markus Armbruster, mreitz,
Stefan Hajnoczi, pbonzini
Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
tests/qemu-iotests/041 | 100 ++++++++++++++++++++++++++++++++++-----------
tests/qemu-iotests/041.out | 4 +-
2 files changed, 79 insertions(+), 25 deletions(-)
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index 05b5962..c7da95d 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -34,9 +34,11 @@ quorum_img3 = os.path.join(iotests.test_dir, 'quorum3.img')
quorum_repair_img = os.path.join(iotests.test_dir, 'quorum_repair.img')
quorum_snapshot_file = os.path.join(iotests.test_dir, 'quorum_snapshot.img')
-
class TestSingleDrive(iotests.QMPTestCase):
image_len = 1 * 1024 * 1024 # MB
+ qmp_cmd = 'drive-mirror'
+ qmp_target = target_img
+ not_found_error = 'DeviceNotFound'
def setUp(self):
iotests.create_image(backing_img, self.image_len)
@@ -58,8 +60,8 @@ class TestSingleDrive(iotests.QMPTestCase):
def test_complete(self):
self.assert_no_active_block_jobs()
- result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
- target=target_img)
+ result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
+ target=self.qmp_target)
self.assert_qmp(result, 'return', {})
self.complete_and_wait()
@@ -72,8 +74,8 @@ class TestSingleDrive(iotests.QMPTestCase):
def test_cancel(self):
self.assert_no_active_block_jobs()
- result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
- target=target_img)
+ result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
+ target=self.qmp_target)
self.assert_qmp(result, 'return', {})
self.cancel_and_wait(force=True)
@@ -84,8 +86,8 @@ class TestSingleDrive(iotests.QMPTestCase):
def test_cancel_after_ready(self):
self.assert_no_active_block_jobs()
- result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
- target=target_img)
+ result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
+ target=self.qmp_target)
self.assert_qmp(result, 'return', {})
self.wait_ready_and_cancel()
@@ -98,8 +100,8 @@ class TestSingleDrive(iotests.QMPTestCase):
def test_pause(self):
self.assert_no_active_block_jobs()
- result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
- target=target_img)
+ result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
+ target=self.qmp_target)
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('block-job-pause', device='drive0')
@@ -125,8 +127,8 @@ class TestSingleDrive(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
# A small buffer is rounded up automatically
- result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
- buf_size=4096, target=target_img)
+ result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
+ buf_size=4096, target=self.qmp_target)
self.assert_qmp(result, 'return', {})
self.complete_and_wait()
@@ -141,8 +143,8 @@ class TestSingleDrive(iotests.QMPTestCase):
qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d'
% (self.image_len, self.image_len), target_img)
- result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
- buf_size=65536, mode='existing', target=target_img)
+ result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
+ buf_size=65536, mode='existing', target=self.qmp_target)
self.assert_qmp(result, 'return', {})
self.complete_and_wait()
@@ -157,8 +159,8 @@ class TestSingleDrive(iotests.QMPTestCase):
qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
% (self.image_len, backing_img), target_img)
- result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
- mode='existing', target=target_img)
+ result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
+ mode='existing', target=self.qmp_target)
self.assert_qmp(result, 'return', {})
self.complete_and_wait()
@@ -172,30 +174,82 @@ class TestSingleDrive(iotests.QMPTestCase):
if iotests.qemu_default_machine != 'pc':
return
- result = self.vm.qmp('drive-mirror', device='drive1', # CD-ROM
- sync='full', target=target_img)
- self.assert_qmp(result, 'error/class', 'GenericError')
+ result = self.vm.qmp(self.qmp_cmd, device='ide1-cd0', sync='full',
+ target=self.qmp_target)
+ self.assert_qmp(result, 'error/class', self.not_found_error)
def test_image_not_found(self):
- result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
- mode='existing', target=target_img)
+ result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
+ mode='existing', target=self.qmp_target)
self.assert_qmp(result, 'error/class', 'GenericError')
def test_device_not_found(self):
- result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
- target=target_img)
- self.assert_qmp(result, 'error/class', 'DeviceNotFound')
+ result = self.vm.qmp(self.qmp_cmd, device='nonexistent', sync='full',
+ target=self.qmp_target)
+ self.assert_qmp(result, 'error/class', self.not_found_error)
+
+class TestSingleBlockdev(TestSingleDrive):
+ qmp_cmd = 'blockdev-mirror'
+ qmp_target = 'node1'
+ not_found_error = 'GenericError'
+
+ def setUp(self):
+ TestSingleDrive.setUp(self)
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
+ args = {'options':
+ {'driver': iotests.imgfmt,
+ 'node-name': self.qmp_target,
+ 'file': { 'filename': target_img, 'driver': 'file' } } }
+ result = self.vm.qmp("blockdev-add", **args)
+ self.assert_qmp(result, 'return', {})
+
+ test_large_cluster = None
+ test_image_not_found = None
+ test_small_buffer2 = None
+
+class TestBlockdevAttached(iotests.QMPTestCase):
+ image_len = 1 * 1024 * 1024 # MB
+
+ def setUp(self):
+ iotests.create_image(backing_img, self.image_len)
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
+ self.vm = iotests.VM().add_drive(test_img)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(test_img)
+ os.remove(target_img)
+
+ def test_blockdev_attached(self):
+ self.assert_no_active_block_jobs()
+ args = {'options':
+ {'driver': iotests.imgfmt,
+ 'id': 'drive1',
+ 'file': { 'filename': target_img, 'driver': 'file' } } }
+ result = self.vm.qmp("blockdev-add", **args)
+ self.assert_qmp(result, 'return', {})
+ result = self.vm.qmp('blockdev-mirror', device='drive0', sync='full',
+ target='drive1')
+ self.assert_qmp(result, 'error/class', 'GenericError')
class TestSingleDriveZeroLength(TestSingleDrive):
image_len = 0
test_small_buffer2 = None
test_large_cluster = None
+class TestSingleBlockdevZeroLength(TestSingleBlockdev):
+ image_len = 0
+
class TestSingleDriveUnalignedLength(TestSingleDrive):
image_len = 1025 * 1024
test_small_buffer2 = None
test_large_cluster = None
+class TestSingleBlockdevUnalignedLength(TestSingleBlockdev):
+ image_len = 1025 * 1024
+
class TestMirrorNoBacking(iotests.QMPTestCase):
image_len = 2 * 1024 * 1024 # MB
diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out
index 24093bc..b67d050 100644
--- a/tests/qemu-iotests/041.out
+++ b/tests/qemu-iotests/041.out
@@ -1,5 +1,5 @@
-......................................................
+............................................................................
----------------------------------------------------------------------
-Ran 54 tests
+Ran 76 tests
OK
--
2.4.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v4 4/5] qmp: Add blockdev-mirror command
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 4/5] qmp: Add blockdev-mirror command Fam Zheng
@ 2016-01-04 20:02 ` Max Reitz
0 siblings, 0 replies; 8+ messages in thread
From: Max Reitz @ 2016-01-04 20:02 UTC (permalink / raw)
To: Fam Zheng, qemu-devel
Cc: Kevin Wolf, qemu-block, Jeff Cody, Markus Armbruster,
Stefan Hajnoczi, pbonzini
[-- Attachment #1: Type: text/plain, Size: 828 bytes --]
On 24.12.2015 05:45, Fam Zheng wrote:
> 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>
> ---
> blockdev.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> qapi/block-core.json | 48 ++++++++++++++++++++++++++++++++++++++++
> qmp-commands.hx | 50 +++++++++++++++++++++++++++++++++++++++++-
> 3 files changed, 159 insertions(+), 1 deletion(-)
Reviewed-by: Max Reitz <mreitz@redhat.com>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror
2015-12-24 4:45 [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror Fam Zheng
` (4 preceding siblings ...)
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 5/5] iotests: Add test cases for blockdev-mirror Fam Zheng
@ 2016-01-06 18:03 ` Max Reitz
5 siblings, 0 replies; 8+ messages in thread
From: Max Reitz @ 2016-01-06 18:03 UTC (permalink / raw)
To: Fam Zheng, qemu-devel
Cc: Kevin Wolf, qemu-block, Jeff Cody, Markus Armbruster,
Stefan Hajnoczi, pbonzini
[-- Attachment #1: Type: text/plain, Size: 1665 bytes --]
On 24.12.2015 05:45, Fam Zheng wrote:
> v4: 02: Add Max's rev-by.
> 04: buf_size -> buf-size.
> Add Markus' Ack-by.
> 05: 'node1' -> qmp_target.
> Fix double quotes.
> Add Max's Rev-by.
>
> v3: Rebase to master.
>
> v2: 01: Move bdrv_op_block_all down. [Max]
> 02, 04: Add Max's rev-by.
> 03: Check has_mode and fix "return;". [Max]
> 05: Check target->blk.
> Drop superfluous whitespace. [Max]
> 06: Drop superfluous whitespace hunk and add Max's rev-by. [Max]
>
> This is the counterpart of blockdev-backup. The biggest value of this command
> is to allow full flexibility on target image open options, via blockdev-add.
> For example this could help solve the target provisioning issue in:
>
> http://lists.gnu.org/archive/html/qemu-devel/2015-06/msg02139.html
>
> Fam Zheng (5):
> block: Rename BLOCK_OP_TYPE_MIRROR to BLOCK_OP_TYPE_MIRROR_SOURCE
> block: Extract blockdev part of qmp_drive_mirror
> block: Add check on mirror target
> qmp: Add blockdev-mirror command
> iotests: Add test cases for blockdev-mirror
>
> blockdev.c | 179 ++++++++++++++++++++++++++++++----------
> hw/block/dataplane/virtio-blk.c | 2 +-
> include/block/block.h | 3 +-
> qapi/block-core.json | 48 +++++++++++
> qmp-commands.hx | 50 ++++++++++-
> tests/qemu-iotests/041 | 100 ++++++++++++++++------
> tests/qemu-iotests/041.out | 4 +-
> 7 files changed, 316 insertions(+), 70 deletions(-)
Thanks, applied to my block tree:
https://github.com/XanClic/qemu/commits/block
Max
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2016-01-06 18:04 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-12-24 4:45 [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror Fam Zheng
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 1/5] block: Rename BLOCK_OP_TYPE_MIRROR to BLOCK_OP_TYPE_MIRROR_SOURCE Fam Zheng
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 2/5] block: Extract blockdev part of qmp_drive_mirror Fam Zheng
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 3/5] block: Add check on mirror target Fam Zheng
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 4/5] qmp: Add blockdev-mirror command Fam Zheng
2016-01-04 20:02 ` Max Reitz
2015-12-24 4:45 ` [Qemu-devel] [PATCH v4 5/5] iotests: Add test cases for blockdev-mirror Fam Zheng
2016-01-06 18:03 ` [Qemu-devel] [PATCH v4 0/5] qmp: Add blockdev-mirror Max Reitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).