* [pve-devel] [PATCH qemu 1/2] fix #7222: add fix for crash caused by zero write during sync drive mirror
2026-01-12 15:59 [pve-devel] [PATCH-SERIES qemu 0/2] fix two completely different bugs both caused by non-aligned zero writes Fiona Ebner
@ 2026-01-12 15:59 ` Fiona Ebner
2026-01-12 15:59 ` [pve-devel] [PATCH qemu 2/2] fix #7197: add fix to avoid misaligned BLKZEROOUT casuing a hard error Fiona Ebner
1 sibling, 0 replies; 3+ messages in thread
From: Fiona Ebner @ 2026-01-12 15:59 UTC (permalink / raw)
To: pve-devel
Upstream submission [0].
[0]: https://lore.kernel.org/qemu-devel/20260112152544.261923-1-f.ebner@proxmox.com/T/
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
---
...d-support-for-sync-bitmap-mode-never.patch | 20 +++----
...-support-for-conditional-and-always-.patch | 6 +-
...-to-bdrv_dirty_bitmap_merge_internal.patch | 4 +-
.../0006-mirror-move-some-checks-to-qmp.patch | 4 +-
...ck-range-when-setting-zero-bitmap-fo.patch | 58 +++++++++++++++++++
debian/patches/series | 1 +
6 files changed, 76 insertions(+), 17 deletions(-)
create mode 100644 debian/patches/extra/0012-block-mirror-check-range-when-setting-zero-bitmap-fo.patch
diff --git a/debian/patches/bitmap-mirror/0001-drive-mirror-add-support-for-sync-bitmap-mode-never.patch b/debian/patches/bitmap-mirror/0001-drive-mirror-add-support-for-sync-bitmap-mode-never.patch
index 1a20886..6e93d4f 100644
--- a/debian/patches/bitmap-mirror/0001-drive-mirror-add-support-for-sync-bitmap-mode-never.patch
+++ b/debian/patches/bitmap-mirror/0001-drive-mirror-add-support-for-sync-bitmap-mode-never.patch
@@ -38,7 +38,7 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
5 files changed, 135 insertions(+), 21 deletions(-)
diff --git a/block/mirror.c b/block/mirror.c
-index b344182c74..a184e91478 100644
+index bc982cb99a..99805e7a9d 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -74,6 +74,8 @@ typedef struct MirrorBlockJob {
@@ -93,7 +93,7 @@ index b344182c74..a184e91478 100644
.pause = mirror_pause,
.complete = mirror_complete,
.cancel = commit_active_cancel,
-@@ -1835,6 +1850,8 @@ static BlockJob *mirror_start_job(
+@@ -1838,6 +1853,8 @@ static BlockJob *mirror_start_job(
BlockCompletionFunc *cb,
void *opaque,
const BlockJobDriver *driver,
@@ -102,7 +102,7 @@ index b344182c74..a184e91478 100644
BlockDriverState *base,
bool auto_complete, const char *filter_node_name,
bool is_mirror, MirrorCopyMode copy_mode,
-@@ -1850,10 +1867,39 @@ static BlockJob *mirror_start_job(
+@@ -1853,10 +1870,39 @@ static BlockJob *mirror_start_job(
GLOBAL_STATE_CODE();
@@ -144,7 +144,7 @@ index b344182c74..a184e91478 100644
assert(is_power_of_2(granularity));
if (buf_size < 0) {
-@@ -1995,6 +2041,8 @@ static BlockJob *mirror_start_job(
+@@ -1998,6 +2044,8 @@ static BlockJob *mirror_start_job(
s->on_source_error = on_source_error;
s->on_target_error = on_target_error;
s->sync_mode = sync_mode;
@@ -153,7 +153,7 @@ index b344182c74..a184e91478 100644
s->backing_mode = backing_mode;
s->target_is_zero = target_is_zero;
qatomic_set(&s->copy_mode, copy_mode);
-@@ -2020,6 +2068,18 @@ static BlockJob *mirror_start_job(
+@@ -2023,6 +2071,18 @@ static BlockJob *mirror_start_job(
*/
bdrv_disable_dirty_bitmap(s->dirty_bitmap);
@@ -172,7 +172,7 @@ index b344182c74..a184e91478 100644
bdrv_graph_wrlock_drained();
ret = block_job_add_bdrv(&s->common, "source", bs, 0,
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |
-@@ -2102,6 +2162,9 @@ fail:
+@@ -2105,6 +2165,9 @@ fail:
if (s->dirty_bitmap) {
bdrv_release_dirty_bitmap(s->dirty_bitmap);
}
@@ -182,7 +182,7 @@ index b344182c74..a184e91478 100644
job_early_fail(&s->common.job);
}
-@@ -2124,7 +2187,10 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
+@@ -2127,7 +2190,10 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
BlockDriverState *target, const char *replaces,
int creation_flags, int64_t speed,
uint32_t granularity, int64_t buf_size,
@@ -194,7 +194,7 @@ index b344182c74..a184e91478 100644
bool target_is_zero,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
-@@ -2135,13 +2201,6 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
+@@ -2138,13 +2204,6 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
GLOBAL_STATE_CODE();
@@ -208,7 +208,7 @@ index b344182c74..a184e91478 100644
bdrv_graph_rdlock_main_loop();
base = mode == MIRROR_SYNC_MODE_TOP ? bdrv_backing_chain_next(bs) : NULL;
bdrv_graph_rdunlock_main_loop();
-@@ -2149,8 +2208,8 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
+@@ -2152,8 +2211,8 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
mirror_start_job(job_id, bs, creation_flags, target, replaces,
speed, granularity, buf_size, mode, backing_mode,
target_is_zero, on_source_error, on_target_error, unmap,
@@ -219,7 +219,7 @@ index b344182c74..a184e91478 100644
}
BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
-@@ -2177,7 +2236,7 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
+@@ -2180,7 +2239,7 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
job_id, bs, creation_flags, base, NULL, speed, 0, 0,
MIRROR_SYNC_MODE_TOP, MIRROR_LEAVE_BACKING_CHAIN, false,
on_error, on_error, true, cb, opaque,
diff --git a/debian/patches/bitmap-mirror/0002-drive-mirror-add-support-for-conditional-and-always-.patch b/debian/patches/bitmap-mirror/0002-drive-mirror-add-support-for-conditional-and-always-.patch
index 7771887..8258adc 100644
--- a/debian/patches/bitmap-mirror/0002-drive-mirror-add-support-for-conditional-and-always-.patch
+++ b/debian/patches/bitmap-mirror/0002-drive-mirror-add-support-for-conditional-and-always-.patch
@@ -24,7 +24,7 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/block/mirror.c b/block/mirror.c
-index a184e91478..79b6f16d27 100644
+index 99805e7a9d..7dae4d6e8a 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -734,8 +734,6 @@ static int mirror_exit_common(Job *job)
@@ -55,7 +55,7 @@ index a184e91478..79b6f16d27 100644
bs_opaque->job = NULL;
bdrv_drained_end(src);
-@@ -1877,10 +1887,6 @@ static BlockJob *mirror_start_job(
+@@ -1880,10 +1890,6 @@ static BlockJob *mirror_start_job(
" sync mode",
MirrorSyncMode_str(sync_mode));
return NULL;
@@ -66,7 +66,7 @@ index a184e91478..79b6f16d27 100644
}
} else if (bitmap) {
error_setg(errp,
-@@ -1897,6 +1903,12 @@ static BlockJob *mirror_start_job(
+@@ -1900,6 +1906,12 @@ static BlockJob *mirror_start_job(
return NULL;
}
granularity = bdrv_dirty_bitmap_granularity(bitmap);
diff --git a/debian/patches/bitmap-mirror/0004-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch b/debian/patches/bitmap-mirror/0004-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch
index 9468058..4f9cdbd 100644
--- a/debian/patches/bitmap-mirror/0004-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch
+++ b/debian/patches/bitmap-mirror/0004-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch
@@ -16,7 +16,7 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/block/mirror.c b/block/mirror.c
-index 79b6f16d27..4741930d9b 100644
+index 7dae4d6e8a..0f96c8b5ce 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -855,8 +855,8 @@ static int mirror_exit_common(Job *job)
@@ -30,7 +30,7 @@ index 79b6f16d27..4741930d9b 100644
}
}
bdrv_release_dirty_bitmap(s->dirty_bitmap);
-@@ -2085,11 +2085,8 @@ static BlockJob *mirror_start_job(
+@@ -2088,11 +2088,8 @@ static BlockJob *mirror_start_job(
}
if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
diff --git a/debian/patches/bitmap-mirror/0006-mirror-move-some-checks-to-qmp.patch b/debian/patches/bitmap-mirror/0006-mirror-move-some-checks-to-qmp.patch
index 7014368..238f47b 100644
--- a/debian/patches/bitmap-mirror/0006-mirror-move-some-checks-to-qmp.patch
+++ b/debian/patches/bitmap-mirror/0006-mirror-move-some-checks-to-qmp.patch
@@ -21,10 +21,10 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
3 files changed, 70 insertions(+), 59 deletions(-)
diff --git a/block/mirror.c b/block/mirror.c
-index 4741930d9b..17f19ca015 100644
+index 0f96c8b5ce..5340a695b1 100644
--- a/block/mirror.c
+++ b/block/mirror.c
-@@ -1877,31 +1877,13 @@ static BlockJob *mirror_start_job(
+@@ -1880,31 +1880,13 @@ static BlockJob *mirror_start_job(
GLOBAL_STATE_CODE();
diff --git a/debian/patches/extra/0012-block-mirror-check-range-when-setting-zero-bitmap-fo.patch b/debian/patches/extra/0012-block-mirror-check-range-when-setting-zero-bitmap-fo.patch
new file mode 100644
index 0000000..908d721
--- /dev/null
+++ b/debian/patches/extra/0012-block-mirror-check-range-when-setting-zero-bitmap-fo.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Fiona Ebner <f.ebner@proxmox.com>
+Date: Mon, 12 Jan 2026 15:32:52 +0100
+Subject: [PATCH] block/mirror: check range when setting zero bitmap for sync
+ write
+
+Some Proxmox users reported an occasional assertion failure [0][1] in
+busy VMs when using drive mirror with active mode. In particular, the
+failure may occur for zero writes shorter than the job granularity:
+
+> #0 0x00007b421154b507 in abort ()
+> #1 0x00007b421154b420 in ?? ()
+> #2 0x0000641c582e061f in bitmap_set (map=0x7b4204014e00, start=14, nr=-1)
+> #3 0x0000641c58062824 in do_sync_target_write (job=0x641c7e73d1e0,
+> method=MIRROR_METHOD_ZERO, offset=852480, bytes=4096, qiov=0x0, flags=0)
+> #4 0x0000641c58062250 in bdrv_mirror_top_do_write (bs=0x641c7e62e1f0,
+ method=MIRROR_METHOD_ZERO, copy_to_target=true, offset=852480,
+ bytes=4096, qiov=0x0, flags=0)
+> #5 0x0000641c58061f31 in bdrv_mirror_top_pwrite_zeroes (bs=0x641c7e62e1f0,
+ offset=852480, bytes=4096, flags=0)
+
+The range for the dirty bitmap described by dirty_bitmap_offset and
+dirty_bitmap_end is narrower than the original range and in fact,
+dirty_bitmap_end might be smaller than dirty_bitmap_offset. There
+already is a check for 'dirty_bitmap_offset < dirty_bitmap_end' before
+resetting the dirty bitmap. Add such a check for setting the zero
+bitmap too, which uses the same narrower range.
+
+[0]: https://forum.proxmox.com/threads/177981/
+[1]: https://bugzilla.proxmox.com/show_bug.cgi?id=7222
+
+Cc: qemu-stable@nongnu.org
+Fixes: 7e277545b9 ("mirror: Skip writing zeroes when target is already zero")
+Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
+---
+ block/mirror.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/block/mirror.c b/block/mirror.c
+index b344182c74..bc982cb99a 100644
+--- a/block/mirror.c
++++ b/block/mirror.c
+@@ -1514,9 +1514,12 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method,
+ assert(!qiov);
+ ret = blk_co_pwrite_zeroes(job->target, offset, bytes, flags);
+ if (job->zero_bitmap && ret >= 0) {
+- bitmap_set(job->zero_bitmap, dirty_bitmap_offset / job->granularity,
+- (dirty_bitmap_end - dirty_bitmap_offset) /
+- job->granularity);
++ if (dirty_bitmap_offset < dirty_bitmap_end) {
++ bitmap_set(job->zero_bitmap,
++ dirty_bitmap_offset / job->granularity,
++ (dirty_bitmap_end - dirty_bitmap_offset) /
++ job->granularity);
++ }
+ }
+ break;
+
diff --git a/debian/patches/series b/debian/patches/series
index 83e7f6d..99d9369 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -9,6 +9,7 @@ extra/0008-ui-vdagent-fix-windows-agent-regression.patch
extra/0009-file-posix-populate-pwrite_zeroes_alignment.patch
extra/0010-block-use-pwrite_zeroes_alignment-when-writing-first.patch
extra/0011-block-io_uring-avoid-potentially-getting-stuck-after.patch
+extra/0012-block-mirror-check-range-when-setting-zero-bitmap-fo.patch
bitmap-mirror/0001-drive-mirror-add-support-for-sync-bitmap-mode-never.patch
bitmap-mirror/0002-drive-mirror-add-support-for-conditional-and-always-.patch
bitmap-mirror/0003-mirror-add-check-for-bitmap-mode-without-bitmap.patch
--
2.47.3
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 3+ messages in thread