xref: /qemu/tests/qemu-iotests/251 (revision 138ca49a)
1#!/usr/bin/env bash
2#
3# Test qemu-img convert --salvage
4#
5# Copyright (C) 2019 Red Hat, Inc.
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19#
20
21# creator
22owner=mreitz@redhat.com
23
24seq=$(basename $0)
25echo "QA output created by $seq"
26
27status=1	# failure is the default!
28
29_cleanup()
30{
31    _cleanup_test_img
32}
33trap "_cleanup; exit \$status" 0 1 2 3 15
34
35# get standard environment, filters and checks
36. ./common.rc
37. ./common.filter
38. ./common.qemu
39
40_supported_fmt generic
41_supported_proto file
42_supported_os Linux
43_unsupported_imgopts "subformat=streamOptimized"
44
45if [ "$IMGOPTSSYNTAX" = "true" ]; then
46    # We use json:{} filenames here, so we cannot work with additional options.
47    _unsupported_fmt $IMGFMT
48else
49    # - With VDI, the output is ordered differently.  Just disable it.
50    # - VHDX has large clusters; because qemu-img convert tries to
51    #   align the requests to the cluster size, the output is ordered
52    #   differently, so disable it, too.
53    _unsupported_fmt vdi vhdx
54fi
55
56
57TEST_IMG="$TEST_IMG.orig" _make_test_img 64M
58
59$QEMU_IO -c 'write -P 42 0 64M' "$TEST_IMG.orig" | _filter_qemu_io
60
61
62sector_size=512
63
64# Offsets on which to fail block-status.  Keep in ascending order so
65# the indexing done by _filter_offsets will appear in ascending order
66# in the output as well.
67status_fail_offsets="$((16 * 1024 * 1024 + 8192))
68                     $((33 * 1024 * 1024 + 512))"
69
70# Offsets on which to fail reads.  Keep in ascending order for the
71# same reason.
72# The second element is shared with $status_fail_offsets on purpose.
73# Starting with the third element, we test what happens when a
74# continuous range of sectors is inaccessible.
75read_fail_offsets="$((32 * 1024 * 1024 - 65536))
76                   $((33 * 1024 * 1024 + 512))
77                   $(seq $((34 * 1024 * 1024)) $sector_size \
78                         $((34 * 1024 * 1024 + 4096 - $sector_size)))"
79
80
81# blkdebug must be above the format layer so it can intercept all
82# block-status events
83source_img="json:{'driver': 'blkdebug',
84                  'image': {
85                      'driver': '$IMGFMT',
86                      'file': {
87                          'driver': 'file',
88                          'filename': '$TEST_IMG.orig'
89                      }
90                  },
91                  'inject-error': ["
92
93for ofs in $status_fail_offsets
94do
95    source_img+="{ 'event': 'none',
96                   'iotype': 'block-status',
97                   'errno': 5,
98                   'sector': $((ofs / sector_size)) },"
99done
100
101for ofs in $read_fail_offsets
102do
103    source_img+="{ 'event': 'none',
104                   'iotype': 'read',
105                   'errno': 5,
106                   'sector': $((ofs / sector_size)) },"
107done
108
109# Remove the trailing comma and terminate @inject-error and json:{}
110source_img="${source_img%,} ] }"
111
112
113echo
114
115
116_filter_offsets() {
117    filters=
118
119    index=0
120    for ofs in $1
121    do
122        filters+=" -e s/$ofs/status_fail_offset_$index/"
123        index=$((index + 1))
124    done
125
126    index=0
127    for ofs in $2
128    do
129        filters+=" -e s/$ofs/read_fail_offset_$index/"
130        index=$((index + 1))
131    done
132
133    sed $filters
134}
135
136# While determining the number of allocated sectors in the input
137# image, we should see one block status warning per element of
138# $status_fail_offsets.
139#
140# Then, the image is read.  Since the block status is queried in
141# basically the same way, the same warnings as in the previous step
142# should reappear.  Interleaved with those we should see a read
143# warning per element of $read_fail_offsets.
144# Note that $read_fail_offsets and $status_fail_offsets share an
145# element (read_fail_offset_1 == status_fail_offset_1), so
146# "status_fail_offset_1" in the output is the same as
147# "read_fail_offset_1".
148$QEMU_IMG convert --salvage "$source_img" "$TEST_IMG" 2>&1 \
149    | _filter_offsets "$status_fail_offsets" "$read_fail_offsets"
150
151echo
152
153# The offsets where the block status could not be determined should
154# have been treated as containing data and thus should be correct in
155# the output image.
156# The offsets where reading failed altogether should be 0.  Make them
157# 0 in the input image, too, so we can compare both images.
158for ofs in $read_fail_offsets
159do
160    $QEMU_IO -c "write -z $ofs $sector_size" "$TEST_IMG.orig" \
161        | _filter_qemu_io \
162        | _filter_offsets '' "$read_fail_offsets"
163done
164
165echo
166
167# These should be equal now.
168$QEMU_IMG compare "$TEST_IMG.orig" "$TEST_IMG"
169
170
171# success, all done
172echo "*** done"
173rm -f $seq.full
174status=0
175