@@ -47,6 +47,8 @@ typedef struct BackupBlockJob {
47
47
HBitmap * copy_bitmap ;
48
48
bool use_copy_range ;
49
49
int64_t copy_range_size ;
50
+
51
+ bool serialize_target_writes ;
50
52
} BackupBlockJob ;
51
53
52
54
static const BlockJobDriver backup_job_driver ;
@@ -102,6 +104,8 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
102
104
QEMUIOVector qiov ;
103
105
BlockBackend * blk = job -> common .blk ;
104
106
int nbytes ;
107
+ int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0 ;
108
+ int write_flags = job -> serialize_target_writes ? BDRV_REQ_SERIALISING : 0 ;
105
109
106
110
hbitmap_reset (job -> copy_bitmap , start / job -> cluster_size , 1 );
107
111
nbytes = MIN (job -> cluster_size , job -> len - start );
@@ -112,8 +116,7 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
112
116
iov .iov_len = nbytes ;
113
117
qemu_iovec_init_external (& qiov , & iov , 1 );
114
118
115
- ret = blk_co_preadv (blk , start , qiov .size , & qiov ,
116
- is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0 );
119
+ ret = blk_co_preadv (blk , start , qiov .size , & qiov , read_flags );
117
120
if (ret < 0 ) {
118
121
trace_backup_do_cow_read_fail (job , start , ret );
119
122
if (error_is_read ) {
@@ -124,11 +127,11 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
124
127
125
128
if (qemu_iovec_is_zero (& qiov )) {
126
129
ret = blk_co_pwrite_zeroes (job -> target , start ,
127
- qiov .size , BDRV_REQ_MAY_UNMAP );
130
+ qiov .size , write_flags | BDRV_REQ_MAY_UNMAP );
128
131
} else {
129
132
ret = blk_co_pwritev (job -> target , start ,
130
- qiov .size , & qiov ,
131
- job -> compress ? BDRV_REQ_WRITE_COMPRESSED : 0 );
133
+ qiov .size , & qiov , write_flags |
134
+ ( job -> compress ? BDRV_REQ_WRITE_COMPRESSED : 0 ) );
132
135
}
133
136
if (ret < 0 ) {
134
137
trace_backup_do_cow_write_fail (job , start , ret );
@@ -156,14 +159,16 @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job,
156
159
int nr_clusters ;
157
160
BlockBackend * blk = job -> common .blk ;
158
161
int nbytes ;
162
+ int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0 ;
163
+ int write_flags = job -> serialize_target_writes ? BDRV_REQ_SERIALISING : 0 ;
159
164
160
165
assert (QEMU_IS_ALIGNED (job -> copy_range_size , job -> cluster_size ));
161
166
nbytes = MIN (job -> copy_range_size , end - start );
162
167
nr_clusters = DIV_ROUND_UP (nbytes , job -> cluster_size );
163
168
hbitmap_reset (job -> copy_bitmap , start / job -> cluster_size ,
164
169
nr_clusters );
165
170
ret = blk_co_copy_range (blk , start , job -> target , start , nbytes ,
166
- is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0 );
171
+ read_flags , write_flags );
167
172
if (ret < 0 ) {
168
173
trace_backup_do_cow_copy_range_fail (job , start , ret );
169
174
hbitmap_set (job -> copy_bitmap , start / job -> cluster_size ,
@@ -701,6 +706,9 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
701
706
sync_bitmap : NULL ;
702
707
job -> compress = compress ;
703
708
709
+ /* Detect image-fleecing (and similar) schemes */
710
+ job -> serialize_target_writes = bdrv_chain_contains (target , bs );
711
+
704
712
/* If there is no backing file on the target, we cannot rely on COW if our
705
713
* backup cluster size is smaller than the target cluster size. Even for
706
714
* targets with a backing file, try to avoid COW if possible. */
0 commit comments