--- /dev/null
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
+Date: Thu, 11 Apr 2024 11:29:23 +0200
+Subject: [PATCH] block/copy-before-write: support unligned snapshot-discard
+
+First thing that crashes on unligned access here is
+bdrv_reset_dirty_bitmap(). Correct way is to align-down the
+snapshot-discard request.
+
+Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
+Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
+Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
+---
+ block/copy-before-write.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/block/copy-before-write.c b/block/copy-before-write.c
+index a2dddf6f57..0a219c2b75 100644
+--- a/block/copy-before-write.c
++++ b/block/copy-before-write.c
+@@ -325,14 +325,24 @@ static int coroutine_fn GRAPH_RDLOCK
+ cbw_co_pdiscard_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes)
+ {
+ BDRVCopyBeforeWriteState *s = bs->opaque;
++ uint32_t cluster_size = block_copy_cluster_size(s->bcs);
++ int64_t aligned_offset = QEMU_ALIGN_UP(offset, cluster_size);
++ int64_t aligned_end = QEMU_ALIGN_DOWN(offset + bytes, cluster_size);
++ int64_t aligned_bytes;
++
++ if (aligned_end <= aligned_offset) {
++ return 0;
++ }
++ aligned_bytes = aligned_end - aligned_offset;
+
+ WITH_QEMU_LOCK_GUARD(&s->lock) {
+- bdrv_reset_dirty_bitmap(s->access_bitmap, offset, bytes);
++ bdrv_reset_dirty_bitmap(s->access_bitmap, aligned_offset,
++ aligned_bytes);
+ }
+
+- block_copy_reset(s->bcs, offset, bytes);
++ block_copy_reset(s->bcs, aligned_offset, aligned_bytes);
+
+- return bdrv_co_pdiscard(s->target, offset, bytes);
++ return bdrv_co_pdiscard(s->target, aligned_offset, aligned_bytes);
+ }
+
+ static void cbw_refresh_filename(BlockDriverState *bs)