All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Denis V. Lunev" <den@openvz.org>
To: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org, "Denis V. Lunev" <den@openvz.org>,
	Stefan Hajnoczi <stefanha@redhat.com>
Subject: [PATCH v7 23/25] iotests: cover a broken Format Extension and a combined repair
Date: Thu,  3 Sep 2026 16:41:41 +0200	[thread overview]
Message-ID: <20260903144143.2328870-24-den@openvz.org> (raw)
In-Reply-To: <20260903144143.2328870-1-den@openvz.org>

From: Denis V. Lunev <den@openvz.org>

An image which was not closed correctly may have had its Format
Extension cluster reused by a guest write, which is what the reuse of
those clusters is for. It has to open anyway, as the payload is intact,
and it has to stop pointing at what is no longer an extension.

The same damage in an image which was closed correctly is what an older
qemu leaves behind, as it ignores the extension in read-write mode and
truncates the file to the end of the payload on close. Both shapes of
it are covered: the cluster overwritten with something which is not an
extension, and the cluster truncated away with the header still
pointing past the end of the file. Neither keeps the image shut, and
qemu-img info is enough to tell, as it opens the image on its own.

Rebuilding the used bitmap after a leak is repaired reports the errors
which come with a BAT pointing a cluster twice, and those are the ones
qemu-img check is there to fix, so a duplicate entry next to a leak is
covered too.

Cc: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
---
 tests/qemu-iotests/tests/parallels-checks     | 80 +++++++++++++++++++
 tests/qemu-iotests/tests/parallels-checks.out | 57 +++++++++++++
 2 files changed, 137 insertions(+)

diff --git a/tests/qemu-iotests/tests/parallels-checks b/tests/qemu-iotests/tests/parallels-checks
index 84eb526f44..ca89ed5d62 100755
--- a/tests/qemu-iotests/tests/parallels-checks
+++ b/tests/qemu-iotests/tests/parallels-checks
@@ -443,6 +443,86 @@ echo "== guest data was never in doubt =="
 # Clear image
 _make_test_img $SIZE
 
