From: Yunjian Long <long.yunjian@zte.com.cn>
In the raw block devices scenario, when the guest OS writes only
a small amount of valid data, the current mirroring mechanism writes
all the data to the destination. However, when the target device has
already been zeroed, it is actually possible to skip writing zero data,
which is very useful for performance improvement.
Signed-off-by: Yunjian Long <long.yunjian@zte.com.cn>
---
block/mirror.c | 34 +++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-)
diff --git a/block/mirror.c b/block/mirror.c
index 2fcded9e93..939a97f1ba 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -199,6 +199,22 @@ static void coroutine_fn mirror_wait_on_conflicts(MirrorOp *self,
}
}
+static bool check_iov_is_zero(struct iovec *iov, int niov)
+{
+ int i = 0;
+
+ if (niov <= 0) {
+ return false;
+ }
+
+ for (i = 0; i < niov; i++) {
+ if (!buffer_is_zero(iov->iov_base, iov->iov_len)) {
+ return false;
+ }
+ }
+ return true;
+}
+
static void coroutine_fn mirror_iteration_done(MirrorOp *op, int ret)
{
MirrorBlockJob *s = op->s;
@@ -270,6 +286,12 @@ static void coroutine_fn mirror_read_complete(MirrorOp *op, int ret)
return;
}
+ if (s->target_is_zero && op->qiov.size > 0 &&
+ check_iov_is_zero(op->qiov.iov, op->qiov.niov)) {
+ mirror_iteration_done(op, ret);
+ return;
+ }
+
ret = blk_co_pwritev(s->target, op->offset, op->qiov.size, &op->qiov, 0);
mirror_write_complete(op, ret);
}
@@ -1656,8 +1678,14 @@ bdrv_mirror_top_do_write(BlockDriverState *bs, MirrorMethod method,
MirrorOp *op = NULL;
MirrorBDSOpaque *s = bs->opaque;
int ret = 0;
+ bool target_force_write = false;
- if (copy_to_target) {
+ if (s->job && s->job->target_is_zero && qiov->size > 0 &&
+ check_iov_is_zero(qiov->iov, qiov->niov)) {
+ target_force_write = true;
+ }
+
+ if (copy_to_target || target_force_write) {
op = active_write_prepare(s->job, offset, bytes);
}
@@ -1689,12 +1717,12 @@ bdrv_mirror_top_do_write(BlockDriverState *bs, MirrorMethod method,
goto out;
}
- if (copy_to_target) {
+ if (copy_to_target || target_force_write) {
do_sync_target_write(s->job, method, offset, bytes, qiov, flags);
}
out:
- if (copy_to_target) {
+ if (copy_to_target || target_force_write) {
active_write_settle(op);
}
return ret;
--
2.27.0