]>
Commit | Line | Data |
---|---|---|
83faa3fe | 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
059a9447 | 2 | From: John Snow <jsnow@redhat.com> |
83faa3fe TL |
3 | Date: Mon, 6 Apr 2020 12:17:03 +0200 |
4 | Subject: [PATCH] drive-mirror: add support for sync=bitmap mode=never | |
059a9447 FG |
5 | MIME-Version: 1.0 |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | This patch adds support for the "BITMAP" sync mode to drive-mirror and | |
10 | blockdev-mirror. It adds support only for the BitmapSyncMode "never," | |
11 | because it's the simplest mode. | |
12 | ||
13 | This mode simply uses a user-provided bitmap as an initial copy | |
14 | manifest, and then does not clear any bits in the bitmap at the | |
15 | conclusion of the operation. | |
16 | ||
17 | Any new writes dirtied during the operation are copied out, in contrast | |
18 | to backup. Note that whether these writes are reflected in the bitmap | |
19 | at the conclusion of the operation depends on whether that bitmap is | |
20 | actually recording! | |
21 | ||
22 | This patch was originally based on one by Ma Haocong, but it has since | |
23 | been modified pretty heavily. | |
24 | ||
25 | Suggested-by: Ma Haocong <mahaocong@didichuxing.com> | |
26 | Signed-off-by: Ma Haocong <mahaocong@didichuxing.com> | |
27 | Signed-off-by: John Snow <jsnow@redhat.com> | |
28 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
ddbf7a87 | 29 | Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> |
f1eed34a | 30 | [FE: rebased for 8.2.2] |
bf251437 | 31 | Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> |
059a9447 | 32 | --- |
f1eed34a | 33 | block/mirror.c | 99 ++++++++++++++++++++------ |
bf251437 | 34 | blockdev.c | 38 +++++++++- |
dc9827a6 | 35 | include/block/block_int-global-state.h | 4 +- |
10e10933 | 36 | qapi/block-core.json | 25 ++++++- |
dc9827a6 | 37 | tests/unit/test-block-iothread.c | 4 +- |
f1eed34a | 38 | 5 files changed, 142 insertions(+), 28 deletions(-) |
059a9447 | 39 | |
059a9447 | 40 | diff --git a/block/mirror.c b/block/mirror.c |
4fbd50e2 | 41 | index 1bdce3b657..0c5c72df2e 100644 |
059a9447 FG |
42 | --- a/block/mirror.c |
43 | +++ b/block/mirror.c | |
dc9827a6 | 44 | @@ -51,7 +51,7 @@ typedef struct MirrorBlockJob { |
059a9447 FG |
45 | BlockDriverState *to_replace; |
46 | /* Used to block operations on the drive-mirror-replace target */ | |
47 | Error *replace_blocker; | |
48 | - bool is_none_mode; | |
49 | + MirrorSyncMode sync_mode; | |
50 | BlockMirrorBackingMode backing_mode; | |
51 | /* Whether the target image requires explicit zero-initialization */ | |
52 | bool zero_target; | |
f1eed34a | 53 | @@ -73,6 +73,8 @@ typedef struct MirrorBlockJob { |
059a9447 FG |
54 | size_t buf_size; |
55 | int64_t bdev_length; | |
56 | unsigned long *cow_bitmap; | |
57 | + BdrvDirtyBitmap *sync_bitmap; | |
58 | + BitmapSyncMode bitmap_mode; | |
59 | BdrvDirtyBitmap *dirty_bitmap; | |
60 | BdrvDirtyBitmapIter *dbi; | |
61 | uint8_t *buf; | |
4fbd50e2 | 62 | @@ -722,7 +724,8 @@ static int mirror_exit_common(Job *job) |
059a9447 | 63 | &error_abort); |
f1eed34a | 64 | |
059a9447 FG |
65 | if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { |
66 | - BlockDriverState *backing = s->is_none_mode ? src : s->base; | |
67 | + BlockDriverState *backing; | |
68 | + backing = s->sync_mode == MIRROR_SYNC_MODE_NONE ? src : s->base; | |
817b7667 SR |
69 | BlockDriverState *unfiltered_target = bdrv_skip_filters(target_bs); |
70 | ||
71 | if (bdrv_cow_bs(unfiltered_target) != backing) { | |
4fbd50e2 | 72 | @@ -819,6 +822,16 @@ static void mirror_abort(Job *job) |
059a9447 FG |
73 | assert(ret == 0); |
74 | } | |
75 | ||
76 | +/* Always called after commit/abort. */ | |
77 | +static void mirror_clean(Job *job) | |
78 | +{ | |
79 | + MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); | |
80 | + | |
81 | + if (s->sync_bitmap) { | |
82 | + bdrv_dirty_bitmap_set_busy(s->sync_bitmap, false); | |
83 | + } | |
84 | +} | |
85 | + | |
86 | static void coroutine_fn mirror_throttle(MirrorBlockJob *s) | |
87 | { | |
88 | int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); | |
4fbd50e2 | 89 | @@ -1015,7 +1028,8 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) |
059a9447 FG |
90 | mirror_free_init(s); |
91 | ||
92 | s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); | |
93 | - if (!s->is_none_mode) { | |
94 | + if ((s->sync_mode == MIRROR_SYNC_MODE_TOP) || | |
95 | + (s->sync_mode == MIRROR_SYNC_MODE_FULL)) { | |
96 | ret = mirror_dirty_init(s); | |
97 | if (ret < 0 || job_is_cancelled(&s->common.job)) { | |
98 | goto immediate_exit; | |
4fbd50e2 | 99 | @@ -1304,6 +1318,7 @@ static const BlockJobDriver mirror_job_driver = { |
059a9447 FG |
100 | .run = mirror_run, |
101 | .prepare = mirror_prepare, | |
102 | .abort = mirror_abort, | |
103 | + .clean = mirror_clean, | |
104 | .pause = mirror_pause, | |
105 | .complete = mirror_complete, | |
8dca018b | 106 | .cancel = mirror_cancel, |
4fbd50e2 | 107 | @@ -1322,6 +1337,7 @@ static const BlockJobDriver commit_active_job_driver = { |
059a9447 FG |
108 | .run = mirror_run, |
109 | .prepare = mirror_prepare, | |
110 | .abort = mirror_abort, | |
111 | + .clean = mirror_clean, | |
112 | .pause = mirror_pause, | |
113 | .complete = mirror_complete, | |
4567474e | 114 | .cancel = commit_active_cancel, |
4fbd50e2 | 115 | @@ -1714,7 +1730,10 @@ static BlockJob *mirror_start_job( |
059a9447 FG |
116 | BlockCompletionFunc *cb, |
117 | void *opaque, | |
118 | const BlockJobDriver *driver, | |
119 | - bool is_none_mode, BlockDriverState *base, | |
120 | + MirrorSyncMode sync_mode, | |
121 | + BdrvDirtyBitmap *bitmap, | |
122 | + BitmapSyncMode bitmap_mode, | |
123 | + BlockDriverState *base, | |
124 | bool auto_complete, const char *filter_node_name, | |
125 | bool is_mirror, MirrorCopyMode copy_mode, | |
126 | Error **errp) | |
4fbd50e2 | 127 | @@ -1728,10 +1747,39 @@ static BlockJob *mirror_start_job( |
f1eed34a FE |
128 | |
129 | GLOBAL_STATE_CODE(); | |
059a9447 FG |
130 | |
131 | - if (granularity == 0) { | |
dc9827a6 | 132 | - granularity = bdrv_get_default_bitmap_granularity(target); |
059a9447 FG |
133 | + if (sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { |
134 | + error_setg(errp, "Sync mode '%s' not supported", | |
135 | + MirrorSyncMode_str(sync_mode)); | |
136 | + return NULL; | |
137 | + } else if (sync_mode == MIRROR_SYNC_MODE_BITMAP) { | |
138 | + if (!bitmap) { | |
139 | + error_setg(errp, "Must provide a valid bitmap name for '%s'" | |
140 | + " sync mode", | |
141 | + MirrorSyncMode_str(sync_mode)); | |
142 | + return NULL; | |
143 | + } else if (bitmap_mode != BITMAP_SYNC_MODE_NEVER) { | |
144 | + error_setg(errp, | |
145 | + "Bitmap Sync Mode '%s' is not supported by Mirror", | |
146 | + BitmapSyncMode_str(bitmap_mode)); | |
147 | + } | |
148 | + } else if (bitmap) { | |
149 | + error_setg(errp, | |
150 | + "sync mode '%s' is not compatible with bitmaps", | |
151 | + MirrorSyncMode_str(sync_mode)); | |
152 | + return NULL; | |
dc9827a6 FE |
153 | } |
154 | ||
059a9447 FG |
155 | + if (bitmap) { |
156 | + if (granularity) { | |
157 | + error_setg(errp, "granularity (%d)" | |
158 | + "cannot be specified when a bitmap is provided", | |
159 | + granularity); | |
160 | + return NULL; | |
161 | + } | |
162 | + granularity = bdrv_dirty_bitmap_granularity(bitmap); | |
163 | + } else if (granularity == 0) { | |
dc9827a6 FE |
164 | + granularity = bdrv_get_default_bitmap_granularity(target); |
165 | + } | |
059a9447 FG |
166 | assert(is_power_of_2(granularity)); |
167 | ||
168 | if (buf_size < 0) { | |
4fbd50e2 | 169 | @@ -1871,7 +1919,9 @@ static BlockJob *mirror_start_job( |
059a9447 FG |
170 | s->replaces = g_strdup(replaces); |
171 | s->on_source_error = on_source_error; | |
172 | s->on_target_error = on_target_error; | |
173 | - s->is_none_mode = is_none_mode; | |
174 | + s->sync_mode = sync_mode; | |
175 | + s->sync_bitmap = bitmap; | |
176 | + s->bitmap_mode = bitmap_mode; | |
177 | s->backing_mode = backing_mode; | |
178 | s->zero_target = zero_target; | |
f1eed34a | 179 | qatomic_set(&s->copy_mode, copy_mode); |
4fbd50e2 | 180 | @@ -1897,6 +1947,18 @@ static BlockJob *mirror_start_job( |
f1eed34a FE |
181 | */ |
182 | bdrv_disable_dirty_bitmap(s->dirty_bitmap); | |
059a9447 FG |
183 | |
184 | + if (s->sync_bitmap) { | |
185 | + bdrv_dirty_bitmap_set_busy(s->sync_bitmap, true); | |
186 | + } | |
187 | + | |
188 | + if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) { | |
189 | + bdrv_merge_dirty_bitmap(s->dirty_bitmap, s->sync_bitmap, | |
190 | + NULL, &local_err); | |
191 | + if (local_err) { | |
192 | + goto fail; | |
193 | + } | |
194 | + } | |
195 | + | |
4fbd50e2 | 196 | bdrv_graph_wrlock(); |
059a9447 FG |
197 | ret = block_job_add_bdrv(&s->common, "source", bs, 0, |
198 | BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE | | |
4fbd50e2 | 199 | @@ -1979,6 +2041,9 @@ fail: |
059a9447 FG |
200 | if (s->dirty_bitmap) { |
201 | bdrv_release_dirty_bitmap(s->dirty_bitmap); | |
202 | } | |
203 | + if (s->sync_bitmap) { | |
204 | + bdrv_dirty_bitmap_set_busy(s->sync_bitmap, false); | |
205 | + } | |
206 | job_early_fail(&s->common.job); | |
207 | } | |
208 | ||
4fbd50e2 | 209 | @@ -2001,35 +2066,28 @@ void mirror_start(const char *job_id, BlockDriverState *bs, |
059a9447 FG |
210 | BlockDriverState *target, const char *replaces, |
211 | int creation_flags, int64_t speed, | |
212 | uint32_t granularity, int64_t buf_size, | |
213 | - MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, | |
214 | + MirrorSyncMode mode, BdrvDirtyBitmap *bitmap, | |
215 | + BitmapSyncMode bitmap_mode, | |
216 | + BlockMirrorBackingMode backing_mode, | |
217 | bool zero_target, | |
218 | BlockdevOnError on_source_error, | |
219 | BlockdevOnError on_target_error, | |
220 | bool unmap, const char *filter_node_name, | |
221 | MirrorCopyMode copy_mode, Error **errp) | |
222 | { | |
223 | - bool is_none_mode; | |
224 | BlockDriverState *base; | |
225 | ||
dc9827a6 FE |
226 | GLOBAL_STATE_CODE(); |
227 | ||
059a9447 FG |
228 | - if ((mode == MIRROR_SYNC_MODE_INCREMENTAL) || |
229 | - (mode == MIRROR_SYNC_MODE_BITMAP)) { | |
230 | - error_setg(errp, "Sync mode '%s' not supported", | |
231 | - MirrorSyncMode_str(mode)); | |
232 | - return; | |
233 | - } | |
f1eed34a FE |
234 | - |
235 | bdrv_graph_rdlock_main_loop(); | |
059a9447 | 236 | - is_none_mode = mode == MIRROR_SYNC_MODE_NONE; |
817b7667 | 237 | base = mode == MIRROR_SYNC_MODE_TOP ? bdrv_backing_chain_next(bs) : NULL; |
f1eed34a FE |
238 | bdrv_graph_rdunlock_main_loop(); |
239 | ||
059a9447 FG |
240 | mirror_start_job(job_id, bs, creation_flags, target, replaces, |
241 | speed, granularity, buf_size, backing_mode, zero_target, | |
242 | on_source_error, on_target_error, unmap, NULL, NULL, | |
243 | - &mirror_job_driver, is_none_mode, base, false, | |
244 | - filter_node_name, true, copy_mode, errp); | |
245 | + &mirror_job_driver, mode, bitmap, bitmap_mode, base, | |
246 | + false, filter_node_name, true, copy_mode, errp); | |
247 | } | |
248 | ||
249 | BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, | |
4fbd50e2 | 250 | @@ -2056,7 +2114,8 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, |
059a9447 FG |
251 | job_id, bs, creation_flags, base, NULL, speed, 0, 0, |
252 | MIRROR_LEAVE_BACKING_CHAIN, false, | |
253 | on_error, on_error, true, cb, opaque, | |
254 | - &commit_active_job_driver, false, base, auto_complete, | |
255 | + &commit_active_job_driver, MIRROR_SYNC_MODE_FULL, | |
256 | + NULL, 0, base, auto_complete, | |
257 | filter_node_name, false, MIRROR_COPY_MODE_BACKGROUND, | |
8dca018b SR |
258 | errp); |
259 | if (!job) { | |
059a9447 | 260 | diff --git a/blockdev.c b/blockdev.c |
4fbd50e2 | 261 | index 057601dcf0..8682814a7a 100644 |
059a9447 FG |
262 | --- a/blockdev.c |
263 | +++ b/blockdev.c | |
4fbd50e2 | 264 | @@ -2776,6 +2776,9 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, |
059a9447 | 265 | BlockDriverState *target, |
bf251437 | 266 | const char *replaces, |
059a9447 | 267 | enum MirrorSyncMode sync, |
059a9447 FG |
268 | + const char *bitmap_name, |
269 | + bool has_bitmap_mode, | |
270 | + BitmapSyncMode bitmap_mode, | |
271 | BlockMirrorBackingMode backing_mode, | |
272 | bool zero_target, | |
273 | bool has_speed, int64_t speed, | |
4fbd50e2 | 274 | @@ -2794,6 +2797,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, |
059a9447 | 275 | { |
817b7667 | 276 | BlockDriverState *unfiltered_bs; |
059a9447 FG |
277 | int job_flags = JOB_DEFAULT; |
278 | + BdrvDirtyBitmap *bitmap = NULL; | |
279 | ||
10e10933 FE |
280 | GLOBAL_STATE_CODE(); |
281 | GRAPH_RDLOCK_GUARD_MAINLOOP(); | |
4fbd50e2 | 282 | @@ -2848,6 +2852,29 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, |
059a9447 FG |
283 | sync = MIRROR_SYNC_MODE_FULL; |
284 | } | |
285 | ||
ea766207 | 286 | + if (bitmap_name) { |
059a9447 FG |
287 | + if (granularity) { |
288 | + error_setg(errp, "Granularity and bitmap cannot both be set"); | |
289 | + return; | |
290 | + } | |
291 | + | |
292 | + if (!has_bitmap_mode) { | |
293 | + error_setg(errp, "bitmap-mode must be specified if" | |
294 | + " a bitmap is provided"); | |
295 | + return; | |
296 | + } | |
297 | + | |
298 | + bitmap = bdrv_find_dirty_bitmap(bs, bitmap_name); | |
299 | + if (!bitmap) { | |
300 | + error_setg(errp, "Dirty bitmap '%s' not found", bitmap_name); | |
301 | + return; | |
302 | + } | |
303 | + | |
304 | + if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { | |
305 | + return; | |
306 | + } | |
307 | + } | |
308 | + | |
bf251437 | 309 | if (!replaces) { |
817b7667 SR |
310 | /* We want to mirror from @bs, but keep implicit filters on top */ |
311 | unfiltered_bs = bdrv_skip_implicit_filters(bs); | |
4fbd50e2 | 312 | @@ -2889,8 +2916,8 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, |
059a9447 FG |
313 | * and will allow to check whether the node still exist at mirror completion |
314 | */ | |
315 | mirror_start(job_id, bs, target, | |
bf251437 | 316 | - replaces, job_flags, |
059a9447 | 317 | - speed, granularity, buf_size, sync, backing_mode, zero_target, |
bf251437 FE |
318 | + replaces, job_flags, speed, granularity, buf_size, sync, |
319 | + bitmap, bitmap_mode, backing_mode, zero_target, | |
059a9447 FG |
320 | on_source_error, on_target_error, unmap, filter_node_name, |
321 | copy_mode, errp); | |
322 | } | |
4fbd50e2 | 323 | @@ -3034,6 +3061,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) |
059a9447 | 324 | |
bf251437 FE |
325 | blockdev_mirror_common(arg->job_id, bs, target_bs, |
326 | arg->replaces, arg->sync, | |
327 | + arg->bitmap, | |
059a9447 FG |
328 | + arg->has_bitmap_mode, arg->bitmap_mode, |
329 | backing_mode, zero_target, | |
330 | arg->has_speed, arg->speed, | |
331 | arg->has_granularity, arg->granularity, | |
4fbd50e2 | 332 | @@ -3053,6 +3082,8 @@ void qmp_blockdev_mirror(const char *job_id, |
059a9447 | 333 | const char *device, const char *target, |
bf251437 | 334 | const char *replaces, |
059a9447 | 335 | MirrorSyncMode sync, |
bf251437 | 336 | + const char *bitmap, |
059a9447 FG |
337 | + bool has_bitmap_mode, BitmapSyncMode bitmap_mode, |
338 | bool has_speed, int64_t speed, | |
339 | bool has_granularity, uint32_t granularity, | |
340 | bool has_buf_size, int64_t buf_size, | |
4fbd50e2 | 341 | @@ -3093,7 +3124,8 @@ void qmp_blockdev_mirror(const char *job_id, |
059a9447 FG |
342 | } |
343 | ||
bf251437 FE |
344 | blockdev_mirror_common(job_id, bs, target_bs, |
345 | - replaces, sync, backing_mode, | |
346 | + replaces, sync, | |
059a9447 FG |
347 | + bitmap, has_bitmap_mode, bitmap_mode, backing_mode, |
348 | zero_target, has_speed, speed, | |
349 | has_granularity, granularity, | |
350 | has_buf_size, buf_size, | |
dc9827a6 | 351 | diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h |
4fbd50e2 | 352 | index d2201e27f4..cc1387ae02 100644 |
dc9827a6 FE |
353 | --- a/include/block/block_int-global-state.h |
354 | +++ b/include/block/block_int-global-state.h | |
4fbd50e2 | 355 | @@ -158,7 +158,9 @@ void mirror_start(const char *job_id, BlockDriverState *bs, |
83faa3fe TL |
356 | BlockDriverState *target, const char *replaces, |
357 | int creation_flags, int64_t speed, | |
358 | uint32_t granularity, int64_t buf_size, | |
359 | - MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, | |
360 | + MirrorSyncMode mode, BdrvDirtyBitmap *bitmap, | |
361 | + BitmapSyncMode bitmap_mode, | |
362 | + BlockMirrorBackingMode backing_mode, | |
363 | bool zero_target, | |
364 | BlockdevOnError on_source_error, | |
365 | BlockdevOnError on_target_error, | |
059a9447 | 366 | diff --git a/qapi/block-core.json b/qapi/block-core.json |
4fbd50e2 | 367 | index 746d1694c2..45ab548dfe 100644 |
059a9447 FG |
368 | --- a/qapi/block-core.json |
369 | +++ b/qapi/block-core.json | |
4fbd50e2 | 370 | @@ -2174,6 +2174,15 @@ |
10e10933 FE |
371 | # destination (all the disk, only the sectors allocated in the |
372 | # topmost image, or only new I/O). | |
059a9447 | 373 | # |
10e10933 FE |
374 | +# @bitmap: The name of a bitmap to use for sync=bitmap mode. This |
375 | +# argument must be present for bitmap mode and absent otherwise. | |
376 | +# The bitmap's granularity is used instead of @granularity (Since | |
377 | +# 4.1). | |
059a9447 | 378 | +# |
10e10933 FE |
379 | +# @bitmap-mode: Specifies the type of data the bitmap should contain |
380 | +# after the operation concludes. Must be present if sync is | |
381 | +# "bitmap". Must NOT be present otherwise. (Since 4.1) | |
059a9447 | 382 | +# |
10e10933 FE |
383 | # @granularity: granularity of the dirty bitmap, default is 64K if the |
384 | # image format doesn't have clusters, 4K if the clusters are | |
385 | # smaller than that, else the cluster size. Must be a power of 2 | |
4fbd50e2 | 386 | @@ -2216,7 +2225,9 @@ |
059a9447 FG |
387 | { 'struct': 'DriveMirror', |
388 | 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', | |
389 | '*format': 'str', '*node-name': 'str', '*replaces': 'str', | |
390 | - 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode', | |
391 | + 'sync': 'MirrorSyncMode', '*bitmap': 'str', | |
392 | + '*bitmap-mode': 'BitmapSyncMode', | |
393 | + '*mode': 'NewImageMode', | |
394 | '*speed': 'int', '*granularity': 'uint32', | |
395 | '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', | |
396 | '*on-target-error': 'BlockdevOnError', | |
4fbd50e2 | 397 | @@ -2496,6 +2507,15 @@ |
10e10933 FE |
398 | # destination (all the disk, only the sectors allocated in the |
399 | # topmost image, or only new I/O). | |
059a9447 | 400 | # |
10e10933 FE |
401 | +# @bitmap: The name of a bitmap to use for sync=bitmap mode. This |
402 | +# argument must be present for bitmap mode and absent otherwise. | |
403 | +# The bitmap's granularity is used instead of @granularity (since | |
404 | +# 4.1). | |
059a9447 | 405 | +# |
10e10933 FE |
406 | +# @bitmap-mode: Specifies the type of data the bitmap should contain |
407 | +# after the operation concludes. Must be present if sync is | |
408 | +# "bitmap". Must NOT be present otherwise. (Since 4.1) | |
059a9447 | 409 | +# |
10e10933 FE |
410 | # @granularity: granularity of the dirty bitmap, default is 64K if the |
411 | # image format doesn't have clusters, 4K if the clusters are | |
412 | # smaller than that, else the cluster size. Must be a power of 2 | |
4fbd50e2 | 413 | @@ -2544,7 +2564,8 @@ |
059a9447 FG |
414 | { 'command': 'blockdev-mirror', |
415 | 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', | |
416 | '*replaces': 'str', | |
417 | - 'sync': 'MirrorSyncMode', | |
418 | + 'sync': 'MirrorSyncMode', '*bitmap': 'str', | |
419 | + '*bitmap-mode': 'BitmapSyncMode', | |
420 | '*speed': 'int', '*granularity': 'uint32', | |
421 | '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', | |
422 | '*on-target-error': 'BlockdevOnError', | |
8dca018b | 423 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c |
4fbd50e2 | 424 | index 3766d5de6b..afa44cbd34 100644 |
8dca018b SR |
425 | --- a/tests/unit/test-block-iothread.c |
426 | +++ b/tests/unit/test-block-iothread.c | |
4fbd50e2 FE |
427 | @@ -755,8 +755,8 @@ static void test_propagate_mirror(void) |
428 | ||
83faa3fe TL |
429 | /* Start a mirror job */ |
430 | mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0, | |
431 | - MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false, | |
432 | - BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, | |
433 | + MIRROR_SYNC_MODE_NONE, NULL, 0, MIRROR_OPEN_BACKING_CHAIN, | |
434 | + false, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, | |
435 | false, "filter_node", MIRROR_COPY_MODE_BACKGROUND, | |
436 | &error_abort); | |
4fbd50e2 | 437 |