abd3622cc0
L2 entries for compressed clusters have a field that indicates the number of sectors used to store the data in the image. That's however not the size of the compressed data itself, just the number of sectors where that data is located. The actual data size is usually not a multiple of the sector size, and therefore cannot be represented with this field. The way it works is that QEMU reads all the specified sectors and starts decompressing the data until there's enough to recover the original uncompressed cluster. If there are any bytes left that haven't been decompressed they are simply ignored. One consequence of this is that even if the size field is larger than it needs to be QEMU can handle it just fine: it will read more data from disk but it will ignore the extra bytes. This test creates an image with two compressed clusters that use 5 sectors (2.5 KB) each, increases the size field to the maximum (8192 sectors, or 4 MB) and verifies that the data can be read without problems. This test is important because while the decompressed data takes exactly one cluster, the maximum value allowed in the compressed size field is twice the cluster size. So although QEMU won't produce images with such large values we need to make sure that it can handle them. Another effect of increasing the size field is that it can make it include data from the following host cluster(s). In this case 'qemu-img check' will detect that the refcounts are not correct, and we'll need to rebuild them. Additionally, this patch also tests that decreasing the size corrupts the image since the original data can no longer be recovered. In this case QEMU returns an error when trying to read the compressed data, but 'qemu-img check' doesn't see anything wrong if the refcounts are consistent. One possible task for the future is to make 'qemu-img check' verify the sizes of the compressed clusters, by trying to decompress the data and checking that the size stored in the L2 entry is correct. Signed-off-by: Alberto Garcia <berto@igalia.com> Message-id: 20180329120745.11154-1-berto@igalia.com Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Max Reitz <mreitz@redhat.com>
270 lines
12 KiB
Bash
Executable File
270 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Test some qemu-img convert cases
|
|
#
|
|
# Copyright (C) 2015 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=kwolf@redhat.com
|
|
|
|
seq="$(basename $0)"
|
|
echo "QA output created by $seq"
|
|
|
|
here="$PWD"
|
|
status=1 # failure is the default!
|
|
|
|
_cleanup()
|
|
{
|
|
rm -f "$TEST_IMG".[123]
|
|
_cleanup_test_img
|
|
}
|
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
|
|
|
# get standard environment, filters and checks
|
|
. ./common.rc
|
|
. ./common.filter
|
|
|
|
_supported_fmt qcow2
|
|
_supported_proto file
|
|
_supported_os Linux
|
|
|
|
|
|
TEST_IMG="$TEST_IMG".base _make_test_img 64M
|
|
$QEMU_IO -c "write -P 0x11 0 64M" "$TEST_IMG".base 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
|
|
echo
|
|
echo "=== Check allocation status regression with -B ==="
|
|
echo
|
|
|
|
_make_test_img -b "$TEST_IMG".base
|
|
$QEMU_IO -c "write -P 0x22 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
|
|
echo
|
|
echo "=== Check that zero clusters are kept in overlay ==="
|
|
echo
|
|
|
|
_make_test_img -b "$TEST_IMG".base
|
|
|
|
$QEMU_IO -c "write -P 0 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
$QEMU_IO -c "write -z 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
|
|
echo
|
|
echo "=== Concatenate multiple source images ==="
|
|
echo
|
|
|
|
TEST_IMG="$TEST_IMG".1 _make_test_img 4M
|
|
TEST_IMG="$TEST_IMG".2 _make_test_img 4M
|
|
TEST_IMG="$TEST_IMG".3 _make_test_img 4M
|
|
|
|
$QEMU_IO -c "write -P 0x11 0 64k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0x22 0 64k" "$TEST_IMG".2 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0x33 0 64k" "$TEST_IMG".3 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
$QEMU_IMG convert -O $IMGFMT "$TEST_IMG".[123] "$TEST_IMG"
|
|
$QEMU_IMG map "$TEST_IMG" | _filter_qemu_img_map
|
|
$QEMU_IO -c "read -P 0x11 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x22 4M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x33 8M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
$QEMU_IMG convert -c -O $IMGFMT "$TEST_IMG".[123] "$TEST_IMG"
|
|
$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
|
|
$QEMU_IO -c "read -P 0x11 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x22 4M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x33 8M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
# -B can't be combined with concatenation
|
|
$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base "$TEST_IMG".[123] "$TEST_IMG"
|
|
$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base "$TEST_IMG".[123] "$TEST_IMG"
|
|
|
|
|
|
echo
|
|
echo "=== Compression with misaligned allocations and image sizes ==="
|
|
echo
|
|
|
|
TEST_IMG="$TEST_IMG".1 _make_test_img 1023k -o cluster_size=1024
|
|
TEST_IMG="$TEST_IMG".2 _make_test_img 1023k -o cluster_size=1024
|
|
|
|
$QEMU_IO -c "write -P 0x11 16k 16k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0x22 130k 130k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0x33 1022k 1k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0x44 0k 1k" "$TEST_IMG".2 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
$QEMU_IMG convert -c -O $IMGFMT "$TEST_IMG".[12] "$TEST_IMG"
|
|
$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
|
|
$QEMU_IO -c "read -P 0 0k 16k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x11 16k 16k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 32k 98k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x22 130k 130k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 260k 762k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x33 1022k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x44 1023k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 1024k 1022k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
|
|
echo
|
|
echo "=== Corrupted size field in compressed cluster descriptor ==="
|
|
echo
|
|
# Create an empty image and fill half of it with compressed data.
|
|
# The L2 entries of the two compressed clusters are located at
|
|
# 0x800000 and 0x800008, their original values are 0x4008000000a00000
|
|
# and 0x4008000000a00802 (5 sectors for compressed data each).
|
|
_make_test_img 8M -o cluster_size=2M
|
|
$QEMU_IO -c "write -c -P 0x11 0 2M" -c "write -c -P 0x11 2M 2M" "$TEST_IMG" \
|
|
2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
# Reduce size of compressed data to 4 sectors: this corrupts the image.
|
|
poke_file "$TEST_IMG" $((0x800000)) "\x40\x06"
|
|
$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
# 'qemu-img check' however doesn't see anything wrong because it
|
|
# doesn't try to decompress the data and the refcounts are consistent.
|
|
# TODO: update qemu-img so this can be detected.
|
|
_check_test_img
|
|
|
|
# Increase size of compressed data to the maximum (8192 sectors).
|
|
# This makes QEMU read more data (8192 sectors instead of 5, host
|
|
# addresses [0xa00000, 0xdfffff]), but the decompression algorithm
|
|
# stops once we have enough to restore the uncompressed cluster, so
|
|
# the rest of the data is ignored.
|
|
poke_file "$TEST_IMG" $((0x800000)) "\x7f\xfe"
|
|
# Do it also for the second compressed cluster (L2 entry at 0x800008).
|
|
# In this case the compressed data would span 3 host clusters
|
|
# (host addresses: [0xa00802, 0xe00801])
|
|
poke_file "$TEST_IMG" $((0x800008)) "\x7f\xfe"
|
|
|
|
# Here the image is too small so we're asking QEMU to read beyond the
|
|
# end of the image.
|
|
$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
# But if we grow the image we won't be reading beyond its end anymore.
|
|
$QEMU_IO -c "write -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
# The refcount data is however wrong because due to the increased size
|
|
# of the compressed data it now reaches the following host clusters.
|
|
# This can be repaired by qemu-img check by increasing the refcount of
|
|
# those clusters.
|
|
# TODO: update qemu-img to correct the compressed cluster size instead.
|
|
_check_test_img -r all
|
|
$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
echo
|
|
echo "=== Full allocation with -S 0 ==="
|
|
echo
|
|
|
|
# Standalone image
|
|
_make_test_img 64M
|
|
$QEMU_IO -c "write -P 0x22 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write -P 0 3M 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
echo
|
|
echo convert -S 0:
|
|
$QEMU_IMG convert -O $IMGFMT -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 3M 61M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
echo
|
|
echo convert -c -S 0:
|
|
$QEMU_IMG convert -O $IMGFMT -c -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 3M 61M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
# With backing file
|
|
TEST_IMG="$TEST_IMG".base _make_test_img 64M
|
|
$QEMU_IO -c "write -P 0x11 0 32M" "$TEST_IMG".base 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
_make_test_img -b "$TEST_IMG".base 64M
|
|
$QEMU_IO -c "write -P 0x22 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
echo
|
|
echo convert -S 0 with source backing file:
|
|
$QEMU_IMG convert -O $IMGFMT -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
echo
|
|
echo convert -c -S 0 with source backing file:
|
|
$QEMU_IMG convert -O $IMGFMT -c -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
# With keeping the backing file
|
|
echo
|
|
echo convert -S 0 -B ...
|
|
$QEMU_IMG convert -O $IMGFMT -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
echo
|
|
echo convert -c -S 0 -B ...
|
|
$QEMU_IMG convert -O $IMGFMT -c -S 0 "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
|
|
echo
|
|
echo "=== Non-zero -S ==="
|
|
echo
|
|
|
|
_make_test_img 64M -o cluster_size=1k
|
|
$QEMU_IO -c "write -P 0 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write 0 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write 8k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
$QEMU_IO -c "write 17k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
|
for min_sparse in 4k 8k; do
|
|
echo
|
|
echo convert -S $min_sparse
|
|
$QEMU_IMG convert -O $IMGFMT -o cluster_size=1k -S $min_sparse "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
|
|
echo
|
|
echo convert -c -S $min_sparse
|
|
# For compressed images, -S values other than 0 are ignored
|
|
$QEMU_IMG convert -O $IMGFMT -o cluster_size=1k -c -S $min_sparse "$TEST_IMG" "$TEST_IMG".orig
|
|
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
|
|
done
|
|
|
|
# success, all done
|
|
echo '*** done'
|
|
rm -f $seq.full
|
|
status=0
|