aboutsummaryrefslogtreecommitdiff
path: root/block/block-copy.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/block-copy.c')
-rw-r--r--block/block-copy.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/block/block-copy.c b/block/block-copy.c
index 0becad52da..58b4345a5a 100644
--- a/block/block-copy.c
+++ b/block/block-copy.c
@@ -317,10 +317,11 @@ static uint32_t block_copy_max_transfer(BdrvChild *source, BdrvChild *target)
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
int64_t cluster_size, bool use_copy_range,
- BdrvRequestFlags write_flags, Error **errp)
+ bool compress, Error **errp)
{
BlockCopyState *s;
BdrvDirtyBitmap *copy_bitmap;
+ bool is_fleecing;
copy_bitmap = bdrv_create_dirty_bitmap(source->bs, cluster_size, NULL,
errp);
@@ -329,6 +330,22 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
}
bdrv_disable_dirty_bitmap(copy_bitmap);
+ /*
+ * If source is in backing chain of target assume that target is going to be
+ * used for "image fleecing", i.e. it should represent a kind of snapshot of
+ * source at backup-start point in time. And target is going to be read by
+ * somebody (for example, used as NBD export) during backup job.
+ *
+ * In this case, we need to add BDRV_REQ_SERIALISING write flag to avoid
+ * intersection of backup writes and third party reads from target,
+ * otherwise reading from target we may occasionally read already updated by
+ * guest data.
+ *
+ * For more information see commit f8d59dfb40bb and test
+ * tests/qemu-iotests/222
+ */
+ is_fleecing = bdrv_chain_contains(target->bs, source->bs);
+
s = g_new(BlockCopyState, 1);
*s = (BlockCopyState) {
.source = source,
@@ -336,7 +353,8 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
.copy_bitmap = copy_bitmap,
.cluster_size = cluster_size,
.len = bdrv_dirty_bitmap_size(copy_bitmap),
- .write_flags = write_flags,
+ .write_flags = (is_fleecing ? BDRV_REQ_SERIALISING : 0) |
+ (compress ? BDRV_REQ_WRITE_COMPRESSED : 0),
.mem = shres_create(BLOCK_COPY_MAX_MEM),
.max_transfer = QEMU_ALIGN_DOWN(
block_copy_max_transfer(source, target),
@@ -351,7 +369,7 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
* behalf).
*/
s->method = COPY_READ_WRITE_CLUSTER;
- } else if (write_flags & BDRV_REQ_WRITE_COMPRESSED) {
+ } else if (compress) {
/* Compression supports only cluster-size writes and no copy-range. */
s->method = COPY_READ_WRITE_CLUSTER;
} else {