aboutsummaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorMax Reitz <mreitz@redhat.com>2019-08-01 19:38:59 +0200
committerMichael Roth <mdroth@linux.vnet.ibm.com>2019-10-01 16:58:28 -0500
commit70353442dbda6c66475403d1907f14939e73b716 (patch)
tree00ba352b6c96e481bf00a6e93f8e81fc01facce5 /block
parent872b7b8ef9a62a72a125a9bb87e77b8e6867c7e1 (diff)
backup: Copy only dirty areas
The backup job must only copy areas that the copy_bitmap reports as dirty. This is always the case when using traditional non-offloading backup, because it copies each cluster separately. When offloading the copy operation, we sometimes copy more than one cluster at a time, but we only check whether the first one is dirty. Therefore, whenever copy offloading is possible, the backup job currently produces wrong output when the guest writes to an area of which an inner part has already been backed up, because that inner part will be re-copied. Fixes: 9ded4a0114968e98b41494fc035ba14f84cdf700 Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Message-id: 20190801173900.23851-2-mreitz@redhat.com Cc: qemu-stable@nongnu.org Signed-off-by: Max Reitz <mreitz@redhat.com> (cherry picked from commit 4a5b91ca024fc6fd87021c54655af76a35f2ef1e) Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Diffstat (limited to 'block')
-rw-r--r--block/backup.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/block/backup.c b/block/backup.c
index d1b94a6dbe..f67c208cf0 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -204,22 +204,31 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
cow_request_begin(&cow_request, job, start, end);
while (start < end) {
+ int64_t dirty_end;
+
if (!hbitmap_get(job->copy_bitmap, start)) {
trace_backup_do_cow_skip(job, start);
start += job->cluster_size;
continue; /* already copied */
}
+ dirty_end = hbitmap_next_zero(job->copy_bitmap, start, (end - start));
+ if (dirty_end < 0) {
+ dirty_end = end;
+ }
+
trace_backup_do_cow_process(job, start);
if (job->use_copy_range) {
- ret = backup_cow_with_offload(job, start, end, is_write_notifier);
+ ret = backup_cow_with_offload(job, start, dirty_end,
+ is_write_notifier);
if (ret < 0) {
job->use_copy_range = false;
}
}
if (!job->use_copy_range) {
- ret = backup_cow_with_bounce_buffer(job, start, end, is_write_notifier,
+ ret = backup_cow_with_bounce_buffer(job, start, dirty_end,
+ is_write_notifier,
error_is_read, &bounce_buffer);
}
if (ret < 0) {