xref: /openbmc/qemu/tests/qemu-iotests/214 (revision 74163add)
111a82d14SPhilippe Mathieu-Daudé#!/usr/bin/env bash
29dd003a9SVladimir Sementsov-Ogievskiy# group: rw auto
36cba5377SMax Reitz#
46cba5377SMax Reitz# Test qcow2 image compression
56cba5377SMax Reitz#
66cba5377SMax Reitz# Copyright (C) 2018 Igalia, S.L.
76cba5377SMax Reitz# Author: Alberto Garcia <berto@igalia.com>
86cba5377SMax Reitz#
96cba5377SMax Reitz# This program is free software; you can redistribute it and/or modify
106cba5377SMax Reitz# it under the terms of the GNU General Public License as published by
116cba5377SMax Reitz# the Free Software Foundation; either version 2 of the License, or
126cba5377SMax Reitz# (at your option) any later version.
136cba5377SMax Reitz#
146cba5377SMax Reitz# This program is distributed in the hope that it will be useful,
156cba5377SMax Reitz# but WITHOUT ANY WARRANTY; without even the implied warranty of
166cba5377SMax Reitz# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
176cba5377SMax Reitz# GNU General Public License for more details.
186cba5377SMax Reitz#
196cba5377SMax Reitz# You should have received a copy of the GNU General Public License
206cba5377SMax Reitz# along with this program.  If not, see <http://www.gnu.org/licenses/>.
216cba5377SMax Reitz#
226cba5377SMax Reitz
236cba5377SMax Reitzseq=$(basename "$0")
246cba5377SMax Reitzecho "QA output created by $seq"
256cba5377SMax Reitz
266cba5377SMax Reitzstatus=1	# failure is the default!
276cba5377SMax Reitz
286cba5377SMax Reitz_cleanup()
296cba5377SMax Reitz{
306cba5377SMax Reitz    _cleanup_test_img
316cba5377SMax Reitz}
326cba5377SMax Reitztrap "_cleanup; exit \$status" 0 1 2 3 15
336cba5377SMax Reitz
346cba5377SMax Reitz# get standard environment, filters and checks
356cba5377SMax Reitz. ./common.rc
366cba5377SMax Reitz. ./common.filter
376cba5377SMax Reitz
386cba5377SMax Reitz_supported_fmt qcow2
3957284d2aSMax Reitz_supported_proto file fuse
406cba5377SMax Reitz
416cba5377SMax Reitz# Repairing the corrupted image requires qemu-img check to store a
426cba5377SMax Reitz# refcount up to 3, which requires at least two refcount bits.
433be2024aSMax Reitz# External data files do not support compressed clusters.
443be2024aSMax Reitz_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
456cba5377SMax Reitz
466cba5377SMax Reitz
476cba5377SMax Reitzecho
486cba5377SMax Reitzecho "=== Corrupted size field in compressed cluster descriptor ==="
496cba5377SMax Reitzecho
506cba5377SMax Reitz# Create an empty image and fill half of it with compressed data.
516cba5377SMax Reitz# The L2 entries of the two compressed clusters are located at
526cba5377SMax Reitz# 0x800000 and 0x800008, their original values are 0x4008000000a00000
536cba5377SMax Reitz# and 0x4008000000a00802 (5 sectors for compressed data each).
54da87d5f8SVladimir Sementsov-Ogievskiy_make_test_img 8M -o cluster_size=2M,compression_type=zlib
556cba5377SMax Reitz$QEMU_IO -c "write -c -P 0x11 0 2M" -c "write -c -P 0x11 2M 2M" "$TEST_IMG" \
566cba5377SMax Reitz         2>&1 | _filter_qemu_io | _filter_testdir
576cba5377SMax Reitz
586cba5377SMax Reitz# Reduce size of compressed data to 4 sectors: this corrupts the image.
596cba5377SMax Reitzpoke_file "$TEST_IMG" $((0x800000)) "\x40\x06"
606cba5377SMax Reitz$QEMU_IO -c "read  -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
616cba5377SMax Reitz
626cba5377SMax Reitz# 'qemu-img check' however doesn't see anything wrong because it
636cba5377SMax Reitz# doesn't try to decompress the data and the refcounts are consistent.
646cba5377SMax Reitz# TODO: update qemu-img so this can be detected.
656cba5377SMax Reitz_check_test_img
666cba5377SMax Reitz
676cba5377SMax Reitz# Increase size of compressed data to the maximum (8192 sectors).
686cba5377SMax Reitz# This makes QEMU read more data (8192 sectors instead of 5, host
696cba5377SMax Reitz# addresses [0xa00000, 0xdfffff]), but the decompression algorithm
706cba5377SMax Reitz# stops once we have enough to restore the uncompressed cluster, so
716cba5377SMax Reitz# the rest of the data is ignored.
726cba5377SMax Reitzpoke_file "$TEST_IMG" $((0x800000)) "\x7f\xfe"
736cba5377SMax Reitz# Do it also for the second compressed cluster (L2 entry at 0x800008).
746cba5377SMax Reitz# In this case the compressed data would span 3 host clusters
756cba5377SMax Reitz# (host addresses: [0xa00802, 0xe00801])
766cba5377SMax Reitzpoke_file "$TEST_IMG" $((0x800008)) "\x7f\xfe"
776cba5377SMax Reitz
786cba5377SMax Reitz# Here the image is too small so we're asking QEMU to read beyond the
796cba5377SMax Reitz# end of the image.
806cba5377SMax Reitz$QEMU_IO -c "read  -P 0x11  0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
816cba5377SMax Reitz# But if we grow the image we won't be reading beyond its end anymore.
826cba5377SMax Reitz$QEMU_IO -c "write -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
836cba5377SMax Reitz$QEMU_IO -c "read  -P 0x11  0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
846cba5377SMax Reitz
856cba5377SMax Reitz# The refcount data is however wrong because due to the increased size
866cba5377SMax Reitz# of the compressed data it now reaches the following host clusters.
876cba5377SMax Reitz# This can be repaired by qemu-img check by increasing the refcount of
886cba5377SMax Reitz# those clusters.
896cba5377SMax Reitz# TODO: update qemu-img to correct the compressed cluster size instead.
906cba5377SMax Reitz_check_test_img -r all
916cba5377SMax Reitz$QEMU_IO -c "read  -P 0x11  0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
926cba5377SMax Reitz$QEMU_IO -c "read  -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
936cba5377SMax Reitz
9419959445SAndrey Shinkevichecho
9519959445SAndrey Shinkevichecho "=== Write compressed data of multiple clusters ==="
9619959445SAndrey Shinkevichecho
9719959445SAndrey Shinkevichcluster_size=0x10000
9819959445SAndrey Shinkevich_make_test_img 2M -o cluster_size=$cluster_size
9919959445SAndrey Shinkevich
10019959445SAndrey Shinkevichecho "Write uncompressed data:"
10119959445SAndrey Shinkevichlet data_size="8 * $cluster_size"
10219959445SAndrey Shinkevich$QEMU_IO -c "write -P 0xaa 0 $data_size" "$TEST_IMG" \
10319959445SAndrey Shinkevich         2>&1 | _filter_qemu_io | _filter_testdir
10419959445SAndrey ShinkevichsizeA=$($QEMU_IMG info --output=json "$TEST_IMG" |
105*74163addSHanna Reitz        sed -n '/"actual-size":/ s/[^0-9]//gp' |
106*74163addSHanna Reitz        head -n 1)
10719959445SAndrey Shinkevich
10819959445SAndrey Shinkevich_make_test_img 2M -o cluster_size=$cluster_size
10919959445SAndrey Shinkevichecho "Write compressed data:"
11019959445SAndrey Shinkevichlet data_size="3 * $cluster_size + $cluster_size / 2"
11119959445SAndrey Shinkevich# Set compress on. That will align the written data
11219959445SAndrey Shinkevich# by the cluster size and will write them compressed.
11319959445SAndrey ShinkevichQEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT \
11419959445SAndrey Shinkevich$QEMU_IO -c "write -P 0xbb 0 $data_size" --image-opts \
11519959445SAndrey Shinkevich         "driver=compress,file.driver=$IMGFMT,file.file.driver=file,file.file.filename=$TEST_IMG" \
11619959445SAndrey Shinkevich         2>&1 | _filter_qemu_io | _filter_testdir
11719959445SAndrey Shinkevich
11819959445SAndrey Shinkevichlet offset="4 * $cluster_size + $cluster_size / 4"
11919959445SAndrey ShinkevichQEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT \
12019959445SAndrey Shinkevich$QEMU_IO -c "write -P 0xcc $offset $data_size" "json:{\
12119959445SAndrey Shinkevich    'driver': 'compress',
12219959445SAndrey Shinkevich    'file': {'driver': '$IMGFMT',
12319959445SAndrey Shinkevich             'file': {'driver': 'file',
12419959445SAndrey Shinkevich                      'filename': '$TEST_IMG'}}}" | \
12519959445SAndrey Shinkevich                          _filter_qemu_io | _filter_testdir
12619959445SAndrey Shinkevich
12719959445SAndrey ShinkevichsizeB=$($QEMU_IMG info --output=json "$TEST_IMG" |
128*74163addSHanna Reitz        sed -n '/"actual-size":/ s/[^0-9]//gp' |
129*74163addSHanna Reitz        head -n 1)
13019959445SAndrey Shinkevich
13100237589SAlex Bennéeif [ $sizeA -lt $sizeB ]
13219959445SAndrey Shinkevichthen
13300237589SAlex Bennée    echo "Compression ERROR ($sizeA < $sizeB)"
13419959445SAndrey Shinkevichfi
13519959445SAndrey Shinkevich
13619959445SAndrey Shinkevich$QEMU_IMG check --output=json "$TEST_IMG" |
13719959445SAndrey Shinkevich          sed -n 's/,$//; /"compressed-clusters":/ s/^ *//p'
13819959445SAndrey Shinkevich
1396cba5377SMax Reitz# success, all done
1406cba5377SMax Reitzecho '*** done'
1416cba5377SMax Reitzrm -f $seq.full
1426cba5377SMax Reitzstatus=0
143