2019-03-07 17:58:38 +03:00
|
|
|
#!/usr/bin/env bash
|
2021-01-16 16:44:19 +03:00
|
|
|
# group: rw auto quick
|
2013-08-30 16:34:31 +04:00
|
|
|
#
|
|
|
|
# Test case for image corruption (overlapping data structures) in qcow2
|
|
|
|
#
|
|
|
|
# Copyright (C) 2013 Red Hat, Inc.
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
|
|
|
|
# creator
|
|
|
|
owner=mreitz@redhat.com
|
|
|
|
|
2013-10-11 16:02:11 +04:00
|
|
|
seq="$(basename $0)"
|
2013-08-30 16:34:31 +04:00
|
|
|
echo "QA output created by $seq"
|
|
|
|
|
|
|
|
status=1 # failure is the default!
|
|
|
|
|
|
|
|
_cleanup()
|
|
|
|
{
|
|
|
|
_cleanup_test_img
|
|
|
|
}
|
|
|
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
|
|
|
|
tests: iotests: drop some stderr line
In my Out-Of-Band test, "check -qcow2 060" fail with this:
--- /home/peterx/git/qemu/tests/qemu-iotests/060.out
+++ /home/peterx/git/qemu/bin/tests/qemu-iotests/060.out.bad
@@ -427,8 +427,8 @@
QMP_VERSION
{"return": {}}
qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1
index: 0); further non-fatal corruption events will be suppressed
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a0
0 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}}
read failed: Input/output error
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a0
0 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}}
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP},
"event": "SHUTDOWN", "data": {"guest": false}}
The order of the event and the in/out error line is swapped. I didn't
dig up the reason, but AFAIU what we want to verify is the event rather
than stderr. Let's drop the stderr line directly for this test.
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20180620073223.31964-5-peterx@redhat.com>
[Commit message touched up]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-06-20 10:32:20 +03:00
|
|
|
# Sometimes the error line might be dumped before/after an event
|
|
|
|
# randomly. Mask it out for specific test that may trigger this
|
|
|
|
# uncertainty for current test for now.
|
|
|
|
_filter_io_error()
|
|
|
|
{
|
|
|
|
sed '/Input\/output error/d'
|
|
|
|
}
|
|
|
|
|
2013-08-30 16:34:31 +04:00
|
|
|
# get standard environment, filters and checks
|
|
|
|
. ./common.rc
|
|
|
|
. ./common.filter
|
|
|
|
|
2019-11-07 19:36:47 +03:00
|
|
|
# This tests qcow2-specific low-level functionality
|
2013-08-30 16:34:31 +04:00
|
|
|
_supported_fmt qcow2
|
2020-10-27 22:05:59 +03:00
|
|
|
_supported_proto file fuse
|
2013-08-30 16:34:31 +04:00
|
|
|
_supported_os Linux
|
2019-11-07 19:37:07 +03:00
|
|
|
# These tests only work for compat=1.1 images without an external
|
|
|
|
# data file with refcount_bits=16
|
|
|
|
_unsupported_imgopts 'compat=0.10' data_file \
|
|
|
|
'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
|
2013-08-30 16:34:31 +04:00
|
|
|
|
2019-12-04 18:46:13 +03:00
|
|
|
# The repair process will create a large file - so check for availability first
|
|
|
|
_require_large_file 64G
|
|
|
|
|
2013-08-30 16:34:31 +04:00
|
|
|
rt_offset=65536 # 0x10000 (XXX: just an assumption)
|
|
|
|
rb_offset=131072 # 0x20000 (XXX: just an assumption)
|
|
|
|
l1_offset=196608 # 0x30000 (XXX: just an assumption)
|
|
|
|
l2_offset=262144 # 0x40000 (XXX: just an assumption)
|
2013-10-11 16:02:11 +04:00
|
|
|
l2_offset_after_snapshot=524288 # 0x80000 (XXX: just an assumption)
|
2013-08-30 16:34:31 +04:00
|
|
|
|
2013-10-11 16:02:11 +04:00
|
|
|
OPEN_RW="open -o overlap-check=all $TEST_IMG"
|
|
|
|
# Overlap checks are done before write operations only, therefore opening an
|
|
|
|
# image read-only makes the overlap-check option irrelevant
|
|
|
|
OPEN_RO="open -r $TEST_IMG"
|
|
|
|
|
2013-08-30 16:34:31 +04:00
|
|
|
echo
|
|
|
|
echo "=== Testing L2 reference into L1 ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
# Link first L1 entry (first L2 table) onto itself
|
|
|
|
# (Note the MSb in the L1 entry is set, ensuring the refcount is one - else any
|
|
|
|
# later write will result in a COW operation, effectively ruining this attempt
|
|
|
|
# on image corruption)
|
|
|
|
poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x03\x00\x00"
|
|
|
|
_check_test_img
|
|
|
|
|
|
|
|
# The corrupt bit should not be set anyway
|
2014-05-25 01:24:58 +04:00
|
|
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
2013-08-30 16:34:31 +04:00
|
|
|
|
|
|
|
# Try to write something, thereby forcing the corrupt bit to be set
|
2013-10-11 16:02:11 +04:00
|
|
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
|
2013-08-30 16:34:31 +04:00
|
|
|
|
|
|
|
# The corrupt bit must now be set
|
2014-05-25 01:24:58 +04:00
|
|
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
2013-08-30 16:34:31 +04:00
|
|
|
|
2014-09-30 23:31:29 +04:00
|
|
|
# This information should be available through qemu-img info
|
2014-11-27 17:03:53 +03:00
|
|
|
_img_info --format-specific
|
2014-09-30 23:31:29 +04:00
|
|
|
|
2013-08-30 16:34:31 +04:00
|
|
|
# Try to open the image R/W (which should fail)
|
2013-10-11 16:02:11 +04:00
|
|
|
$QEMU_IO -c "$OPEN_RW" -c "read 0 512" 2>&1 | _filter_qemu_io \
|
|
|
|
| _filter_testdir \
|
|
|
|
| _filter_imgfmt
|
2013-08-30 16:34:31 +04:00
|
|
|
|
|
|
|
# Try to open it RO (which should succeed)
|
2013-10-11 16:02:11 +04:00
|
|
|
$QEMU_IO -c "$OPEN_RO" -c "read 0 512" | _filter_qemu_io
|
2013-08-30 16:34:31 +04:00
|
|
|
|
|
|
|
# We could now try to fix the image, but this would probably fail (how should an
|
|
|
|
# L2 table linked onto the L1 table be fixed?)
|
|
|
|
|
|
|
|
echo
|
|
|
|
echo "=== Testing cluster data reference into refcount block ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
# Allocate L2 table
|
|
|
|
truncate -s "$(($l2_offset+65536))" "$TEST_IMG"
|
|
|
|
poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x04\x00\x00"
|
|
|
|
# Mark cluster as used
|
|
|
|
poke_file "$TEST_IMG" "$(($rb_offset+8))" "\x00\x01"
|
|
|
|
# Redirect new data cluster onto refcount block
|
|
|
|
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x02\x00\x00"
|
|
|
|
_check_test_img
|
2014-05-25 01:24:58 +04:00
|
|
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
2013-10-11 16:02:11 +04:00
|
|
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
|
2014-05-25 01:24:58 +04:00
|
|
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
2013-08-30 16:34:31 +04:00
|
|
|
|
|
|
|
# Try to fix it
|
|
|
|
_check_test_img -r all
|
|
|
|
|
|
|
|
# The corrupt bit should be cleared
|
2014-05-25 01:24:58 +04:00
|
|
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
2013-08-30 16:34:31 +04:00
|
|
|
|
|
|
|
# Look if it's really really fixed
|
2013-10-11 16:02:11 +04:00
|
|
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
|
2014-05-25 01:24:58 +04:00
|
|
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
2013-10-11 16:02:11 +04:00
|
|
|
|
|
|
|
echo
|
|
|
|
echo "=== Testing cluster data reference into inactive L2 table ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 1 0 512" | _filter_qemu_io
|
|
|
|
$QEMU_IMG snapshot -c foo "$TEST_IMG"
|
|
|
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 2 0 512" | _filter_qemu_io
|
|
|
|
# The inactive L2 table remains at its old offset
|
|
|
|
poke_file "$TEST_IMG" "$l2_offset_after_snapshot" \
|
|
|
|
"\x80\x00\x00\x00\x00\x04\x00\x00"
|
|
|
|
_check_test_img
|
2014-05-25 01:24:58 +04:00
|
|
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
2013-10-11 16:02:11 +04:00
|
|
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 3 0 512" | _filter_qemu_io
|
2014-05-25 01:24:58 +04:00
|
|
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
2013-10-11 16:02:11 +04:00
|
|
|
_check_test_img -r all
|
2014-05-25 01:24:58 +04:00
|
|
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
2013-10-11 16:02:11 +04:00
|
|
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 4 0 512" | _filter_qemu_io
|
2014-05-25 01:24:58 +04:00
|
|
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
2013-10-11 16:02:11 +04:00
|
|
|
|
|
|
|
# Check data
|
|
|
|
$QEMU_IO -c "$OPEN_RO" -c "read -P 4 0 512" | _filter_qemu_io
|
|
|
|
$QEMU_IMG snapshot -a foo "$TEST_IMG"
|
|
|
|
_check_test_img
|
|
|
|
$QEMU_IO -c "$OPEN_RO" -c "read -P 1 0 512" | _filter_qemu_io
|
2013-08-30 16:34:31 +04:00
|
|
|
|
2014-03-11 02:44:09 +04:00
|
|
|
echo
|
|
|
|
echo "=== Testing overlap while COW is in flight ==="
|
|
|
|
echo
|
2019-05-16 17:27:49 +03:00
|
|
|
BACKING_IMG=$TEST_IMG.base
|
|
|
|
TEST_IMG=$BACKING_IMG _make_test_img 1G
|
|
|
|
|
|
|
|
$QEMU_IO -c 'write 0k 64k' "$BACKING_IMG" | _filter_qemu_io
|
|
|
|
|
iotests: Specify explicit backing format where sensible
There are many existing qcow2 images that specify a backing file but
no format. This has been the source of CVEs in the past, but has
become more prominent of a problem now that libvirt has switched to
-blockdev. With older -drive, at least the probing was always done by
qemu (so the only risk of a changed format between successive boots of
a guest was if qemu was upgraded and probed differently). But with
newer -blockdev, libvirt must specify a format; if libvirt guesses raw
where the image was formatted, this results in data corruption visible
to the guest; conversely, if libvirt guesses qcow2 where qemu was
using raw, this can result in potential security holes, so modern
libvirt instead refuses to use images without explicit backing format.
The change in libvirt to reject images without explicit backing format
has pointed out that a number of tools have been far too reliant on
probing in the past. It's time to set a better example in our own
iotests of properly setting this parameter.
iotest calls to create, rebase, and convert are all impacted to some
degree. It's a bit annoying that we are inconsistent on command line
- while all of those accept -o backing_file=...,backing_fmt=..., the
shortcuts are different: create and rebase have -b and -F, while
convert has -B but no -F. (amend has no shortcuts, but the previous
patch just deprecated the use of amend to change backing chains).
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200706203954.341758-9-eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2020-07-06 23:39:52 +03:00
|
|
|
_make_test_img -b "$BACKING_IMG" -F $IMGFMT 1G
|
2014-03-11 02:44:09 +04:00
|
|
|
# Write two clusters, the second one enforces creation of an L2 table after
|
|
|
|
# the first data cluster.
|
|
|
|
$QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io
|
2020-03-31 14:43:45 +03:00
|
|
|
# Free the first cluster. This cluster will soon enough be reallocated and
|
2014-03-11 02:44:09 +04:00
|
|
|
# used for COW.
|
2020-03-31 14:43:45 +03:00
|
|
|
poke_file "$TEST_IMG" "$l2_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
|
|
poke_file "$TEST_IMG" "$(($rb_offset+10))" "\x00\x00"
|
2014-03-11 02:44:09 +04:00
|
|
|
# Now, corrupt the image by marking the second L2 table cluster as free.
|
2020-03-31 14:43:45 +03:00
|
|
|
poke_file "$TEST_IMG" "$(($rb_offset+12))" "\x00\x00"
|
2014-03-11 02:44:09 +04:00
|
|
|
# Start a write operation requiring COW on the image stopping it right before
|
|
|
|
# doing the read; then, trigger the corruption prevention by writing anything to
|
|
|
|
# any unallocated cluster, leading to an attempt to overwrite the second L2
|
|
|
|
# table. Finally, resume the COW write and see it fail (but not crash).
|
|
|
|
echo "open -o file.driver=blkdebug $TEST_IMG
|
|
|
|
break cow_read 0
|
|
|
|
aio_write 0k 1k
|
|
|
|
wait_break 0
|
|
|
|
write 64k 64k
|
|
|
|
resume 0" | $QEMU_IO | _filter_qemu_io
|
|
|
|
|
2014-08-08 00:47:54 +04:00
|
|
|
echo
|
|
|
|
echo "=== Testing unallocated image header ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
# Create L1/L2
|
2014-09-05 18:07:19 +04:00
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
2014-08-08 00:47:54 +04:00
|
|
|
poke_file "$TEST_IMG" "$rb_offset" "\x00\x00"
|
2014-09-05 18:07:19 +04:00
|
|
|
$QEMU_IO -c "write 64k 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
|
|
|
|
echo
|
|
|
|
echo "=== Testing unaligned L1 entry ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
# This will be masked with ~(512 - 1) = ~0x1ff, so whether the lower 9 bits are
|
|
|
|
# aligned or not does not matter
|
|
|
|
poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x04\x2a\x00"
|
|
|
|
$QEMU_IO -c "read 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
|
2015-01-19 23:49:04 +03:00
|
|
|
# Test how well zero cluster expansion can cope with this
|
|
|
|
_make_test_img 64M
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x04\x2a\x00"
|
|
|
|
$QEMU_IMG amend -o compat=0.10 "$TEST_IMG"
|
|
|
|
|
2014-09-05 18:07:19 +04:00
|
|
|
echo
|
|
|
|
echo "=== Testing unaligned L2 entry ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x05\x2a\x00"
|
|
|
|
$QEMU_IO -c "read 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
|
2015-01-19 23:49:04 +03:00
|
|
|
echo
|
|
|
|
echo "=== Testing unaligned pre-allocated zero cluster ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x05\x2a\x01"
|
|
|
|
# zero cluster expansion
|
|
|
|
$QEMU_IMG amend -o compat=0.10 "$TEST_IMG"
|
|
|
|
|
2014-09-05 18:07:19 +04:00
|
|
|
echo
|
|
|
|
echo "=== Testing unaligned reftable entry ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\x00\x02\x2a\x00"
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
|
|
|
|
echo
|
|
|
|
echo "=== Testing non-fatal corruption on freeing ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x05\x2a\x00"
|
|
|
|
$QEMU_IO -c "discard 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
|
|
|
|
echo
|
|
|
|
echo "=== Testing read-only corruption report ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x05\x2a\x00"
|
|
|
|
# Should only emit a single error message
|
|
|
|
$QEMU_IO -c "$OPEN_RO" -c "read 0 64k" -c "read 0 64k" | _filter_qemu_io
|
|
|
|
|
|
|
|
echo
|
|
|
|
echo "=== Testing non-fatal and then fatal corruption report ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
$QEMU_IO -c "write 0 128k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x05\x2a\x00"
|
|
|
|
poke_file "$TEST_IMG" "$(($l2_offset+8))" "\x80\x00\x00\x00\x00\x06\x2a\x00"
|
|
|
|
# Should emit two error messages
|
|
|
|
$QEMU_IO -c "discard 0 64k" -c "read 64k 64k" "$TEST_IMG" | _filter_qemu_io
|
2014-08-08 00:47:54 +04:00
|
|
|
|
2017-11-03 17:18:55 +03:00
|
|
|
echo
|
|
|
|
echo "=== Testing empty refcount table ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
2017-11-08 15:13:06 +03:00
|
|
|
# Repair the image
|
|
|
|
_check_test_img -r all
|
2017-11-03 17:18:55 +03:00
|
|
|
|
2017-11-03 17:18:50 +03:00
|
|
|
echo
|
|
|
|
echo "=== Testing empty refcount table with valid L1 and L2 tables ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
|
|
# Since the first data cluster is already allocated this triggers an
|
|
|
|
# allocation with an explicit offset (using qcow2_alloc_clusters_at())
|
|
|
|
# causing a refcount block to be allocated at offset 0
|
|
|
|
$QEMU_IO -c "write 0 128k" "$TEST_IMG" | _filter_qemu_io
|
2017-11-08 15:13:06 +03:00
|
|
|
# Repair the image
|
|
|
|
_check_test_img -r all
|
2017-11-03 17:18:50 +03:00
|
|
|
|
2017-11-03 17:18:51 +03:00
|
|
|
echo
|
|
|
|
echo "=== Testing empty refcount block ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
poke_file "$TEST_IMG" "$rb_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
2017-11-08 15:13:06 +03:00
|
|
|
# Repair the image
|
|
|
|
_check_test_img -r all
|
2017-11-03 17:18:51 +03:00
|
|
|
|
2017-11-03 17:18:52 +03:00
|
|
|
echo
|
|
|
|
echo "=== Testing empty refcount block with compressed write ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
$QEMU_IO -c "write 64k 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
poke_file "$TEST_IMG" "$rb_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
|
|
# The previous write already allocated an L2 table, so now this new
|
|
|
|
# write will try to allocate a compressed data cluster at offset 0.
|
|
|
|
$QEMU_IO -c "write -c 0k 64k" "$TEST_IMG" | _filter_qemu_io
|
2017-11-08 15:13:06 +03:00
|
|
|
# Repair the image
|
|
|
|
_check_test_img -r all
|
2017-11-03 17:18:52 +03:00
|
|
|
|
2017-11-03 17:18:53 +03:00
|
|
|
echo
|
|
|
|
echo "=== Testing zero refcount table size ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
poke_file "$TEST_IMG" "56" "\x00\x00\x00\x00"
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
|
2017-11-08 15:13:06 +03:00
|
|
|
# Repair the image
|
|
|
|
_check_test_img -r all
|
2017-11-03 17:18:53 +03:00
|
|
|
|
2017-11-03 17:18:54 +03:00
|
|
|
echo
|
|
|
|
echo "=== Testing incorrect refcount table offset ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
poke_file "$TEST_IMG" "48" "\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
|
2017-11-10 23:31:07 +03:00
|
|
|
echo
|
|
|
|
echo "=== Testing dirty corrupt image ==="
|
|
|
|
echo
|
|
|
|
|
|
|
|
_make_test_img 64M
|
|
|
|
|
|
|
|
# Let the refblock appear unaligned
|
|
|
|
poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\xff\xff\x2a\x00"
|
|
|
|
# Mark the image dirty, thus forcing an automatic check when opening it
|
|
|
|
poke_file "$TEST_IMG" 72 "\x00\x00\x00\x00\x00\x00\x00\x01"
|
|
|
|
# Open the image (qemu should refuse to do so)
|
|
|
|
$QEMU_IO -c close "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
|
|
|
|
|
|
|
|
echo '--- Repairing ---'
|
|
|
|
|
|
|
|
# The actual repair should have happened (because of the dirty bit),
|
|
|
|
# but some cleanup may have failed (like freeing the old reftable)
|
|
|
|
# because the image was already marked corrupt by that point
|
|
|
|
_check_test_img -r all
|
|
|
|
|
2017-11-10 23:31:08 +03:00
|
|
|
echo
|
|
|
|
echo "=== Writing to an unaligned preallocated zero cluster ==="
|
|
|
|
echo
|
|
|
|
|
|
|
|
_make_test_img 64M
|
|
|
|
|
|
|
|
# Allocate the L2 table
|
|
|
|
$QEMU_IO -c "write 0 64k" -c "discard 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
# Pretend there is a preallocated zero cluster somewhere inside the
|
|
|
|
# image header
|
|
|
|
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x00\x2a\x01"
|
|
|
|
# Let's write to it!
|
|
|
|
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
|
2017-11-10 23:37:59 +03:00
|
|
|
echo '--- Repairing ---'
|
|
|
|
_check_test_img -r all
|
2017-11-10 23:31:08 +03:00
|
|
|
|
2017-11-10 23:31:09 +03:00
|
|
|
echo
|
|
|
|
echo '=== Discarding with an unaligned refblock ==='
|
|
|
|
echo
|
|
|
|
|
|
|
|
_make_test_img 64M
|
|
|
|
|
|
|
|
$QEMU_IO -c "write 0 128k" "$TEST_IMG" | _filter_qemu_io
|
|
|
|
# Make our refblock unaligned
|
|
|
|
poke_file "$TEST_IMG" "$(($rt_offset))" "\x00\x00\x00\x00\x00\x00\x2a\x00"
|
|
|
|
# Now try to discard something that will be submitted as two requests
|
|
|
|
# (main part + tail)
|
|
|
|
$QEMU_IO -c "discard 0 65537" "$TEST_IMG"
|
|
|
|
|
|
|
|
echo '--- Repairing ---'
|
|
|
|
# Fails the first repair because the corruption prevents the check
|
|
|
|
# function from double-checking
|
|
|
|
# (Using -q for the first invocation, because otherwise the
|
|
|
|
# double-check error message appears above the summary for some
|
|
|
|
# reason -- so let's just hide the summary)
|
|
|
|
_check_test_img -q -r all
|
|
|
|
_check_test_img -r all
|
|
|
|
|
2017-11-10 23:31:10 +03:00
|
|
|
echo
|
|
|
|
echo "=== Discarding an out-of-bounds refblock ==="
|
|
|
|
echo
|
|
|
|
|
|
|
|
_make_test_img 64M
|
|
|
|
|
|
|
|
# Pretend there's a refblock really up high
|
|
|
|
poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\xff\xff\xff\x00\x00\x00\x00"
|
|
|
|
# Let's try to shrink the qcow2 image so that the block driver tries
|
|
|
|
# to discard that refblock (and see what happens!)
|
|
|
|
$QEMU_IMG resize --shrink "$TEST_IMG" 32M
|
|
|
|
|
|
|
|
echo '--- Checking and retrying ---'
|
|
|
|
# Image should not be resized
|
|
|
|
_img_info | grep 'virtual size'
|
|
|
|
# But it should pass this check, because the "partial" resize has
|
|
|
|
# already overwritten refblocks past the end
|
|
|
|
_check_test_img -r all
|
|
|
|
# So let's try again
|
|
|
|
$QEMU_IMG resize --shrink "$TEST_IMG" 32M
|
|
|
|
_img_info | grep 'virtual size'
|
|
|
|
|
|
|
|
echo
|
|
|
|
echo "=== Discarding a non-covered in-bounds refblock ==="
|
|
|
|
echo
|
|
|
|
|
2019-11-07 19:36:57 +03:00
|
|
|
_make_test_img -o 'refcount_bits=1' 64M
|
2017-11-10 23:31:10 +03:00
|
|
|
|
|
|
|
# Pretend there's a refblock somewhere where there is no refblock to
|
|
|
|
# cover it (but the covering refblock has a valid index in the
|
|
|
|
# reftable)
|
|
|
|
# Every refblock covers 65536 * 8 * 65536 = 32 GB, so we have to point
|
|
|
|
# to 0x10_0000_0000 (64G) to point to the third refblock
|
|
|
|
poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\x00\x00\x10\x00\x00\x00\x00"
|
|
|
|
$QEMU_IMG resize --shrink "$TEST_IMG" 32M
|
|
|
|
|
|
|
|
echo '--- Checking and retrying ---'
|
|
|
|
# Image should not be resized
|
|
|
|
_img_info | grep 'virtual size'
|
|
|
|
# But it should pass this check, because the "partial" resize has
|
|
|
|
# already overwritten refblocks past the end
|
|
|
|
_check_test_img -r all
|
|
|
|
# So let's try again
|
|
|
|
$QEMU_IMG resize --shrink "$TEST_IMG" 32M
|
|
|
|
_img_info | grep 'virtual size'
|
|
|
|
|
2017-11-10 23:31:11 +03:00
|
|
|
echo
|
|
|
|
echo "=== Discarding a refblock covered by an unaligned refblock ==="
|
|
|
|
echo
|
|
|
|
|
2019-11-07 19:36:57 +03:00
|
|
|
_make_test_img -o 'refcount_bits=1' 64M
|
2017-11-10 23:31:11 +03:00
|
|
|
|
|
|
|
# Same as above
|
|
|
|
poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\x00\x00\x10\x00\x00\x00\x00"
|
|
|
|
# But now we actually "create" an unaligned third refblock
|
|
|
|
poke_file "$TEST_IMG" "$(($rt_offset+16))" "\x00\x00\x00\x00\x00\x00\x02\x00"
|
|
|
|
$QEMU_IMG resize --shrink "$TEST_IMG" 32M
|
|
|
|
|
|
|
|
echo '--- Repairing ---'
|
|
|
|
# Fails the first repair because the corruption prevents the check
|
|
|
|
# function from double-checking
|
|
|
|
# (Using -q for the first invocation, because otherwise the
|
|
|
|
# double-check error message appears above the summary for some
|
|
|
|
# reason -- so let's just hide the summary)
|
|
|
|
_check_test_img -q -r all
|
|
|
|
_check_test_img -r all
|
|
|
|
|
2017-11-06 17:53:45 +03:00
|
|
|
echo
|
|
|
|
echo "=== Testing the QEMU shutdown with a corrupted image ==="
|
|
|
|
echo
|
|
|
|
_make_test_img 64M
|
|
|
|
poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
|
|
echo "{'execute': 'qmp_capabilities'}
|
|
|
|
{'execute': 'human-monitor-command',
|
|
|
|
'arguments': {'command-line': 'qemu-io drive \"write 0 512\"'}}
|
|
|
|
{'execute': 'quit'}" \
|
|
|
|
| $QEMU -qmp stdio -nographic -nodefaults \
|
|
|
|
-drive if=none,node-name=drive,file="$TEST_IMG",driver=qcow2 \
|
|
|
|
| _filter_qmp | _filter_qemu_io
|
|
|
|
|
2018-06-06 22:37:02 +03:00
|
|
|
echo
|
|
|
|
echo "=== Testing incoming inactive corrupted image ==="
|
|
|
|
echo
|
|
|
|
|
|
|
|
_make_test_img 64M
|
|
|
|
# Create an unaligned L1 entry, so qemu will signal a corruption when
|
|
|
|
# reading from the covered area
|
|
|
|
poke_file "$TEST_IMG" "$l1_offset" "\x00\x00\x00\x00\x2a\x2a\x2a\x2a"
|
|
|
|
|
|
|
|
# Inactive images are effectively read-only images, so this should be a
|
|
|
|
# non-fatal corruption (which does not modify the image)
|
|
|
|
echo "{'execute': 'qmp_capabilities'}
|
|
|
|
{'execute': 'human-monitor-command',
|
|
|
|
'arguments': {'command-line': 'qemu-io drive \"read 0 512\"'}}
|
|
|
|
{'execute': 'quit'}" \
|
|
|
|
| $QEMU -qmp stdio -nographic -nodefaults \
|
|
|
|
-blockdev "{'node-name': 'drive',
|
|
|
|
'driver': 'qcow2',
|
|
|
|
'file': {
|
|
|
|
'driver': 'file',
|
|
|
|
'filename': '$TEST_IMG'
|
|
|
|
}}" \
|
|
|
|
-incoming exec:'cat /dev/null' \
|
|
|
|
2>&1 \
|
tests: iotests: drop some stderr line
In my Out-Of-Band test, "check -qcow2 060" fail with this:
--- /home/peterx/git/qemu/tests/qemu-iotests/060.out
+++ /home/peterx/git/qemu/bin/tests/qemu-iotests/060.out.bad
@@ -427,8 +427,8 @@
QMP_VERSION
{"return": {}}
qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1
index: 0); further non-fatal corruption events will be suppressed
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a0
0 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}}
read failed: Input/output error
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a0
0 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}}
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP},
"event": "SHUTDOWN", "data": {"guest": false}}
The order of the event and the in/out error line is swapped. I didn't
dig up the reason, but AFAIU what we want to verify is the event rather
than stderr. Let's drop the stderr line directly for this test.
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20180620073223.31964-5-peterx@redhat.com>
[Commit message touched up]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-06-20 10:32:20 +03:00
|
|
|
| _filter_qmp | _filter_qemu_io | _filter_io_error
|
2018-06-06 22:37:02 +03:00
|
|
|
|
|
|
|
echo
|
|
|
|
# Image should not have been marked corrupt
|
|
|
|
_img_info --format-specific | grep 'corrupt:'
|
|
|
|
|
2013-08-30 16:34:31 +04:00
|
|
|
# success, all done
|
|
|
|
echo "*** done"
|
|
|
|
rm -f $seq.full
|
|
|
|
status=0
|