xref: /openbmc/qemu/tests/qemu-iotests/108 (revision 9ffd6d646d1d5ee9087a8cbf0b7d2f96c5656162)
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