]> git.proxmox.com Git - pve-qemu.git/blame - debian/patches/bitmap-mirror/0001-drive-mirror-add-support-for-sync-bitmap-mode-never.patch
backup: improve error when copy-before-write fails for fleecing
[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>
f1eed34a 30[FE: rebased for 8.2.2]
bf251437 31Signed-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 40diff --git a/block/mirror.c b/block/mirror.c
4fbd50e2 41index 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 260diff --git a/blockdev.c b/blockdev.c
4fbd50e2 261index 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 351diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h
4fbd50e2 352index 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 366diff --git a/qapi/block-core.json b/qapi/block-core.json
4fbd50e2 367index 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 423diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
4fbd50e2 424index 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