111a82d14SPhilippe Mathieu-Daudé#!/usr/bin/env bash 29dd003a9SVladimir Sementsov-Ogievskiy# group: rw auto quick 3234764eeSMax Reitz# 4234764eeSMax Reitz# Test case for repairing qcow2 images which cannot be repaired using 5234764eeSMax Reitz# the on-disk refcount structures 6234764eeSMax Reitz# 7234764eeSMax Reitz# Copyright (C) 2014 Red Hat, Inc. 8234764eeSMax Reitz# 9234764eeSMax Reitz# This program is free software; you can redistribute it and/or modify 10234764eeSMax Reitz# it under the terms of the GNU General Public License as published by 11234764eeSMax Reitz# the Free Software Foundation; either version 2 of the License, or 12234764eeSMax Reitz# (at your option) any later version. 13234764eeSMax Reitz# 14234764eeSMax Reitz# This program is distributed in the hope that it will be useful, 15234764eeSMax Reitz# but WITHOUT ANY WARRANTY; without even the implied warranty of 16234764eeSMax Reitz# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17234764eeSMax Reitz# GNU General Public License for more details. 18234764eeSMax Reitz# 19234764eeSMax Reitz# You should have received a copy of the GNU General Public License 20234764eeSMax Reitz# along with this program. If not, see <http://www.gnu.org/licenses/>. 21234764eeSMax Reitz# 22234764eeSMax Reitz 23234764eeSMax Reitz# creator 2442a5009dSJohn Snowowner=hreitz@redhat.com 25234764eeSMax Reitz 26234764eeSMax Reitzseq="$(basename $0)" 27234764eeSMax Reitzecho "QA output created by $seq" 28234764eeSMax Reitz 29234764eeSMax Reitzstatus=1 # failure is the default! 30234764eeSMax Reitz 31234764eeSMax Reitz_cleanup() 32234764eeSMax Reitz{ 33234764eeSMax Reitz _cleanup_test_img 34*9ffd6d64SHanna Reitz if [ -f "$TEST_DIR/qsd.pid" ]; then 35*9ffd6d64SHanna Reitz qsd_pid=$(cat "$TEST_DIR/qsd.pid") 36*9ffd6d64SHanna Reitz kill -KILL "$qsd_pid" 37*9ffd6d64SHanna Reitz fusermount -u "$TEST_DIR/fuse-export" &>/dev/null 38*9ffd6d64SHanna Reitz fi 39*9ffd6d64SHanna Reitz rm -f "$TEST_DIR/fuse-export" 40234764eeSMax Reitz} 41234764eeSMax Reitztrap "_cleanup; exit \$status" 0 1 2 3 15 42234764eeSMax Reitz 43234764eeSMax Reitz# get standard environment, filters and checks 44234764eeSMax Reitz. ./common.rc 45234764eeSMax Reitz. ./common.filter 46*9ffd6d64SHanna Reitz. ./common.qemu 47234764eeSMax Reitz 48e696f335SMax Reitz# This tests qcow2-specific low-level functionality 49234764eeSMax Reitz_supported_fmt qcow2 5057284d2aSMax Reitz_supported_proto file fuse 51234764eeSMax Reitz_supported_os Linux 523be2024aSMax Reitz# This test directly modifies a refblock so it relies on refcount_bits being 16; 533be2024aSMax Reitz# and the low-level modification it performs are not tuned for external data 543be2024aSMax Reitz# files 553be2024aSMax Reitz_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file 56234764eeSMax Reitz 57*9ffd6d64SHanna Reitz# This test either needs sudo -n losetup or FUSE exports to work 58*9ffd6d64SHanna Reitzif sudo -n losetup &>/dev/null; then 59*9ffd6d64SHanna Reitz loopdev=true 60*9ffd6d64SHanna Reitzelse 61*9ffd6d64SHanna Reitz loopdev=false 62*9ffd6d64SHanna Reitz 63*9ffd6d64SHanna Reitz # QSD --export fuse will either yield "Parameter 'id' is missing" 64*9ffd6d64SHanna Reitz # or "Invalid parameter 'fuse'", depending on whether there is 65*9ffd6d64SHanna Reitz # FUSE support or not. 66*9ffd6d64SHanna Reitz error=$($QSD --export fuse 2>&1) 67*9ffd6d64SHanna Reitz if [[ $error = *"'fuse'"* ]]; then 68*9ffd6d64SHanna Reitz _notrun 'Passwordless sudo for losetup or FUSE support required, but' \ 69*9ffd6d64SHanna Reitz 'neither is available' 70*9ffd6d64SHanna Reitz fi 71*9ffd6d64SHanna Reitzfi 72*9ffd6d64SHanna Reitz 73234764eeSMax Reitzecho 74234764eeSMax Reitzecho '=== Repairing an image without any refcount table ===' 75234764eeSMax Reitzecho 76234764eeSMax Reitz 77234764eeSMax Reitz_make_test_img 64M 78234764eeSMax Reitz# just write some data 79234764eeSMax Reitz$QEMU_IO -c 'write -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io 80234764eeSMax Reitz 81234764eeSMax Reitz# refcount_table_offset 82234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x30)) "\x00\x00\x00\x00\x00\x00\x00\x00" 83234764eeSMax Reitz# refcount_table_clusters 84234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x38)) "\x00\x00\x00\x00" 85234764eeSMax Reitz 86234764eeSMax Reitz_check_test_img -r all 87234764eeSMax Reitz 88234764eeSMax Reitz$QEMU_IO -c 'read -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io 89234764eeSMax Reitz 90234764eeSMax Reitzecho 91234764eeSMax Reitzecho '=== Repairing unreferenced data cluster in new refblock area ===' 92234764eeSMax Reitzecho 93234764eeSMax Reitz 94407fb56aSMax Reitz_make_test_img -o 'cluster_size=512' 64M 95234764eeSMax Reitz# Allocate the first 128 kB in the image (first refblock) 96234764eeSMax Reitz$QEMU_IO -c 'write 0 0x1b200' "$TEST_IMG" | _filter_qemu_io 97234764eeSMax Reitz# should be 131072 == 0x20000 98234764eeSMax Reitzstat -c '%s' "$TEST_IMG" 99234764eeSMax Reitz 100234764eeSMax Reitz# Enter a cluster at 128 kB (0x20000) 101234764eeSMax Reitz# XXX: This should be the first free entry in the last L2 table, but we cannot 102234764eeSMax Reitz# be certain 103234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x1ccc8)) "\x80\x00\x00\x00\x00\x02\x00\x00" 104234764eeSMax Reitz 105234764eeSMax Reitz# Fill the cluster 106234764eeSMax Reitztruncate -s $((0x20200)) "$TEST_IMG" 107234764eeSMax Reitz$QEMU_IO -c "open -o driver=raw $TEST_IMG" -c 'write -P 42 128k 512' \ 108234764eeSMax Reitz | _filter_qemu_io 109234764eeSMax Reitz 110234764eeSMax Reitz# The data should now appear at this guest offset 111234764eeSMax Reitz$QEMU_IO -c 'read -P 42 0x1b200 512' "$TEST_IMG" | _filter_qemu_io 112234764eeSMax Reitz 113234764eeSMax Reitz# This cluster is unallocated; fix it 114234764eeSMax Reitz_check_test_img -r all 115234764eeSMax Reitz 116234764eeSMax Reitz# This repair operation must have allocated a new refblock; and that refblock 117234764eeSMax Reitz# should not overlap with the unallocated data cluster. If it does, the data 118234764eeSMax Reitz# will be damaged, so check it. 119234764eeSMax Reitz$QEMU_IO -c 'read -P 42 0x1b200 512' "$TEST_IMG" | _filter_qemu_io 120234764eeSMax Reitz 121234764eeSMax Reitzecho 122234764eeSMax Reitzecho '=== Repairing refblock beyond the image end ===' 123234764eeSMax Reitzecho 124234764eeSMax Reitz 125234764eeSMax Reitzecho 126234764eeSMax Reitzecho '--- Otherwise clean ---' 127234764eeSMax Reitzecho 128234764eeSMax Reitz 129234764eeSMax Reitz_make_test_img 64M 130234764eeSMax Reitz# Normally, qemu doesn't create empty refblocks, so we just have to do it by 131234764eeSMax Reitz# hand 132234764eeSMax Reitz# XXX: This should be the entry for the second refblock 133234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x10008)) "\x00\x00\x00\x00\x00\x10\x00\x00" 134234764eeSMax Reitz# Mark that refblock as used 135234764eeSMax Reitz# XXX: This should be the 17th entry (cluster 16) of the first 136234764eeSMax Reitz# refblock 137234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x20020)) "\x00\x01" 138234764eeSMax Reitz_check_test_img -r all 139234764eeSMax Reitz 140234764eeSMax Reitzecho 141234764eeSMax Reitzecho '--- Refblock is unallocated ---' 142234764eeSMax Reitzecho 143234764eeSMax Reitz 144234764eeSMax Reitz_make_test_img 64M 145234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x10008)) "\x00\x00\x00\x00\x00\x10\x00\x00" 146234764eeSMax Reitz_check_test_img -r all 147234764eeSMax Reitz 148234764eeSMax Reitzecho 149234764eeSMax Reitzecho '--- Signed overflow after the refblock ---' 150234764eeSMax Reitzecho 151234764eeSMax Reitz 152234764eeSMax Reitz_make_test_img 64M 153234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x10008)) "\x7f\xff\xff\xff\xff\xff\x00\x00" 154234764eeSMax Reitz_check_test_img -r all 155234764eeSMax Reitz 156234764eeSMax Reitzecho 157234764eeSMax Reitzecho '--- Unsigned overflow after the refblock ---' 158234764eeSMax Reitzecho 159234764eeSMax Reitz 160234764eeSMax Reitz_make_test_img 64M 161234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x10008)) "\xff\xff\xff\xff\xff\xff\x00\x00" 162234764eeSMax Reitz_check_test_img -r all 163234764eeSMax Reitz 164*9ffd6d64SHanna Reitzecho 165*9ffd6d64SHanna Reitzecho '=== Check rebuilt reftable location ===' 166*9ffd6d64SHanna Reitz 167*9ffd6d64SHanna Reitz# In an earlier version of the refcount rebuild algorithm, the 168*9ffd6d64SHanna Reitz# reftable was generally placed at the image end (unless something was 169*9ffd6d64SHanna Reitz# allocated in the area covered by the refblock right before the image 170*9ffd6d64SHanna Reitz# file end, then we would try to place the reftable in that refblock). 171*9ffd6d64SHanna Reitz# This was later changed so the reftable would be placed in the 172*9ffd6d64SHanna Reitz# earliest possible location. Test this. 173*9ffd6d64SHanna Reitz 174*9ffd6d64SHanna Reitzecho 175*9ffd6d64SHanna Reitzecho '--- Does the image size increase? ---' 176*9ffd6d64SHanna Reitzecho 177*9ffd6d64SHanna Reitz 178*9ffd6d64SHanna Reitz# First test: Just create some image, write some data to it, and 179*9ffd6d64SHanna Reitz# resize it so there is free space at the end of the image (enough 180*9ffd6d64SHanna Reitz# that it spans at least one full refblock, which for cluster_size=512 181*9ffd6d64SHanna Reitz# images, spans 128k). With the old algorithm, the reftable would 182*9ffd6d64SHanna Reitz# have then been placed at the end of the image file, but with the new 183*9ffd6d64SHanna Reitz# one, it will be put in that free space. 184*9ffd6d64SHanna Reitz# We want to check whether the size of the image file increases due to 185*9ffd6d64SHanna Reitz# rebuilding the refcount structures (it should not). 186*9ffd6d64SHanna Reitz 187*9ffd6d64SHanna Reitz_make_test_img -o 'cluster_size=512' 1M 188*9ffd6d64SHanna Reitz# Write something 189*9ffd6d64SHanna Reitz$QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io 190*9ffd6d64SHanna Reitz 191*9ffd6d64SHanna Reitz# Add free space 192*9ffd6d64SHanna Reitzfile_len=$(stat -c '%s' "$TEST_IMG") 193*9ffd6d64SHanna Reitztruncate -s $((file_len + 256 * 1024)) "$TEST_IMG" 194*9ffd6d64SHanna Reitz 195*9ffd6d64SHanna Reitz# Corrupt the image by saying the image header was not allocated 196*9ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$TEST_IMG" 48 8) 197*9ffd6d64SHanna Reitzrb_offset=$(peek_file_be "$TEST_IMG" $rt_offset 8) 198*9ffd6d64SHanna Reitzpoke_file "$TEST_IMG" $rb_offset "\x00\x00" 199*9ffd6d64SHanna Reitz 200*9ffd6d64SHanna Reitz# Check whether rebuilding the refcount structures increases the image 201*9ffd6d64SHanna Reitz# file size 202*9ffd6d64SHanna Reitzfile_len=$(stat -c '%s' "$TEST_IMG") 203*9ffd6d64SHanna Reitzecho 204*9ffd6d64SHanna Reitz# The only leaks there can be are the old refcount structures that are 205*9ffd6d64SHanna Reitz# leaked during rebuilding, no need to clutter the output with them 206*9ffd6d64SHanna Reitz_check_test_img -r all | grep -v '^Repairing cluster.*refcount=1 reference=0' 207*9ffd6d64SHanna Reitzecho 208*9ffd6d64SHanna Reitzpost_repair_file_len=$(stat -c '%s' "$TEST_IMG") 209*9ffd6d64SHanna Reitz 210*9ffd6d64SHanna Reitzif [[ $file_len -eq $post_repair_file_len ]]; then 211*9ffd6d64SHanna Reitz echo 'OK: Image size did not change' 212*9ffd6d64SHanna Reitzelse 213*9ffd6d64SHanna Reitz echo 'ERROR: Image size differs' \ 214*9ffd6d64SHanna Reitz "($file_len before, $post_repair_file_len after)" 215*9ffd6d64SHanna Reitzfi 216*9ffd6d64SHanna Reitz 217*9ffd6d64SHanna Reitzecho 218*9ffd6d64SHanna Reitzecho '--- Will the reftable occupy a hole specifically left for it? ---' 219*9ffd6d64SHanna Reitzecho 220*9ffd6d64SHanna Reitz 221*9ffd6d64SHanna Reitz# Note: With cluster_size=512, every refblock covers 128k. 222*9ffd6d64SHanna Reitz# The reftable covers 8M per reftable cluster. 223*9ffd6d64SHanna Reitz 224*9ffd6d64SHanna Reitz# Create an image that requires two reftable clusters (just because 225*9ffd6d64SHanna Reitz# this is more interesting than a single-clustered reftable). 226*9ffd6d64SHanna Reitz_make_test_img -o 'cluster_size=512' 9M 227*9ffd6d64SHanna Reitz$QEMU_IO -c 'write 0 8M' "$TEST_IMG" | _filter_qemu_io 228*9ffd6d64SHanna Reitz 229*9ffd6d64SHanna Reitz# Writing 8M will have resized the reftable. Unfortunately, doing so 230*9ffd6d64SHanna Reitz# will leave holes in the file, so we need to fill them up so we can 231*9ffd6d64SHanna Reitz# be sure the whole file is allocated. Do that by writing 232*9ffd6d64SHanna Reitz# consecutively smaller chunks starting from 8 MB, until the file 233*9ffd6d64SHanna Reitz# length increases even with a chunk size of 512. Then we must have 234*9ffd6d64SHanna Reitz# filled all holes. 235*9ffd6d64SHanna Reitzofs=$((8 * 1024 * 1024)) 236*9ffd6d64SHanna Reitzblock_len=$((16 * 1024)) 237*9ffd6d64SHanna Reitzwhile [[ $block_len -ge 512 ]]; do 238*9ffd6d64SHanna Reitz file_len=$(stat -c '%s' "$TEST_IMG") 239*9ffd6d64SHanna Reitz while [[ $(stat -c '%s' "$TEST_IMG") -eq $file_len ]]; do 240*9ffd6d64SHanna Reitz # Do not include this in the reference output, it does not 241*9ffd6d64SHanna Reitz # really matter which qemu-io calls we do here exactly 242*9ffd6d64SHanna Reitz $QEMU_IO -c "write $ofs $block_len" "$TEST_IMG" >/dev/null 243*9ffd6d64SHanna Reitz ofs=$((ofs + block_len)) 244*9ffd6d64SHanna Reitz done 245*9ffd6d64SHanna Reitz block_len=$((block_len / 2)) 246*9ffd6d64SHanna Reitzdone 247*9ffd6d64SHanna Reitz 248*9ffd6d64SHanna Reitz# Fill up to 9M (do not include this in the reference output either, 249*9ffd6d64SHanna Reitz# $ofs is random for all we know) 250*9ffd6d64SHanna Reitz$QEMU_IO -c "write $ofs $((9 * 1024 * 1024 - ofs))" "$TEST_IMG" >/dev/null 251*9ffd6d64SHanna Reitz 252*9ffd6d64SHanna Reitz# Make space as follows: 253*9ffd6d64SHanna Reitz# - For the first refblock: Right at the beginning of the image (this 254*9ffd6d64SHanna Reitz# refblock is placed in the first place possible), 255*9ffd6d64SHanna Reitz# - For the reftable somewhere soon afterwards, still near the 256*9ffd6d64SHanna Reitz# beginning of the image (i.e. covered by the first refblock); the 257*9ffd6d64SHanna Reitz# reftable too is placed in the first place possible, but only after 258*9ffd6d64SHanna Reitz# all refblocks have been placed) 259*9ffd6d64SHanna Reitz# No space is needed for the other refblocks, because no refblock is 260*9ffd6d64SHanna Reitz# put before the space it covers. In this test case, we do not mind 261*9ffd6d64SHanna Reitz# if they are placed at the image file's end. 262*9ffd6d64SHanna Reitz 263*9ffd6d64SHanna Reitz# Before we make that space, we have to find out the host offset of 264*9ffd6d64SHanna Reitz# the area that belonged to the two data clusters at guest offset 4k, 265*9ffd6d64SHanna Reitz# because we expect the reftable to be placed there, and we will have 266*9ffd6d64SHanna Reitz# to verify that it is. 267*9ffd6d64SHanna Reitz 268*9ffd6d64SHanna Reitzl1_offset=$(peek_file_be "$TEST_IMG" 40 8) 269*9ffd6d64SHanna Reitzl2_offset=$(peek_file_be "$TEST_IMG" $l1_offset 8) 270*9ffd6d64SHanna Reitzl2_offset=$((l2_offset & 0x00fffffffffffe00)) 271*9ffd6d64SHanna Reitzdata_4k_offset=$(peek_file_be "$TEST_IMG" \ 272*9ffd6d64SHanna Reitz $((l2_offset + 4096 / 512 * 8)) 8) 273*9ffd6d64SHanna Reitzdata_4k_offset=$((data_4k_offset & 0x00fffffffffffe00)) 274*9ffd6d64SHanna Reitz 275*9ffd6d64SHanna Reitz$QEMU_IO -c "discard 0 512" -c "discard 4k 1k" "$TEST_IMG" | _filter_qemu_io 276*9ffd6d64SHanna Reitz 277*9ffd6d64SHanna Reitz# Corrupt the image by saying the image header was not allocated 278*9ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$TEST_IMG" 48 8) 279*9ffd6d64SHanna Reitzrb_offset=$(peek_file_be "$TEST_IMG" $rt_offset 8) 280*9ffd6d64SHanna Reitzpoke_file "$TEST_IMG" $rb_offset "\x00\x00" 281*9ffd6d64SHanna Reitz 282*9ffd6d64SHanna Reitzecho 283*9ffd6d64SHanna Reitz# The only leaks there can be are the old refcount structures that are 284*9ffd6d64SHanna Reitz# leaked during rebuilding, no need to clutter the output with them 285*9ffd6d64SHanna Reitz_check_test_img -r all | grep -v '^Repairing cluster.*refcount=1 reference=0' 286*9ffd6d64SHanna Reitzecho 287*9ffd6d64SHanna Reitz 288*9ffd6d64SHanna Reitz# Check whether the reftable was put where we expected 289*9ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$TEST_IMG" 48 8) 290*9ffd6d64SHanna Reitzif [[ $rt_offset -eq $data_4k_offset ]]; then 291*9ffd6d64SHanna Reitz echo 'OK: Reftable is where we expect it' 292*9ffd6d64SHanna Reitzelse 293*9ffd6d64SHanna Reitz echo "ERROR: Reftable is at $rt_offset, but was expected at $data_4k_offset" 294*9ffd6d64SHanna Reitzfi 295*9ffd6d64SHanna Reitz 296*9ffd6d64SHanna Reitzecho 297*9ffd6d64SHanna Reitzecho '--- Rebuilding refcount structures on block devices ---' 298*9ffd6d64SHanna Reitzecho 299*9ffd6d64SHanna Reitz 300*9ffd6d64SHanna Reitz# A block device cannot really grow, at least not during qemu-img 301*9ffd6d64SHanna Reitz# check. As mentioned in the above cases, rebuilding the refcount 302*9ffd6d64SHanna Reitz# structure may lead to new refcount structures being written after 303*9ffd6d64SHanna Reitz# the end of the image, and in the past that happened even if there 304*9ffd6d64SHanna Reitz# was more than sufficient space in the image. Such post-EOF writes 305*9ffd6d64SHanna Reitz# will not work on block devices, so test that the new algorithm 306*9ffd6d64SHanna Reitz# avoids it. 307*9ffd6d64SHanna Reitz 308*9ffd6d64SHanna Reitz# If we have passwordless sudo and losetup, we can use those to create 309*9ffd6d64SHanna Reitz# a block device. Otherwise, we can resort to qemu's FUSE export to 310*9ffd6d64SHanna Reitz# create a file that isn't growable, which effectively tests the same 311*9ffd6d64SHanna Reitz# thing. 312*9ffd6d64SHanna Reitz 313*9ffd6d64SHanna Reitz_cleanup_test_img 314*9ffd6d64SHanna Reitztruncate -s $((64 * 1024 * 1024)) "$TEST_IMG" 315*9ffd6d64SHanna Reitz 316*9ffd6d64SHanna Reitzif $loopdev; then 317*9ffd6d64SHanna Reitz export_mp=$(sudo -n losetup --show -f "$TEST_IMG") 318*9ffd6d64SHanna Reitz export_mp_driver=host_device 319*9ffd6d64SHanna Reitz sudo -n chmod go+rw "$export_mp" 320*9ffd6d64SHanna Reitzelse 321*9ffd6d64SHanna Reitz # Create non-growable FUSE export that is a bit like an empty 322*9ffd6d64SHanna Reitz # block device 323*9ffd6d64SHanna Reitz export_mp="$TEST_DIR/fuse-export" 324*9ffd6d64SHanna Reitz export_mp_driver=file 325*9ffd6d64SHanna Reitz touch "$export_mp" 326*9ffd6d64SHanna Reitz 327*9ffd6d64SHanna Reitz $QSD \ 328*9ffd6d64SHanna Reitz --blockdev file,node-name=export-node,filename="$TEST_IMG" \ 329*9ffd6d64SHanna Reitz --export fuse,id=fuse-export,node-name=export-node,mountpoint="$export_mp",writable=on,growable=off \ 330*9ffd6d64SHanna Reitz --pidfile "$TEST_DIR/qsd.pid" \ 331*9ffd6d64SHanna Reitz --daemonize 332*9ffd6d64SHanna Reitzfi 333*9ffd6d64SHanna Reitz 334*9ffd6d64SHanna Reitz# Now create a qcow2 image on the device -- unfortunately, qemu-img 335*9ffd6d64SHanna Reitz# create force-creates the file, so we have to resort to the 336*9ffd6d64SHanna Reitz# blockdev-create job. 337*9ffd6d64SHanna Reitz_launch_qemu \ 338*9ffd6d64SHanna Reitz --blockdev $export_mp_driver,node-name=file,filename="$export_mp" 339*9ffd6d64SHanna Reitz 340*9ffd6d64SHanna Reitz_send_qemu_cmd \ 341*9ffd6d64SHanna Reitz $QEMU_HANDLE \ 342*9ffd6d64SHanna Reitz '{ "execute": "qmp_capabilities" }' \ 343*9ffd6d64SHanna Reitz 'return' 344*9ffd6d64SHanna Reitz 345*9ffd6d64SHanna Reitz# Small cluster size again, so the image needs multiple refblocks 346*9ffd6d64SHanna Reitz_send_qemu_cmd \ 347*9ffd6d64SHanna Reitz $QEMU_HANDLE \ 348*9ffd6d64SHanna Reitz '{ "execute": "blockdev-create", 349*9ffd6d64SHanna Reitz "arguments": { 350*9ffd6d64SHanna Reitz "job-id": "create", 351*9ffd6d64SHanna Reitz "options": { 352*9ffd6d64SHanna Reitz "driver": "qcow2", 353*9ffd6d64SHanna Reitz "file": "file", 354*9ffd6d64SHanna Reitz "size": '$((64 * 1024 * 1024))', 355*9ffd6d64SHanna Reitz "cluster-size": 512 356*9ffd6d64SHanna Reitz } } }' \ 357*9ffd6d64SHanna Reitz '"concluded"' 358*9ffd6d64SHanna Reitz 359*9ffd6d64SHanna Reitz_send_qemu_cmd \ 360*9ffd6d64SHanna Reitz $QEMU_HANDLE \ 361*9ffd6d64SHanna Reitz '{ "execute": "job-dismiss", "arguments": { "id": "create" } }' \ 362*9ffd6d64SHanna Reitz 'return' 363*9ffd6d64SHanna Reitz 364*9ffd6d64SHanna Reitz_send_qemu_cmd \ 365*9ffd6d64SHanna Reitz $QEMU_HANDLE \ 366*9ffd6d64SHanna Reitz '{ "execute": "quit" }' \ 367*9ffd6d64SHanna Reitz 'return' 368*9ffd6d64SHanna Reitz 369*9ffd6d64SHanna Reitzwait=y _cleanup_qemu 370*9ffd6d64SHanna Reitzecho 371*9ffd6d64SHanna Reitz 372*9ffd6d64SHanna Reitz# Write some data 373*9ffd6d64SHanna Reitz$QEMU_IO -c 'write 0 64k' "$export_mp" | _filter_qemu_io 374*9ffd6d64SHanna Reitz 375*9ffd6d64SHanna Reitz# Corrupt the image by saying the image header was not allocated 376*9ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$export_mp" 48 8) 377*9ffd6d64SHanna Reitzrb_offset=$(peek_file_be "$export_mp" $rt_offset 8) 378*9ffd6d64SHanna Reitzpoke_file "$export_mp" $rb_offset "\x00\x00" 379*9ffd6d64SHanna Reitz 380*9ffd6d64SHanna Reitz# Repairing such a simple case should just work 381*9ffd6d64SHanna Reitz# (We used to put the reftable at the end of the image file, which can 382*9ffd6d64SHanna Reitz# never work for non-growable devices.) 383*9ffd6d64SHanna Reitzecho 384*9ffd6d64SHanna ReitzTEST_IMG="$export_mp" _check_test_img -r all \ 385*9ffd6d64SHanna Reitz | grep -v '^Repairing cluster.*refcount=1 reference=0' 386*9ffd6d64SHanna Reitz 387*9ffd6d64SHanna Reitzif $loopdev; then 388*9ffd6d64SHanna Reitz sudo -n losetup -d "$export_mp" 389*9ffd6d64SHanna Reitzelse 390*9ffd6d64SHanna Reitz qsd_pid=$(cat "$TEST_DIR/qsd.pid") 391*9ffd6d64SHanna Reitz kill -TERM "$qsd_pid" 392*9ffd6d64SHanna Reitz # Wait for process to exit (cannot `wait` because the QSD is daemonized) 393*9ffd6d64SHanna Reitz while [ -f "$TEST_DIR/qsd.pid" ]; do 394*9ffd6d64SHanna Reitz true 395*9ffd6d64SHanna Reitz done 396*9ffd6d64SHanna Reitzfi 397*9ffd6d64SHanna Reitz 398234764eeSMax Reitz# success, all done 399234764eeSMax Reitzecho '*** done' 400234764eeSMax Reitzrm -f $seq.full 401234764eeSMax Reitzstatus=0 402