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