xref: /openbmc/qemu/tests/qemu-iotests/108 (revision 92529251)
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
349ffd6d64SHanna Reitz    if [ -f "$TEST_DIR/qsd.pid" ]; then
359ffd6d64SHanna Reitz        qsd_pid=$(cat "$TEST_DIR/qsd.pid")
369ffd6d64SHanna Reitz        kill -KILL "$qsd_pid"
379ffd6d64SHanna Reitz        fusermount -u "$TEST_DIR/fuse-export" &>/dev/null
389ffd6d64SHanna Reitz    fi
399ffd6d64SHanna 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
469ffd6d64SHanna 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
579ffd6d64SHanna Reitz# This test either needs sudo -n losetup or FUSE exports to work
589ffd6d64SHanna Reitzif sudo -n losetup &>/dev/null; then
599ffd6d64SHanna Reitz    loopdev=true
609ffd6d64SHanna Reitzelse
619ffd6d64SHanna Reitz    loopdev=false
629ffd6d64SHanna Reitz
63*92529251SJohn Snow    # Check for usable FUSE in the host environment:
64*92529251SJohn Snow    if test ! -c "/dev/fuse"; then
65*92529251SJohn Snow        _notrun 'No passwordless sudo nor usable /dev/fuse'
66*92529251SJohn Snow    fi
67*92529251SJohn Snow
689ffd6d64SHanna Reitz    # QSD --export fuse will either yield "Parameter 'id' is missing"
699ffd6d64SHanna Reitz    # or "Invalid parameter 'fuse'", depending on whether there is
709ffd6d64SHanna Reitz    # FUSE support or not.
719ffd6d64SHanna Reitz    error=$($QSD --export fuse 2>&1)
729ffd6d64SHanna Reitz    if [[ $error = *"'fuse'"* ]]; then
739ffd6d64SHanna Reitz        _notrun 'Passwordless sudo for losetup or FUSE support required, but' \
749ffd6d64SHanna Reitz                'neither is available'
759ffd6d64SHanna Reitz    fi
769ffd6d64SHanna Reitzfi
779ffd6d64SHanna Reitz
78234764eeSMax Reitzecho
79234764eeSMax Reitzecho '=== Repairing an image without any refcount table ==='
80234764eeSMax Reitzecho
81234764eeSMax Reitz
82234764eeSMax Reitz_make_test_img 64M
83234764eeSMax Reitz# just write some data
84234764eeSMax Reitz$QEMU_IO -c 'write -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io
85234764eeSMax Reitz
86234764eeSMax Reitz# refcount_table_offset
87234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x30)) "\x00\x00\x00\x00\x00\x00\x00\x00"
88234764eeSMax Reitz# refcount_table_clusters
89234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x38)) "\x00\x00\x00\x00"
90234764eeSMax Reitz
91234764eeSMax Reitz_check_test_img -r all
92234764eeSMax Reitz
93234764eeSMax Reitz$QEMU_IO -c 'read -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io
94234764eeSMax Reitz
95234764eeSMax Reitzecho
96234764eeSMax Reitzecho '=== Repairing unreferenced data cluster in new refblock area ==='
97234764eeSMax Reitzecho
98234764eeSMax Reitz
99407fb56aSMax Reitz_make_test_img -o 'cluster_size=512' 64M
100234764eeSMax Reitz# Allocate the first 128 kB in the image (first refblock)
101234764eeSMax Reitz$QEMU_IO -c 'write 0 0x1b200' "$TEST_IMG" | _filter_qemu_io
102234764eeSMax Reitz# should be 131072 == 0x20000
103234764eeSMax Reitzstat -c '%s' "$TEST_IMG"
104234764eeSMax Reitz
105234764eeSMax Reitz# Enter a cluster at 128 kB (0x20000)
106234764eeSMax Reitz# XXX: This should be the first free entry in the last L2 table, but we cannot
107234764eeSMax Reitz# be certain
108234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x1ccc8)) "\x80\x00\x00\x00\x00\x02\x00\x00"
109234764eeSMax Reitz
110234764eeSMax Reitz# Fill the cluster
111234764eeSMax Reitztruncate -s $((0x20200)) "$TEST_IMG"
112234764eeSMax Reitz$QEMU_IO -c "open -o driver=raw $TEST_IMG" -c 'write -P 42 128k 512' \
113234764eeSMax Reitz    | _filter_qemu_io
114234764eeSMax Reitz
115234764eeSMax Reitz# The data should now appear at this guest offset
116234764eeSMax Reitz$QEMU_IO -c 'read -P 42 0x1b200 512' "$TEST_IMG" | _filter_qemu_io
117234764eeSMax Reitz
118234764eeSMax Reitz# This cluster is unallocated; fix it
119234764eeSMax Reitz_check_test_img -r all
120234764eeSMax Reitz
121234764eeSMax Reitz# This repair operation must have allocated a new refblock; and that refblock
122234764eeSMax Reitz# should not overlap with the unallocated data cluster. If it does, the data
123234764eeSMax Reitz# will be damaged, so check it.
124234764eeSMax Reitz$QEMU_IO -c 'read -P 42 0x1b200 512' "$TEST_IMG" | _filter_qemu_io
125234764eeSMax Reitz
126234764eeSMax Reitzecho
127234764eeSMax Reitzecho '=== Repairing refblock beyond the image end ==='
128234764eeSMax Reitzecho
129234764eeSMax Reitz
130234764eeSMax Reitzecho
131234764eeSMax Reitzecho '--- Otherwise clean ---'
132234764eeSMax Reitzecho
133234764eeSMax Reitz
134234764eeSMax Reitz_make_test_img 64M
135234764eeSMax Reitz# Normally, qemu doesn't create empty refblocks, so we just have to do it by
136234764eeSMax Reitz# hand
137234764eeSMax Reitz# XXX: This should be the entry for the second refblock
138234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x10008)) "\x00\x00\x00\x00\x00\x10\x00\x00"
139234764eeSMax Reitz# Mark that refblock as used
140234764eeSMax Reitz# XXX: This should be the 17th entry (cluster 16) of the first
141234764eeSMax Reitz# refblock
142234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x20020)) "\x00\x01"
143234764eeSMax Reitz_check_test_img -r all
144234764eeSMax Reitz
145234764eeSMax Reitzecho
146234764eeSMax Reitzecho '--- Refblock is unallocated ---'
147234764eeSMax Reitzecho
148234764eeSMax Reitz
149234764eeSMax Reitz_make_test_img 64M
150234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x10008)) "\x00\x00\x00\x00\x00\x10\x00\x00"
151234764eeSMax Reitz_check_test_img -r all
152234764eeSMax Reitz
153234764eeSMax Reitzecho
154234764eeSMax Reitzecho '--- Signed overflow after the refblock ---'
155234764eeSMax Reitzecho
156234764eeSMax Reitz
157234764eeSMax Reitz_make_test_img 64M
158234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x10008)) "\x7f\xff\xff\xff\xff\xff\x00\x00"
159234764eeSMax Reitz_check_test_img -r all
160234764eeSMax Reitz
161234764eeSMax Reitzecho
162234764eeSMax Reitzecho '--- Unsigned overflow after the refblock ---'
163234764eeSMax Reitzecho
164234764eeSMax Reitz
165234764eeSMax Reitz_make_test_img 64M
166234764eeSMax Reitzpoke_file "$TEST_IMG" $((0x10008)) "\xff\xff\xff\xff\xff\xff\x00\x00"
167234764eeSMax Reitz_check_test_img -r all
168234764eeSMax Reitz
1699ffd6d64SHanna Reitzecho
1709ffd6d64SHanna Reitzecho '=== Check rebuilt reftable location ==='
1719ffd6d64SHanna Reitz
1729ffd6d64SHanna Reitz# In an earlier version of the refcount rebuild algorithm, the
1739ffd6d64SHanna Reitz# reftable was generally placed at the image end (unless something was
1749ffd6d64SHanna Reitz# allocated in the area covered by the refblock right before the image
1759ffd6d64SHanna Reitz# file end, then we would try to place the reftable in that refblock).
1769ffd6d64SHanna Reitz# This was later changed so the reftable would be placed in the
1779ffd6d64SHanna Reitz# earliest possible location.  Test this.
1789ffd6d64SHanna Reitz
1799ffd6d64SHanna Reitzecho
1809ffd6d64SHanna Reitzecho '--- Does the image size increase? ---'
1819ffd6d64SHanna Reitzecho
1829ffd6d64SHanna Reitz
1839ffd6d64SHanna Reitz# First test: Just create some image, write some data to it, and
1849ffd6d64SHanna Reitz# resize it so there is free space at the end of the image (enough
1859ffd6d64SHanna Reitz# that it spans at least one full refblock, which for cluster_size=512
1869ffd6d64SHanna Reitz# images, spans 128k).  With the old algorithm, the reftable would
1879ffd6d64SHanna Reitz# have then been placed at the end of the image file, but with the new
1889ffd6d64SHanna Reitz# one, it will be put in that free space.
1899ffd6d64SHanna Reitz# We want to check whether the size of the image file increases due to
1909ffd6d64SHanna Reitz# rebuilding the refcount structures (it should not).
1919ffd6d64SHanna Reitz
1929ffd6d64SHanna Reitz_make_test_img -o 'cluster_size=512' 1M
1939ffd6d64SHanna Reitz# Write something
1949ffd6d64SHanna Reitz$QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io
1959ffd6d64SHanna Reitz
1969ffd6d64SHanna Reitz# Add free space
1979ffd6d64SHanna Reitzfile_len=$(stat -c '%s' "$TEST_IMG")
1989ffd6d64SHanna Reitztruncate -s $((file_len + 256 * 1024)) "$TEST_IMG"
1999ffd6d64SHanna Reitz
2009ffd6d64SHanna Reitz# Corrupt the image by saying the image header was not allocated
2019ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$TEST_IMG" 48 8)
2029ffd6d64SHanna Reitzrb_offset=$(peek_file_be "$TEST_IMG" $rt_offset 8)
2039ffd6d64SHanna Reitzpoke_file "$TEST_IMG" $rb_offset "\x00\x00"
2049ffd6d64SHanna Reitz
2059ffd6d64SHanna Reitz# Check whether rebuilding the refcount structures increases the image
2069ffd6d64SHanna Reitz# file size
2079ffd6d64SHanna Reitzfile_len=$(stat -c '%s' "$TEST_IMG")
2089ffd6d64SHanna Reitzecho
2099ffd6d64SHanna Reitz# The only leaks there can be are the old refcount structures that are
2109ffd6d64SHanna Reitz# leaked during rebuilding, no need to clutter the output with them
2119ffd6d64SHanna Reitz_check_test_img -r all | grep -v '^Repairing cluster.*refcount=1 reference=0'
2129ffd6d64SHanna Reitzecho
2139ffd6d64SHanna Reitzpost_repair_file_len=$(stat -c '%s' "$TEST_IMG")
2149ffd6d64SHanna Reitz
2159ffd6d64SHanna Reitzif [[ $file_len -eq $post_repair_file_len ]]; then
2169ffd6d64SHanna Reitz    echo 'OK: Image size did not change'
2179ffd6d64SHanna Reitzelse
2189ffd6d64SHanna Reitz    echo 'ERROR: Image size differs' \
2199ffd6d64SHanna Reitz        "($file_len before, $post_repair_file_len after)"
2209ffd6d64SHanna Reitzfi
2219ffd6d64SHanna Reitz
2229ffd6d64SHanna Reitzecho
2239ffd6d64SHanna Reitzecho '--- Will the reftable occupy a hole specifically left for it?  ---'
2249ffd6d64SHanna Reitzecho
2259ffd6d64SHanna Reitz
2269ffd6d64SHanna Reitz# Note: With cluster_size=512, every refblock covers 128k.
2279ffd6d64SHanna Reitz# The reftable covers 8M per reftable cluster.
2289ffd6d64SHanna Reitz
2299ffd6d64SHanna Reitz# Create an image that requires two reftable clusters (just because
2309ffd6d64SHanna Reitz# this is more interesting than a single-clustered reftable).
2319ffd6d64SHanna Reitz_make_test_img -o 'cluster_size=512' 9M
2329ffd6d64SHanna Reitz$QEMU_IO -c 'write 0 8M' "$TEST_IMG" | _filter_qemu_io
2339ffd6d64SHanna Reitz
2349ffd6d64SHanna Reitz# Writing 8M will have resized the reftable.  Unfortunately, doing so
2359ffd6d64SHanna Reitz# will leave holes in the file, so we need to fill them up so we can
2369ffd6d64SHanna Reitz# be sure the whole file is allocated.  Do that by writing
2379ffd6d64SHanna Reitz# consecutively smaller chunks starting from 8 MB, until the file
2389ffd6d64SHanna Reitz# length increases even with a chunk size of 512.  Then we must have
2399ffd6d64SHanna Reitz# filled all holes.
2409ffd6d64SHanna Reitzofs=$((8 * 1024 * 1024))
2419ffd6d64SHanna Reitzblock_len=$((16 * 1024))
2429ffd6d64SHanna Reitzwhile [[ $block_len -ge 512 ]]; do
2439ffd6d64SHanna Reitz    file_len=$(stat -c '%s' "$TEST_IMG")
2449ffd6d64SHanna Reitz    while [[ $(stat -c '%s' "$TEST_IMG") -eq $file_len ]]; do
2459ffd6d64SHanna Reitz        # Do not include this in the reference output, it does not
2469ffd6d64SHanna Reitz        # really matter which qemu-io calls we do here exactly
2479ffd6d64SHanna Reitz        $QEMU_IO -c "write $ofs $block_len" "$TEST_IMG" >/dev/null
2489ffd6d64SHanna Reitz        ofs=$((ofs + block_len))
2499ffd6d64SHanna Reitz    done
2509ffd6d64SHanna Reitz    block_len=$((block_len / 2))
2519ffd6d64SHanna Reitzdone
2529ffd6d64SHanna Reitz
2539ffd6d64SHanna Reitz# Fill up to 9M (do not include this in the reference output either,
2549ffd6d64SHanna Reitz# $ofs is random for all we know)
2559ffd6d64SHanna Reitz$QEMU_IO -c "write $ofs $((9 * 1024 * 1024 - ofs))" "$TEST_IMG" >/dev/null
2569ffd6d64SHanna Reitz
2579ffd6d64SHanna Reitz# Make space as follows:
2589ffd6d64SHanna Reitz# - For the first refblock: Right at the beginning of the image (this
2599ffd6d64SHanna Reitz#   refblock is placed in the first place possible),
2609ffd6d64SHanna Reitz# - For the reftable somewhere soon afterwards, still near the
2619ffd6d64SHanna Reitz#   beginning of the image (i.e. covered by the first refblock); the
2629ffd6d64SHanna Reitz#   reftable too is placed in the first place possible, but only after
2639ffd6d64SHanna Reitz#   all refblocks have been placed)
2649ffd6d64SHanna Reitz# No space is needed for the other refblocks, because no refblock is
2659ffd6d64SHanna Reitz# put before the space it covers.  In this test case, we do not mind
2669ffd6d64SHanna Reitz# if they are placed at the image file's end.
2679ffd6d64SHanna Reitz
2689ffd6d64SHanna Reitz# Before we make that space, we have to find out the host offset of
2699ffd6d64SHanna Reitz# the area that belonged to the two data clusters at guest offset 4k,
2709ffd6d64SHanna Reitz# because we expect the reftable to be placed there, and we will have
2719ffd6d64SHanna Reitz# to verify that it is.
2729ffd6d64SHanna Reitz
2739ffd6d64SHanna Reitzl1_offset=$(peek_file_be "$TEST_IMG" 40 8)
2749ffd6d64SHanna Reitzl2_offset=$(peek_file_be "$TEST_IMG" $l1_offset 8)
2759ffd6d64SHanna Reitzl2_offset=$((l2_offset & 0x00fffffffffffe00))
2769ffd6d64SHanna Reitzdata_4k_offset=$(peek_file_be "$TEST_IMG" \
2779ffd6d64SHanna Reitz                 $((l2_offset + 4096 / 512 * 8)) 8)
2789ffd6d64SHanna Reitzdata_4k_offset=$((data_4k_offset & 0x00fffffffffffe00))
2799ffd6d64SHanna Reitz
2809ffd6d64SHanna Reitz$QEMU_IO -c "discard 0 512" -c "discard 4k 1k" "$TEST_IMG" | _filter_qemu_io
2819ffd6d64SHanna Reitz
2829ffd6d64SHanna Reitz# Corrupt the image by saying the image header was not allocated
2839ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$TEST_IMG" 48 8)
2849ffd6d64SHanna Reitzrb_offset=$(peek_file_be "$TEST_IMG" $rt_offset 8)
2859ffd6d64SHanna Reitzpoke_file "$TEST_IMG" $rb_offset "\x00\x00"
2869ffd6d64SHanna Reitz
2879ffd6d64SHanna Reitzecho
2889ffd6d64SHanna Reitz# The only leaks there can be are the old refcount structures that are
2899ffd6d64SHanna Reitz# leaked during rebuilding, no need to clutter the output with them
2909ffd6d64SHanna Reitz_check_test_img -r all | grep -v '^Repairing cluster.*refcount=1 reference=0'
2919ffd6d64SHanna Reitzecho
2929ffd6d64SHanna Reitz
2939ffd6d64SHanna Reitz# Check whether the reftable was put where we expected
2949ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$TEST_IMG" 48 8)
2959ffd6d64SHanna Reitzif [[ $rt_offset -eq $data_4k_offset ]]; then
2969ffd6d64SHanna Reitz    echo 'OK: Reftable is where we expect it'
2979ffd6d64SHanna Reitzelse
2989ffd6d64SHanna Reitz    echo "ERROR: Reftable is at $rt_offset, but was expected at $data_4k_offset"
2999ffd6d64SHanna Reitzfi
3009ffd6d64SHanna Reitz
3019ffd6d64SHanna Reitzecho
3029ffd6d64SHanna Reitzecho '--- Rebuilding refcount structures on block devices ---'
3039ffd6d64SHanna Reitzecho
3049ffd6d64SHanna Reitz
3059ffd6d64SHanna Reitz# A block device cannot really grow, at least not during qemu-img
3069ffd6d64SHanna Reitz# check.  As mentioned in the above cases, rebuilding the refcount
3079ffd6d64SHanna Reitz# structure may lead to new refcount structures being written after
3089ffd6d64SHanna Reitz# the end of the image, and in the past that happened even if there
3099ffd6d64SHanna Reitz# was more than sufficient space in the image.  Such post-EOF writes
3109ffd6d64SHanna Reitz# will not work on block devices, so test that the new algorithm
3119ffd6d64SHanna Reitz# avoids it.
3129ffd6d64SHanna Reitz
3139ffd6d64SHanna Reitz# If we have passwordless sudo and losetup, we can use those to create
3149ffd6d64SHanna Reitz# a block device.  Otherwise, we can resort to qemu's FUSE export to
3159ffd6d64SHanna Reitz# create a file that isn't growable, which effectively tests the same
3169ffd6d64SHanna Reitz# thing.
3179ffd6d64SHanna Reitz
3189ffd6d64SHanna Reitz_cleanup_test_img
3199ffd6d64SHanna Reitztruncate -s $((64 * 1024 * 1024)) "$TEST_IMG"
3209ffd6d64SHanna Reitz
3219ffd6d64SHanna Reitzif $loopdev; then
3229ffd6d64SHanna Reitz    export_mp=$(sudo -n losetup --show -f "$TEST_IMG")
3239ffd6d64SHanna Reitz    export_mp_driver=host_device
3249ffd6d64SHanna Reitz    sudo -n chmod go+rw "$export_mp"
3259ffd6d64SHanna Reitzelse
3269ffd6d64SHanna Reitz    # Create non-growable FUSE export that is a bit like an empty
3279ffd6d64SHanna Reitz    # block device
3289ffd6d64SHanna Reitz    export_mp="$TEST_DIR/fuse-export"
3299ffd6d64SHanna Reitz    export_mp_driver=file
3309ffd6d64SHanna Reitz    touch "$export_mp"
3319ffd6d64SHanna Reitz
3329ffd6d64SHanna Reitz    $QSD \
3339ffd6d64SHanna Reitz        --blockdev file,node-name=export-node,filename="$TEST_IMG" \
334348a0740SHanna Reitz        --export fuse,id=fuse-export,node-name=export-node,mountpoint="$export_mp",writable=on,growable=off,allow-other=off \
3359ffd6d64SHanna Reitz        --pidfile "$TEST_DIR/qsd.pid" \
3369ffd6d64SHanna Reitz        --daemonize
3379ffd6d64SHanna Reitzfi
3389ffd6d64SHanna Reitz
3399ffd6d64SHanna Reitz# Now create a qcow2 image on the device -- unfortunately, qemu-img
3409ffd6d64SHanna Reitz# create force-creates the file, so we have to resort to the
3419ffd6d64SHanna Reitz# blockdev-create job.
3429ffd6d64SHanna Reitz_launch_qemu \
3439ffd6d64SHanna Reitz    --blockdev $export_mp_driver,node-name=file,filename="$export_mp"
3449ffd6d64SHanna Reitz
3459ffd6d64SHanna Reitz_send_qemu_cmd \
3469ffd6d64SHanna Reitz    $QEMU_HANDLE \
3479ffd6d64SHanna Reitz    '{ "execute": "qmp_capabilities" }' \
3489ffd6d64SHanna Reitz    'return'
3499ffd6d64SHanna Reitz
3509ffd6d64SHanna Reitz# Small cluster size again, so the image needs multiple refblocks
3519ffd6d64SHanna Reitz_send_qemu_cmd \
3529ffd6d64SHanna Reitz    $QEMU_HANDLE \
3539ffd6d64SHanna Reitz    '{ "execute": "blockdev-create",
3549ffd6d64SHanna Reitz       "arguments": {
3559ffd6d64SHanna Reitz           "job-id": "create",
3569ffd6d64SHanna Reitz           "options": {
3579ffd6d64SHanna Reitz               "driver": "qcow2",
3589ffd6d64SHanna Reitz               "file": "file",
3599ffd6d64SHanna Reitz               "size": '$((64 * 1024 * 1024))',
3609ffd6d64SHanna Reitz               "cluster-size": 512
3619ffd6d64SHanna Reitz           } } }' \
3629ffd6d64SHanna Reitz    '"concluded"'
3639ffd6d64SHanna Reitz
3649ffd6d64SHanna Reitz_send_qemu_cmd \
3659ffd6d64SHanna Reitz    $QEMU_HANDLE \
3669ffd6d64SHanna Reitz    '{ "execute": "job-dismiss", "arguments": { "id": "create" } }' \
3679ffd6d64SHanna Reitz    'return'
3689ffd6d64SHanna Reitz
3699ffd6d64SHanna Reitz_send_qemu_cmd \
3709ffd6d64SHanna Reitz    $QEMU_HANDLE \
3719ffd6d64SHanna Reitz    '{ "execute": "quit" }' \
3729ffd6d64SHanna Reitz    'return'
3739ffd6d64SHanna Reitz
3749ffd6d64SHanna Reitzwait=y _cleanup_qemu
3759ffd6d64SHanna Reitzecho
3769ffd6d64SHanna Reitz
3779ffd6d64SHanna Reitz# Write some data
3789ffd6d64SHanna Reitz$QEMU_IO -c 'write 0 64k' "$export_mp" | _filter_qemu_io
3799ffd6d64SHanna Reitz
3809ffd6d64SHanna Reitz# Corrupt the image by saying the image header was not allocated
3819ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$export_mp" 48 8)
3829ffd6d64SHanna Reitzrb_offset=$(peek_file_be "$export_mp" $rt_offset 8)
3839ffd6d64SHanna Reitzpoke_file "$export_mp" $rb_offset "\x00\x00"
3849ffd6d64SHanna Reitz
3859ffd6d64SHanna Reitz# Repairing such a simple case should just work
3869ffd6d64SHanna Reitz# (We used to put the reftable at the end of the image file, which can
3879ffd6d64SHanna Reitz# never work for non-growable devices.)
3889ffd6d64SHanna Reitzecho
3899ffd6d64SHanna ReitzTEST_IMG="$export_mp" _check_test_img -r all \
3909ffd6d64SHanna Reitz    | grep -v '^Repairing cluster.*refcount=1 reference=0'
3919ffd6d64SHanna Reitz
3929ffd6d64SHanna Reitzif $loopdev; then
3939ffd6d64SHanna Reitz    sudo -n losetup -d "$export_mp"
3949ffd6d64SHanna Reitzelse
3959ffd6d64SHanna Reitz    qsd_pid=$(cat "$TEST_DIR/qsd.pid")
3969ffd6d64SHanna Reitz    kill -TERM "$qsd_pid"
3979ffd6d64SHanna Reitz    # Wait for process to exit (cannot `wait` because the QSD is daemonized)
3989ffd6d64SHanna Reitz    while [ -f "$TEST_DIR/qsd.pid" ]; do
3999ffd6d64SHanna Reitz        true
4009ffd6d64SHanna Reitz    done
4019ffd6d64SHanna Reitzfi
4029ffd6d64SHanna Reitz
403234764eeSMax Reitz# success, all done
404234764eeSMax Reitzecho '*** done'
405234764eeSMax Reitzrm -f $seq.full
406234764eeSMax Reitzstatus=0
407