]> 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.1-2
[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>
ddbf7a87 29Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
059a9447 30---
8dca018b
SR
31 block/mirror.c | 98 +++++++++++++++++++++++++-------
32 blockdev.c | 39 ++++++++++++-
33 include/block/block_int.h | 4 +-
34 qapi/block-core.json | 29 ++++++++--
35 tests/unit/test-block-iothread.c | 4 +-
059a9447
FG
36 5 files changed, 145 insertions(+), 29 deletions(-)
37
059a9447 38diff --git a/block/mirror.c b/block/mirror.c
ddbf7a87 39index 85b781bc21..0821214138 100644
059a9447
FG
40--- a/block/mirror.c
41+++ b/block/mirror.c
817b7667 42@@ -50,7 +50,7 @@ typedef struct MirrorBlockJob {
059a9447
FG
43 BlockDriverState *to_replace;
44 /* Used to block operations on the drive-mirror-replace target */
45 Error *replace_blocker;
46- bool is_none_mode;
47+ MirrorSyncMode sync_mode;
48 BlockMirrorBackingMode backing_mode;
49 /* Whether the target image requires explicit zero-initialization */
50 bool zero_target;
817b7667 51@@ -65,6 +65,8 @@ typedef struct MirrorBlockJob {
059a9447
FG
52 size_t buf_size;
53 int64_t bdev_length;
54 unsigned long *cow_bitmap;
55+ BdrvDirtyBitmap *sync_bitmap;
56+ BitmapSyncMode bitmap_mode;
57 BdrvDirtyBitmap *dirty_bitmap;
58 BdrvDirtyBitmapIter *dbi;
59 uint8_t *buf;
ddbf7a87 60@@ -697,7 +699,8 @@ static int mirror_exit_common(Job *job)
059a9447
FG
61 bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
62 &error_abort);
63 if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {
64- BlockDriverState *backing = s->is_none_mode ? src : s->base;
65+ BlockDriverState *backing;
66+ backing = s->sync_mode == MIRROR_SYNC_MODE_NONE ? src : s->base;
817b7667
SR
67 BlockDriverState *unfiltered_target = bdrv_skip_filters(target_bs);
68
69 if (bdrv_cow_bs(unfiltered_target) != backing) {
ddbf7a87 70@@ -802,6 +805,16 @@ static void mirror_abort(Job *job)
059a9447
FG
71 assert(ret == 0);
72 }
73
74+/* Always called after commit/abort. */
75+static void mirror_clean(Job *job)
76+{
77+ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
78+
79+ if (s->sync_bitmap) {
80+ bdrv_dirty_bitmap_set_busy(s->sync_bitmap, false);
81+ }
82+}
83+
84 static void coroutine_fn mirror_throttle(MirrorBlockJob *s)
85 {
86 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
ddbf7a87 87@@ -983,7 +996,8 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
059a9447
FG
88 mirror_free_init(s);
89
90 s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
91- if (!s->is_none_mode) {
92+ if ((s->sync_mode == MIRROR_SYNC_MODE_TOP) ||
93+ (s->sync_mode == MIRROR_SYNC_MODE_FULL)) {
94 ret = mirror_dirty_init(s);
95 if (ret < 0 || job_is_cancelled(&s->common.job)) {
96 goto immediate_exit;
ddbf7a87 97@@ -1216,6 +1230,7 @@ static const BlockJobDriver mirror_job_driver = {
059a9447
FG
98 .run = mirror_run,
99 .prepare = mirror_prepare,
100 .abort = mirror_abort,
101+ .clean = mirror_clean,
102 .pause = mirror_pause,
103 .complete = mirror_complete,
8dca018b 104 .cancel = mirror_cancel,
ddbf7a87 105@@ -1232,6 +1247,7 @@ static const BlockJobDriver commit_active_job_driver = {
059a9447
FG
106 .run = mirror_run,
107 .prepare = mirror_prepare,
108 .abort = mirror_abort,
109+ .clean = mirror_clean,
110 .pause = mirror_pause,
111 .complete = mirror_complete,
112 },
ddbf7a87 113@@ -1594,7 +1610,10 @@ static BlockJob *mirror_start_job(
059a9447
FG
114 BlockCompletionFunc *cb,
115 void *opaque,
116 const BlockJobDriver *driver,
117- bool is_none_mode, BlockDriverState *base,
118+ MirrorSyncMode sync_mode,
119+ BdrvDirtyBitmap *bitmap,
120+ BitmapSyncMode bitmap_mode,
121+ BlockDriverState *base,
122 bool auto_complete, const char *filter_node_name,
123 bool is_mirror, MirrorCopyMode copy_mode,
124 Error **errp)
ddbf7a87 125@@ -1606,10 +1625,39 @@ static BlockJob *mirror_start_job(
8dca018b 126 uint64_t target_perms, target_shared_perms;
059a9447
FG
127 int ret;
128
129- if (granularity == 0) {
059a9447
FG
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;
ddbf7a87
TL
150+ }
151+
059a9447
FG
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) {
ddbf7a87
TL
161 granularity = bdrv_get_default_bitmap_granularity(target);
162 }
163-
059a9447
FG
164 assert(is_power_of_2(granularity));
165
166 if (buf_size < 0) {
ddbf7a87 167@@ -1747,7 +1795,9 @@ static BlockJob *mirror_start_job(
059a9447
FG
168 s->replaces = g_strdup(replaces);
169 s->on_source_error = on_source_error;
170 s->on_target_error = on_target_error;
171- s->is_none_mode = is_none_mode;
172+ s->sync_mode = sync_mode;
173+ s->sync_bitmap = bitmap;
174+ s->bitmap_mode = bitmap_mode;
175 s->backing_mode = backing_mode;
176 s->zero_target = zero_target;
177 s->copy_mode = copy_mode;
ddbf7a87 178@@ -1768,6 +1818,18 @@ static BlockJob *mirror_start_job(
059a9447
FG
179 bdrv_disable_dirty_bitmap(s->dirty_bitmap);
180 }
181
182+ if (s->sync_bitmap) {
183+ bdrv_dirty_bitmap_set_busy(s->sync_bitmap, true);
184+ }
185+
186+ if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
187+ bdrv_merge_dirty_bitmap(s->dirty_bitmap, s->sync_bitmap,
188+ NULL, &local_err);
189+ if (local_err) {
190+ goto fail;
191+ }
192+ }
193+
194 ret = block_job_add_bdrv(&s->common, "source", bs, 0,
195 BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |
196 BLK_PERM_CONSISTENT_READ,
ddbf7a87 197@@ -1845,6 +1907,9 @@ fail:
059a9447
FG
198 if (s->dirty_bitmap) {
199 bdrv_release_dirty_bitmap(s->dirty_bitmap);
200 }
201+ if (s->sync_bitmap) {
202+ bdrv_dirty_bitmap_set_busy(s->sync_bitmap, false);
203+ }
204 job_early_fail(&s->common.job);
205 }
206
ddbf7a87 207@@ -1862,29 +1927,23 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
059a9447
FG
208 BlockDriverState *target, const char *replaces,
209 int creation_flags, int64_t speed,
210 uint32_t granularity, int64_t buf_size,
211- MirrorSyncMode mode, BlockMirrorBackingMode backing_mode,
212+ MirrorSyncMode mode, BdrvDirtyBitmap *bitmap,
213+ BitmapSyncMode bitmap_mode,
214+ BlockMirrorBackingMode backing_mode,
215 bool zero_target,
216 BlockdevOnError on_source_error,
217 BlockdevOnError on_target_error,
218 bool unmap, const char *filter_node_name,
219 MirrorCopyMode copy_mode, Error **errp)
220 {
221- bool is_none_mode;
222 BlockDriverState *base;
223
224- if ((mode == MIRROR_SYNC_MODE_INCREMENTAL) ||
225- (mode == MIRROR_SYNC_MODE_BITMAP)) {
226- error_setg(errp, "Sync mode '%s' not supported",
227- MirrorSyncMode_str(mode));
228- return;
229- }
230- is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
817b7667 231 base = mode == MIRROR_SYNC_MODE_TOP ? bdrv_backing_chain_next(bs) : NULL;
059a9447
FG
232 mirror_start_job(job_id, bs, creation_flags, target, replaces,
233 speed, granularity, buf_size, backing_mode, zero_target,
234 on_source_error, on_target_error, unmap, NULL, NULL,
235- &mirror_job_driver, is_none_mode, base, false,
236- filter_node_name, true, copy_mode, errp);
237+ &mirror_job_driver, mode, bitmap, bitmap_mode, base,
238+ false, filter_node_name, true, copy_mode, errp);
239 }
240
241 BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
ddbf7a87 242@@ -1909,7 +1968,8 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
059a9447
FG
243 job_id, bs, creation_flags, base, NULL, speed, 0, 0,
244 MIRROR_LEAVE_BACKING_CHAIN, false,
245 on_error, on_error, true, cb, opaque,
246- &commit_active_job_driver, false, base, auto_complete,
247+ &commit_active_job_driver, MIRROR_SYNC_MODE_FULL,
248+ NULL, 0, base, auto_complete,
249 filter_node_name, false, MIRROR_COPY_MODE_BACKGROUND,
8dca018b
SR
250 errp);
251 if (!job) {
059a9447 252diff --git a/blockdev.c b/blockdev.c
f376b2b9 253index 3d8ac368a1..03e99264dc 100644
059a9447
FG
254--- a/blockdev.c
255+++ b/blockdev.c
f376b2b9 256@@ -2957,6 +2957,10 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
059a9447
FG
257 BlockDriverState *target,
258 bool has_replaces, const char *replaces,
259 enum MirrorSyncMode sync,
260+ bool has_bitmap,
261+ const char *bitmap_name,
262+ bool has_bitmap_mode,
263+ BitmapSyncMode bitmap_mode,
264 BlockMirrorBackingMode backing_mode,
265 bool zero_target,
266 bool has_speed, int64_t speed,
f376b2b9 267@@ -2976,6 +2980,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
059a9447 268 {
817b7667 269 BlockDriverState *unfiltered_bs;
059a9447
FG
270 int job_flags = JOB_DEFAULT;
271+ BdrvDirtyBitmap *bitmap = NULL;
272
273 if (!has_speed) {
274 speed = 0;
f376b2b9 275@@ -3030,6 +3035,29 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
059a9447
FG
276 sync = MIRROR_SYNC_MODE_FULL;
277 }
278
279+ if (has_bitmap) {
280+ if (granularity) {
281+ error_setg(errp, "Granularity and bitmap cannot both be set");
282+ return;
283+ }
284+
285+ if (!has_bitmap_mode) {
286+ error_setg(errp, "bitmap-mode must be specified if"
287+ " a bitmap is provided");
288+ return;
289+ }
290+
291+ bitmap = bdrv_find_dirty_bitmap(bs, bitmap_name);
292+ if (!bitmap) {
293+ error_setg(errp, "Dirty bitmap '%s' not found", bitmap_name);
294+ return;
295+ }
296+
297+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
298+ return;
299+ }
300+ }
301+
817b7667
SR
302 if (!has_replaces) {
303 /* We want to mirror from @bs, but keep implicit filters on top */
304 unfiltered_bs = bdrv_skip_implicit_filters(bs);
f376b2b9 305@@ -3076,8 +3104,8 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
059a9447
FG
306 * and will allow to check whether the node still exist at mirror completion
307 */
308 mirror_start(job_id, bs, target,
309- has_replaces ? replaces : NULL, job_flags,
310- speed, granularity, buf_size, sync, backing_mode, zero_target,
311+ has_replaces ? replaces : NULL, job_flags, speed, granularity,
312+ buf_size, sync, bitmap, bitmap_mode, backing_mode, zero_target,
313 on_source_error, on_target_error, unmap, filter_node_name,
314 copy_mode, errp);
315 }
f376b2b9 316@@ -3222,6 +3250,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
059a9447
FG
317
318 blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs,
319 arg->has_replaces, arg->replaces, arg->sync,
320+ arg->has_bitmap, arg->bitmap,
321+ arg->has_bitmap_mode, arg->bitmap_mode,
322 backing_mode, zero_target,
323 arg->has_speed, arg->speed,
324 arg->has_granularity, arg->granularity,
f376b2b9 325@@ -3243,6 +3273,8 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
059a9447
FG
326 const char *device, const char *target,
327 bool has_replaces, const char *replaces,
328 MirrorSyncMode sync,
329+ bool has_bitmap, const char *bitmap,
330+ bool has_bitmap_mode, BitmapSyncMode bitmap_mode,
331 bool has_speed, int64_t speed,
332 bool has_granularity, uint32_t granularity,
333 bool has_buf_size, int64_t buf_size,
f376b2b9 334@@ -3292,7 +3324,8 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
059a9447
FG
335 }
336
337 blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs,
338- has_replaces, replaces, sync, backing_mode,
339+ has_replaces, replaces, sync, has_bitmap,
340+ bitmap, has_bitmap_mode, bitmap_mode, backing_mode,
341 zero_target, has_speed, speed,
342 has_granularity, granularity,
343 has_buf_size, buf_size,
83faa3fe 344diff --git a/include/block/block_int.h b/include/block/block_int.h
ddbf7a87 345index c31cbd034a..11442893d0 100644
83faa3fe
TL
346--- a/include/block/block_int.h
347+++ b/include/block/block_int.h
ddbf7a87 348@@ -1254,7 +1254,9 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
83faa3fe
TL
349 BlockDriverState *target, const char *replaces,
350 int creation_flags, int64_t speed,
351 uint32_t granularity, int64_t buf_size,
352- MirrorSyncMode mode, BlockMirrorBackingMode backing_mode,
353+ MirrorSyncMode mode, BdrvDirtyBitmap *bitmap,
354+ BitmapSyncMode bitmap_mode,
355+ BlockMirrorBackingMode backing_mode,
356 bool zero_target,
357 BlockdevOnError on_source_error,
358 BlockdevOnError on_target_error,
059a9447 359diff --git a/qapi/block-core.json b/qapi/block-core.json
f376b2b9 360index 675d8265eb..6356a63695 100644
059a9447
FG
361--- a/qapi/block-core.json
362+++ b/qapi/block-core.json
f376b2b9 363@@ -1938,10 +1938,19 @@
059a9447
FG
364 # (all the disk, only the sectors allocated in the topmost image, or
365 # only new I/O).
366 #
367+# @bitmap: The name of a bitmap to use for sync=bitmap mode. This argument must
368+# be present for bitmap mode and absent otherwise. The bitmap's
369+# granularity is used instead of @granularity (since 4.1).
370+#
371+# @bitmap-mode: Specifies the type of data the bitmap should contain after
372+# the operation concludes. Must be present if sync is "bitmap".
373+# Must NOT be present otherwise. (Since 4.1)
374+#
375 # @granularity: granularity of the dirty bitmap, default is 64K
376 # if the image format doesn't have clusters, 4K if the clusters
377 # are smaller than that, else the cluster size. Must be a
378-# power of 2 between 512 and 64M (since 1.4).
379+# power of 2 between 512 and 64M. Must not be specified if
380+# @bitmap is present (since 1.4).
381 #
382 # @buf-size: maximum amount of data in flight from source to
383 # target (since 1.4).
f376b2b9 384@@ -1979,7 +1988,9 @@
059a9447
FG
385 { 'struct': 'DriveMirror',
386 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
387 '*format': 'str', '*node-name': 'str', '*replaces': 'str',
388- 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode',
389+ 'sync': 'MirrorSyncMode', '*bitmap': 'str',
390+ '*bitmap-mode': 'BitmapSyncMode',
391+ '*mode': 'NewImageMode',
392 '*speed': 'int', '*granularity': 'uint32',
393 '*buf-size': 'int', '*on-source-error': 'BlockdevOnError',
394 '*on-target-error': 'BlockdevOnError',
f376b2b9 395@@ -2247,10 +2258,19 @@
059a9447
FG
396 # (all the disk, only the sectors allocated in the topmost image, or
397 # only new I/O).
398 #
399+# @bitmap: The name of a bitmap to use for sync=bitmap mode. This argument must
400+# be present for bitmap mode and absent otherwise. The bitmap's
401+# granularity is used instead of @granularity (since 4.1).
402+#
403+# @bitmap-mode: Specifies the type of data the bitmap should contain after
404+# the operation concludes. Must be present if sync is "bitmap".
405+# Must NOT be present otherwise. (Since 4.1)
406+#
407 # @granularity: granularity of the dirty bitmap, default is 64K
408 # if the image format doesn't have clusters, 4K if the clusters
409 # are smaller than that, else the cluster size. Must be a
410-# power of 2 between 512 and 64M
411+# power of 2 between 512 and 64M . Must not be specified if
412+# @bitmap is present.
413 #
414 # @buf-size: maximum amount of data in flight from source to
415 # target
f376b2b9 416@@ -2299,7 +2319,8 @@
059a9447
FG
417 { 'command': 'blockdev-mirror',
418 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
419 '*replaces': 'str',
420- 'sync': 'MirrorSyncMode',
421+ 'sync': 'MirrorSyncMode', '*bitmap': 'str',
422+ '*bitmap-mode': 'BitmapSyncMode',
423 '*speed': 'int', '*granularity': 'uint32',
424 '*buf-size': 'int', '*on-source-error': 'BlockdevOnError',
425 '*on-target-error': 'BlockdevOnError',
8dca018b 426diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
f376b2b9 427index c39e70b2f5..470ef79ae0 100644
8dca018b
SR
428--- a/tests/unit/test-block-iothread.c
429+++ b/tests/unit/test-block-iothread.c
f376b2b9 430@@ -617,8 +617,8 @@ static void test_propagate_mirror(void)
83faa3fe
TL
431
432 /* Start a mirror job */
433 mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0,
434- MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false,
435- BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
436+ MIRROR_SYNC_MODE_NONE, NULL, 0, MIRROR_OPEN_BACKING_CHAIN,
437+ false, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
438 false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
439 &error_abort);
440 job = job_get("job0");