xref: /openbmc/qemu/tests/qemu-iotests/108 (revision 348a0740afc5b313599533eb69bbb2b95d2f1bba)
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
639ffd6d64SHanna Reitz    # QSD --export fuse will either yield "Parameter 'id' is missing"
649ffd6d64SHanna Reitz    # or "Invalid parameter 'fuse'", depending on whether there is
659ffd6d64SHanna Reitz    # FUSE support or not.
669ffd6d64SHanna Reitz    error=$($QSD --export fuse 2>&1)
679ffd6d64SHanna Reitz    if [[ $error = *"'fuse'"* ]]; then
689ffd6d64SHanna Reitz        _notrun 'Passwordless sudo for losetup or FUSE support required, but' \
699ffd6d64SHanna Reitz                'neither is available'
709ffd6d64SHanna Reitz    fi
719ffd6d64SHanna Reitzfi
729ffd6d64SHanna 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
1649ffd6d64SHanna Reitzecho
1659ffd6d64SHanna Reitzecho '=== Check rebuilt reftable location ==='
1669ffd6d64SHanna Reitz
1679ffd6d64SHanna Reitz# In an earlier version of the refcount rebuild algorithm, the
1689ffd6d64SHanna Reitz# reftable was generally placed at the image end (unless something was
1699ffd6d64SHanna Reitz# allocated in the area covered by the refblock right before the image
1709ffd6d64SHanna Reitz# file end, then we would try to place the reftable in that refblock).
1719ffd6d64SHanna Reitz# This was later changed so the reftable would be placed in the
1729ffd6d64SHanna Reitz# earliest possible location.  Test this.
1739ffd6d64SHanna Reitz
1749ffd6d64SHanna Reitzecho
1759ffd6d64SHanna Reitzecho '--- Does the image size increase? ---'
1769ffd6d64SHanna Reitzecho
1779ffd6d64SHanna Reitz
1789ffd6d64SHanna Reitz# First test: Just create some image, write some data to it, and
1799ffd6d64SHanna Reitz# resize it so there is free space at the end of the image (enough
1809ffd6d64SHanna Reitz# that it spans at least one full refblock, which for cluster_size=512
1819ffd6d64SHanna Reitz# images, spans 128k).  With the old algorithm, the reftable would
1829ffd6d64SHanna Reitz# have then been placed at the end of the image file, but with the new
1839ffd6d64SHanna Reitz# one, it will be put in that free space.
1849ffd6d64SHanna Reitz# We want to check whether the size of the image file increases due to
1859ffd6d64SHanna Reitz# rebuilding the refcount structures (it should not).
1869ffd6d64SHanna Reitz
1879ffd6d64SHanna Reitz_make_test_img -o 'cluster_size=512' 1M
1889ffd6d64SHanna Reitz# Write something
1899ffd6d64SHanna Reitz$QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io
1909ffd6d64SHanna Reitz
1919ffd6d64SHanna Reitz# Add free space
1929ffd6d64SHanna Reitzfile_len=$(stat -c '%s' "$TEST_IMG")
1939ffd6d64SHanna Reitztruncate -s $((file_len + 256 * 1024)) "$TEST_IMG"
1949ffd6d64SHanna Reitz
1959ffd6d64SHanna Reitz# Corrupt the image by saying the image header was not allocated
1969ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$TEST_IMG" 48 8)
1979ffd6d64SHanna Reitzrb_offset=$(peek_file_be "$TEST_IMG" $rt_offset 8)
1989ffd6d64SHanna Reitzpoke_file "$TEST_IMG" $rb_offset "\x00\x00"
1999ffd6d64SHanna Reitz
2009ffd6d64SHanna Reitz# Check whether rebuilding the refcount structures increases the image
2019ffd6d64SHanna Reitz# file size
2029ffd6d64SHanna Reitzfile_len=$(stat -c '%s' "$TEST_IMG")
2039ffd6d64SHanna Reitzecho
2049ffd6d64SHanna Reitz# The only leaks there can be are the old refcount structures that are
2059ffd6d64SHanna Reitz# leaked during rebuilding, no need to clutter the output with them
2069ffd6d64SHanna Reitz_check_test_img -r all | grep -v '^Repairing cluster.*refcount=1 reference=0'
2079ffd6d64SHanna Reitzecho
2089ffd6d64SHanna Reitzpost_repair_file_len=$(stat -c '%s' "$TEST_IMG")
2099ffd6d64SHanna Reitz
2109ffd6d64SHanna Reitzif [[ $file_len -eq $post_repair_file_len ]]; then
2119ffd6d64SHanna Reitz    echo 'OK: Image size did not change'
2129ffd6d64SHanna Reitzelse
2139ffd6d64SHanna Reitz    echo 'ERROR: Image size differs' \
2149ffd6d64SHanna Reitz        "($file_len before, $post_repair_file_len after)"
2159ffd6d64SHanna Reitzfi
2169ffd6d64SHanna Reitz
2179ffd6d64SHanna Reitzecho
2189ffd6d64SHanna Reitzecho '--- Will the reftable occupy a hole specifically left for it?  ---'
2199ffd6d64SHanna Reitzecho
2209ffd6d64SHanna Reitz
2219ffd6d64SHanna Reitz# Note: With cluster_size=512, every refblock covers 128k.
2229ffd6d64SHanna Reitz# The reftable covers 8M per reftable cluster.
2239ffd6d64SHanna Reitz
2249ffd6d64SHanna Reitz# Create an image that requires two reftable clusters (just because
2259ffd6d64SHanna Reitz# this is more interesting than a single-clustered reftable).
2269ffd6d64SHanna Reitz_make_test_img -o 'cluster_size=512' 9M
2279ffd6d64SHanna Reitz$QEMU_IO -c 'write 0 8M' "$TEST_IMG" | _filter_qemu_io
2289ffd6d64SHanna Reitz
2299ffd6d64SHanna Reitz# Writing 8M will have resized the reftable.  Unfortunately, doing so
2309ffd6d64SHanna Reitz# will leave holes in the file, so we need to fill them up so we can
2319ffd6d64SHanna Reitz# be sure the whole file is allocated.  Do that by writing
2329ffd6d64SHanna Reitz# consecutively smaller chunks starting from 8 MB, until the file
2339ffd6d64SHanna Reitz# length increases even with a chunk size of 512.  Then we must have
2349ffd6d64SHanna Reitz# filled all holes.
2359ffd6d64SHanna Reitzofs=$((8 * 1024 * 1024))
2369ffd6d64SHanna Reitzblock_len=$((16 * 1024))
2379ffd6d64SHanna Reitzwhile [[ $block_len -ge 512 ]]; do
2389ffd6d64SHanna Reitz    file_len=$(stat -c '%s' "$TEST_IMG")
2399ffd6d64SHanna Reitz    while [[ $(stat -c '%s' "$TEST_IMG") -eq $file_len ]]; do
2409ffd6d64SHanna Reitz        # Do not include this in the reference output, it does not
2419ffd6d64SHanna Reitz        # really matter which qemu-io calls we do here exactly
2429ffd6d64SHanna Reitz        $QEMU_IO -c "write $ofs $block_len" "$TEST_IMG" >/dev/null
2439ffd6d64SHanna Reitz        ofs=$((ofs + block_len))
2449ffd6d64SHanna Reitz    done
2459ffd6d64SHanna Reitz    block_len=$((block_len / 2))
2469ffd6d64SHanna Reitzdone
2479ffd6d64SHanna Reitz
2489ffd6d64SHanna Reitz# Fill up to 9M (do not include this in the reference output either,
2499ffd6d64SHanna Reitz# $ofs is random for all we know)
2509ffd6d64SHanna Reitz$QEMU_IO -c "write $ofs $((9 * 1024 * 1024 - ofs))" "$TEST_IMG" >/dev/null
2519ffd6d64SHanna Reitz
2529ffd6d64SHanna Reitz# Make space as follows:
2539ffd6d64SHanna Reitz# - For the first refblock: Right at the beginning of the image (this
2549ffd6d64SHanna Reitz#   refblock is placed in the first place possible),
2559ffd6d64SHanna Reitz# - For the reftable somewhere soon afterwards, still near the
2569ffd6d64SHanna Reitz#   beginning of the image (i.e. covered by the first refblock); the
2579ffd6d64SHanna Reitz#   reftable too is placed in the first place possible, but only after
2589ffd6d64SHanna Reitz#   all refblocks have been placed)
2599ffd6d64SHanna Reitz# No space is needed for the other refblocks, because no refblock is
2609ffd6d64SHanna Reitz# put before the space it covers.  In this test case, we do not mind
2619ffd6d64SHanna Reitz# if they are placed at the image file's end.
2629ffd6d64SHanna Reitz
2639ffd6d64SHanna Reitz# Before we make that space, we have to find out the host offset of
2649ffd6d64SHanna Reitz# the area that belonged to the two data clusters at guest offset 4k,
2659ffd6d64SHanna Reitz# because we expect the reftable to be placed there, and we will have
2669ffd6d64SHanna Reitz# to verify that it is.
2679ffd6d64SHanna Reitz
2689ffd6d64SHanna Reitzl1_offset=$(peek_file_be "$TEST_IMG" 40 8)
2699ffd6d64SHanna Reitzl2_offset=$(peek_file_be "$TEST_IMG" $l1_offset 8)
2709ffd6d64SHanna Reitzl2_offset=$((l2_offset & 0x00fffffffffffe00))
2719ffd6d64SHanna Reitzdata_4k_offset=$(peek_file_be "$TEST_IMG" \
2729ffd6d64SHanna Reitz                 $((l2_offset + 4096 / 512 * 8)) 8)
2739ffd6d64SHanna Reitzdata_4k_offset=$((data_4k_offset & 0x00fffffffffffe00))
2749ffd6d64SHanna Reitz
2759ffd6d64SHanna Reitz$QEMU_IO -c "discard 0 512" -c "discard 4k 1k" "$TEST_IMG" | _filter_qemu_io
2769ffd6d64SHanna Reitz
2779ffd6d64SHanna Reitz# Corrupt the image by saying the image header was not allocated
2789ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$TEST_IMG" 48 8)
2799ffd6d64SHanna Reitzrb_offset=$(peek_file_be "$TEST_IMG" $rt_offset 8)
2809ffd6d64SHanna Reitzpoke_file "$TEST_IMG" $rb_offset "\x00\x00"
2819ffd6d64SHanna Reitz
2829ffd6d64SHanna Reitzecho
2839ffd6d64SHanna Reitz# The only leaks there can be are the old refcount structures that are
2849ffd6d64SHanna Reitz# leaked during rebuilding, no need to clutter the output with them
2859ffd6d64SHanna Reitz_check_test_img -r all | grep -v '^Repairing cluster.*refcount=1 reference=0'
2869ffd6d64SHanna Reitzecho
2879ffd6d64SHanna Reitz
2889ffd6d64SHanna Reitz# Check whether the reftable was put where we expected
2899ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$TEST_IMG" 48 8)
2909ffd6d64SHanna Reitzif [[ $rt_offset -eq $data_4k_offset ]]; then
2919ffd6d64SHanna Reitz    echo 'OK: Reftable is where we expect it'
2929ffd6d64SHanna Reitzelse
2939ffd6d64SHanna Reitz    echo "ERROR: Reftable is at $rt_offset, but was expected at $data_4k_offset"
2949ffd6d64SHanna Reitzfi
2959ffd6d64SHanna Reitz
2969ffd6d64SHanna Reitzecho
2979ffd6d64SHanna Reitzecho '--- Rebuilding refcount structures on block devices ---'
2989ffd6d64SHanna Reitzecho
2999ffd6d64SHanna Reitz
3009ffd6d64SHanna Reitz# A block device cannot really grow, at least not during qemu-img
3019ffd6d64SHanna Reitz# check.  As mentioned in the above cases, rebuilding the refcount
3029ffd6d64SHanna Reitz# structure may lead to new refcount structures being written after
3039ffd6d64SHanna Reitz# the end of the image, and in the past that happened even if there
3049ffd6d64SHanna Reitz# was more than sufficient space in the image.  Such post-EOF writes
3059ffd6d64SHanna Reitz# will not work on block devices, so test that the new algorithm
3069ffd6d64SHanna Reitz# avoids it.
3079ffd6d64SHanna Reitz
3089ffd6d64SHanna Reitz# If we have passwordless sudo and losetup, we can use those to create
3099ffd6d64SHanna Reitz# a block device.  Otherwise, we can resort to qemu's FUSE export to
3109ffd6d64SHanna Reitz# create a file that isn't growable, which effectively tests the same
3119ffd6d64SHanna Reitz# thing.
3129ffd6d64SHanna Reitz
3139ffd6d64SHanna Reitz_cleanup_test_img
3149ffd6d64SHanna Reitztruncate -s $((64 * 1024 * 1024)) "$TEST_IMG"
3159ffd6d64SHanna Reitz
3169ffd6d64SHanna Reitzif $loopdev; then
3179ffd6d64SHanna Reitz    export_mp=$(sudo -n losetup --show -f "$TEST_IMG")
3189ffd6d64SHanna Reitz    export_mp_driver=host_device
3199ffd6d64SHanna Reitz    sudo -n chmod go+rw "$export_mp"
3209ffd6d64SHanna Reitzelse
3219ffd6d64SHanna Reitz    # Create non-growable FUSE export that is a bit like an empty
3229ffd6d64SHanna Reitz    # block device
3239ffd6d64SHanna Reitz    export_mp="$TEST_DIR/fuse-export"
3249ffd6d64SHanna Reitz    export_mp_driver=file
3259ffd6d64SHanna Reitz    touch "$export_mp"
3269ffd6d64SHanna Reitz
3279ffd6d64SHanna Reitz    $QSD \
3289ffd6d64SHanna Reitz        --blockdev file,node-name=export-node,filename="$TEST_IMG" \
329*348a0740SHanna Reitz        --export fuse,id=fuse-export,node-name=export-node,mountpoint="$export_mp",writable=on,growable=off,allow-other=off \
3309ffd6d64SHanna Reitz        --pidfile "$TEST_DIR/qsd.pid" \
3319ffd6d64SHanna Reitz        --daemonize
3329ffd6d64SHanna Reitzfi
3339ffd6d64SHanna Reitz
3349ffd6d64SHanna Reitz# Now create a qcow2 image on the device -- unfortunately, qemu-img
3359ffd6d64SHanna Reitz# create force-creates the file, so we have to resort to the
3369ffd6d64SHanna Reitz# blockdev-create job.
3379ffd6d64SHanna Reitz_launch_qemu \
3389ffd6d64SHanna Reitz    --blockdev $export_mp_driver,node-name=file,filename="$export_mp"
3399ffd6d64SHanna Reitz
3409ffd6d64SHanna Reitz_send_qemu_cmd \
3419ffd6d64SHanna Reitz    $QEMU_HANDLE \
3429ffd6d64SHanna Reitz    '{ "execute": "qmp_capabilities" }' \
3439ffd6d64SHanna Reitz    'return'
3449ffd6d64SHanna Reitz
3459ffd6d64SHanna Reitz# Small cluster size again, so the image needs multiple refblocks
3469ffd6d64SHanna Reitz_send_qemu_cmd \
3479ffd6d64SHanna Reitz    $QEMU_HANDLE \
3489ffd6d64SHanna Reitz    '{ "execute": "blockdev-create",
3499ffd6d64SHanna Reitz       "arguments": {
3509ffd6d64SHanna Reitz           "job-id": "create",
3519ffd6d64SHanna Reitz           "options": {
3529ffd6d64SHanna Reitz               "driver": "qcow2",
3539ffd6d64SHanna Reitz               "file": "file",
3549ffd6d64SHanna Reitz               "size": '$((64 * 1024 * 1024))',
3559ffd6d64SHanna Reitz               "cluster-size": 512
3569ffd6d64SHanna Reitz           } } }' \
3579ffd6d64SHanna Reitz    '"concluded"'
3589ffd6d64SHanna Reitz
3599ffd6d64SHanna Reitz_send_qemu_cmd \
3609ffd6d64SHanna Reitz    $QEMU_HANDLE \
3619ffd6d64SHanna Reitz    '{ "execute": "job-dismiss", "arguments": { "id": "create" } }' \
3629ffd6d64SHanna Reitz    'return'
3639ffd6d64SHanna Reitz
3649ffd6d64SHanna Reitz_send_qemu_cmd \
3659ffd6d64SHanna Reitz    $QEMU_HANDLE \
3669ffd6d64SHanna Reitz    '{ "execute": "quit" }' \
3679ffd6d64SHanna Reitz    'return'
3689ffd6d64SHanna Reitz
3699ffd6d64SHanna Reitzwait=y _cleanup_qemu
3709ffd6d64SHanna Reitzecho
3719ffd6d64SHanna Reitz
3729ffd6d64SHanna Reitz# Write some data
3739ffd6d64SHanna Reitz$QEMU_IO -c 'write 0 64k' "$export_mp" | _filter_qemu_io
3749ffd6d64SHanna Reitz
3759ffd6d64SHanna Reitz# Corrupt the image by saying the image header was not allocated
3769ffd6d64SHanna Reitzrt_offset=$(peek_file_be "$export_mp" 48 8)
3779ffd6d64SHanna Reitzrb_offset=$(peek_file_be "$export_mp" $rt_offset 8)
3789ffd6d64SHanna Reitzpoke_file "$export_mp" $rb_offset "\x00\x00"
3799ffd6d64SHanna Reitz
3809ffd6d64SHanna Reitz# Repairing such a simple case should just work
3819ffd6d64SHanna Reitz# (We used to put the reftable at the end of the image file, which can
3829ffd6d64SHanna Reitz# never work for non-growable devices.)
3839ffd6d64SHanna Reitzecho
3849ffd6d64SHanna ReitzTEST_IMG="$export_mp" _check_test_img -r all \
3859ffd6d64SHanna Reitz    | grep -v '^Repairing cluster.*refcount=1 reference=0'
3869ffd6d64SHanna Reitz
3879ffd6d64SHanna Reitzif $loopdev; then
3889ffd6d64SHanna Reitz    sudo -n losetup -d "$export_mp"
3899ffd6d64SHanna Reitzelse
3909ffd6d64SHanna Reitz    qsd_pid=$(cat "$TEST_DIR/qsd.pid")
3919ffd6d64SHanna Reitz    kill -TERM "$qsd_pid"
3929ffd6d64SHanna Reitz    # Wait for process to exit (cannot `wait` because the QSD is daemonized)
3939ffd6d64SHanna Reitz    while [ -f "$TEST_DIR/qsd.pid" ]; do
3949ffd6d64SHanna Reitz        true
3959ffd6d64SHanna Reitz    done
3969ffd6d64SHanna Reitzfi
3979ffd6d64SHanna Reitz
398234764eeSMax Reitz# success, all done
399234764eeSMax Reitzecho '*** done'
400234764eeSMax Reitzrm -f $seq.full
401234764eeSMax Reitzstatus=0
402