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