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