+echo "== TEST BROKEN EXTENSION OF AN IMAGE WHICH WAS NOT CLOSED =="
+
+EXT_OFF_OFFSET=56
+
+echo "== add a persistent dirty bitmap =="
+$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" $BITMAP 2>&1 | _filter_testdir
+
+ext_off=$(peek_file_le "$TEST_IMG" $EXT_OFF_OFFSET 8)
+
+echo "== a guest write may reuse the extension cluster, so clobber it =="
+poke_file "$TEST_IMG" $((ext_off * 512)) "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+
+echo "== pretend the image was not closed correctly =="
+poke_file "$TEST_IMG" "$INUSE_OFFSET" "\x59\x6e\x6f\x74"
+
+echo "== the image opens, the extension is dropped =="
+{ $QEMU_IO -c "write -P 0x11 0 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io |
+    _filter_testdir | _filter_generated_node_ids
+
+echo "== and it stopped pointing at the broken extension =="
+echo "ext_off: $(peek_file_le "$TEST_IMG" $EXT_OFF_OFFSET 8)"
+
+echo "== an older qemu leaves the same damage behind a clean close =="
+_make_test_img $SIZE
+$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" $BITMAP 2>&1 | _filter_testdir
+ext_off=$(peek_file_le "$TEST_IMG" $EXT_OFF_OFFSET 8)
+poke_file "$TEST_IMG" $((ext_off * 512)) "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+_img_info | _filter_generated_node_ids
+
+echo "== truncating the extension away is dropped as well =="
+_make_test_img $SIZE
+$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" $BITMAP 2>&1 | _filter_testdir
+ext_off=$(peek_file_le "$TEST_IMG" $EXT_OFF_OFFSET 8)
+truncate -s $((ext_off * 512)) "$TEST_IMG"
+_img_info | _filter_generated_node_ids
+
+# Clear image
+_make_test_img $SIZE
+
+echo "== TEST REPAIR OF A DUPLICATE ENTRY NEXT TO A LEAK =="
+
+echo "== write two clusters =="
+{ $QEMU_IO -c "write -P 0x11 0 $CLUSTER_SIZE" \
+           -c "write -P 0x22 $CLUSTER_SIZE $CLUSTER_SIZE" \
+           "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+echo "== point the second BAT entry at the first cluster =="
+first=$(peek_file_le "$TEST_IMG" $BAT_OFFSET 4)
+poke_file_le "$TEST_IMG" $(($BAT_OFFSET + 4)) 4 $first
+
+echo "== leak a cluster at the end of the image =="
+file_size=`stat --printf="%s" "$TEST_IMG"`
+fallocate -xl $((file_size + CLUSTER_SIZE)) "$TEST_IMG"
+
+echo "== both are repaired in one go =="
+_check_test_img -r all
+
+echo "== and the image opens read-write afterwards =="
+{ $QEMU_IO -c "read -P 0x11 0 $CLUSTER_SIZE" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+# Clear image
+_make_test_img $SIZE
+
+echo "== TEST A LEAK WHICH DOES NOT FIT AN INT =="
+
+echo "== write one cluster =="
+{ $QEMU_IO -c "write -P 0x11 0 $CLUSTER_SIZE" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+echo "== leave 3 GiB of unused space behind it =="
+truncate -s $((3 * 1024 * 1024 * 1024)) "$TEST_IMG"
+
+echo "== closing the image truncates it without complaining =="
+{ $QEMU_IO -c "read -P 0x11 0 $CLUSTER_SIZE" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+file_size=`stat --printf="%s" "$TEST_IMG"`
+echo "file size: $file_size"
+
+# Clear image
+_make_test_img $SIZE
+
 echo "== TEST A DUPLICATE IN THE LAST ALLOCATED BAT ENTRY =="
 
 echo "== write two clusters =="
diff --git a/tests/qemu-iotests/tests/parallels-checks.out b/tests/qemu-iotests/tests/parallels-checks.out
index c6d9445440..f6806f82fa 100644
--- a/tests/qemu-iotests/tests/parallels-checks.out
+++ b/tests/qemu-iotests/tests/parallels-checks.out
@@ -302,6 +302,63 @@ qemu-img: warning: Dropping inconsistent bitmap b2c9e1a4-5d3f-4e8b-9a7c-6f0d1e2b
 read 65536/65536 bytes at offset 0
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
+== TEST BROKEN EXTENSION OF AN IMAGE WHICH WAS NOT CLOSED ==
+== add a persistent dirty bitmap ==
+== a guest write may reuse the extension cluster, so clobber it ==
+== pretend the image was not closed correctly ==
+== the image opens, the extension is dropped ==
+qemu-io: warning: Dropping the Format Extension of node 'NODE_NAME', which does not look like one: Wrong parallels Format Extension magic: 0xaaaaaaaaaaaaaaaa, expected: 0xab234cef23dcea87
+Repairing image was not closed correctly
+Repairing space leaked at the end of the image 1048576
+wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== and it stopped pointing at the broken extension ==
+ext_off: 0
+== an older qemu leaves the same damage behind a clean close ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
+qemu-img: warning: Dropping the Format Extension of node 'NODE_NAME', which does not look like one: Wrong IMGFMT Format Extension magic: 0xaaaaaaaaaaaaaaaa, expected: 0xab234cef23dcea87
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 4 MiB (4194304 bytes)
+== truncating the extension away is dropped as well ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
+qemu-img: warning: Dropping the Format Extension of node 'NODE_NAME', which does not look like one: Format Extension is outside the image file
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 4 MiB (4194304 bytes)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
+== TEST REPAIR OF A DUPLICATE ENTRY NEXT TO A LEAK ==
+== write two clusters ==
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1048576/1048576 bytes at offset 1048576
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== point the second BAT entry at the first cluster ==
+== leak a cluster at the end of the image ==
+== both are repaired in one go ==
+Repairing space leaked at the end of the image 2097152
+Repairing duplicate offset in BAT entry 1
+The following inconsistencies were found and repaired:
+
+    2 leaked clusters
+    1 corruptions
+
+Double checking the fixed image now...
+No errors were found on the image.
+== and the image opens read-write afterwards ==
+read 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
+== TEST A LEAK WHICH DOES NOT FIT AN INT ==
+== write one cluster ==
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+== leave 3 GiB of unused space behind it ==
+== closing the image truncates it without complaining ==
+read 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+file size: 2097152
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
 == TEST A DUPLICATE IN THE LAST ALLOCATED BAT ENTRY ==
 == write two clusters ==
 wrote 1048576/1048576 bytes at offset 0
-- 
2.53.0



  parent reply	other threads:[~2026-09-03 14:47 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-03 14:41 [PATCH v7 00/25] parallels: Add full dirty bitmap support Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 01/25] parallels: Set s->used_bmap to NULL in parallels_free_used_bitmap() Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 02/25] parallels: split inactivation out and add the activation counterpart Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 03/25] iotests: cover inactivating a read-only node Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 04/25] parallels: Make mark_used() a global function Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 05/25] parallels: Limit search in parallels_mark_used to the last marked cluster Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 06/25] parallels: Move host clusters allocation to a separate function Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 07/25] parallels: do not let the check die on what it is meant to report Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 08/25] parallels: Create used bitmap even if checks needed Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 09/25] parallels: Drop unused clusters at the end of the image Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 10/25] parallels: Remove unnecessary data_end field Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 11/25] parallels: Add dirty bitmaps saving Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 12/25] parallels: Let image extensions work in RW mode Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 13/25] parallels: Handle L1 entries equal to one Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 14/25] iotests: cover the Format Extension against the leak check Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 15/25] iotests: run the persistent dirty bitmap test on parallels Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 16/25] parallels: reject a bitmap L1 entry outside the data area Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 17/25] parallels: do not trust the bitmaps of an image which was not closed Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 18/25] parallels: implement removing a stored dirty bitmap Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 19/25] parallels: report the stored dirty bitmaps in qemu-img info Denis V. Lunev
2026-09-04  8:49   ` Markus Armbruster
2026-09-13 19:50     ` Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 20/25] iotests: rename parallels-read-bitmap to parallels-bitmap Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 21/25] iotests: cover storing a parallels dirty bitmap Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 22/25] iotests: cover the qemu-img bitmap operations on parallels Denis V. Lunev
2026-09-03 14:41 ` Denis V. Lunev [this message]
2026-09-03 14:41 ` [PATCH v7 24/25] tests: Turned on 256, 299, 304 and block-status-cache for parallels format Denis V. Lunev
2026-09-03 14:41 ` [PATCH v7 25/25] tests: Add parallels format support to image-fleecing Denis V. Lunev
2026-09-09 14:35   ` Vladimir Sementsov-Ogievskiy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260903144143.2328870-24-den@openvz.org \
    --to=den@openvz.org \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.