@@ -2622,6 +2622,7 @@ void qmp_drive_mirror(const char *device, const char *target,
bool has_on_source_error, BlockdevOnError on_source_error,
bool has_on_target_error, BlockdevOnError on_target_error,
bool has_unmap, bool unmap,
+ bool has_detect_zeroes, bool detect_zeroes,
Error **errp)
{
BlockBackend *blk;
@@ -2634,6 +2635,7 @@ void qmp_drive_mirror(const char *device, const char *target,
int flags;
int64_t size;
int ret;
+ const char *detect_zeroes_str;
if (!has_speed) {
speed = 0;
@@ -2656,6 +2658,9 @@ void qmp_drive_mirror(const char *device, const char *target,
if (!has_unmap) {
unmap = true;
}
+ if (!has_detect_zeroes) {
+ detect_zeroes = true;
+ }
if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "granularity",
@@ -2770,11 +2775,21 @@ void qmp_drive_mirror(const char *device, const char *target,
goto out;
}
+ options = qdict_new();
if (has_node_name) {
- options = qdict_new();
qdict_put(options, "node-name", qstring_from_str(node_name));
}
+ if (unmap) {
+ flags |= BDRV_O_UNMAP;
+ }
+
+ if (detect_zeroes) {
+ detect_zeroes_str = unmap ? "unmap" : "on";
+ } else {
+ detect_zeroes_str = "off";
+ }
+
/* Mirroring takes care of copy-on-write using the source's backing
* file.
*/
@@ -2786,6 +2801,15 @@ void qmp_drive_mirror(const char *device, const char *target,
goto out;
}
+ target_bs->detect_zeroes =
+ bdrv_parse_detect_zeroes_flags(detect_zeroes_str,
+ flags,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto out;
+ }
+
bdrv_set_aio_context(target_bs, aio_context);
/* pass the node name to replace to mirror start since it's loose coupling
@@ -1057,7 +1057,7 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
false, NULL, false, NULL,
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
true, mode, false, 0, false, 0, false, 0,
- false, 0, false, 0, false, true, &err);
+ false, 0, false, 0, false, true, false, true, &err);
hmp_handle_error(mon, &err);
}
@@ -978,6 +978,8 @@
# target image sectors will be unmapped; otherwise, zeroes will be
# written. Both will result in identical contents.
# Default is true. (Since 2.4)
+# @detect-zeroes: #optional Whether to detect zero sectors in source and use
+# zero write on target. Default is true. (Since 2.4)
#
# Returns: nothing on success
# If @device is not a valid block device, DeviceNotFound
@@ -991,7 +993,7 @@
'*speed': 'int', '*granularity': 'uint32',
'*buf-size': 'int', '*on-source-error': 'BlockdevOnError',
'*on-target-error': 'BlockdevOnError',
- '*unmap': 'bool' } }
+ '*unmap': 'bool', '*detect-zeroes': 'bool' } }
##
# @BlockDirtyBitmap
@@ -1503,7 +1503,7 @@ EQMP
.args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?,"
"node-name:s?,replaces:s?,"
"on-source-error:s?,on-target-error:s?,"
- "unmap:b?,"
+ "unmap:b?,detect-zeroes:b?"
"granularity:i?,buf-size:i?",
.mhandler.cmd_new = qmp_marshal_input_drive_mirror,
},
@@ -1545,6 +1545,8 @@ Arguments:
(BlockdevOnError, default 'report')
- "unmap": whether the target sectors should be discarded where source has only
zeroes. (json-bool, optional, default true)
+- "detect-zeroes": if true, the source sectors that are zeroes will be written as
+ sparse on target. (json-bool, optional, default true)
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
The new optional flag defaults to true, in which case, mirror job would check the read sectors and use sparse write if they are zero. Otherwise data will be fully copied. Signed-off-by: Fam Zheng <famz@redhat.com> --- blockdev.c | 26 +++++++++++++++++++++++++- hmp.c | 2 +- qapi/block-core.json | 4 +++- qmp-commands.hx | 4 +++- 4 files changed, 32 insertions(+), 4 deletions(-)