1#!/usr/bin/env bash
2#
3# Test some qemu-img convert cases
4#
5# Copyright (C) 2015 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=kwolf@redhat.com
23
24seq="$(basename $0)"
25echo "QA output created by $seq"
26
27status=1	# failure is the default!
28
29_cleanup()
30{
31    for img in "$TEST_IMG".[123]; do
32        _rm_test_img "$img"
33    done
34    _cleanup_test_img
35}
36trap "_cleanup; exit \$status" 0 1 2 3 15
37
38# get standard environment, filters and checks
39. ./common.rc
40. ./common.filter
41
42_supported_fmt qcow2
43_supported_proto file
44_supported_os Linux
45
46
47TEST_IMG="$TEST_IMG".base _make_test_img 64M
48$QEMU_IO -c "write -P 0x11 0 64M" "$TEST_IMG".base 2>&1 | _filter_qemu_io | _filter_testdir
49
50
51echo
52echo "=== Check allocation status regression with -B ==="
53echo
54
55_make_test_img -b "$TEST_IMG".base -F $IMGFMT
56$QEMU_IO -c "write -P 0x22 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
57$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base \
58    -o backing_fmt=$IMGFMT "$TEST_IMG" "$TEST_IMG".orig
59$QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map
60
61
62echo
63echo "=== Check that zero clusters are kept in overlay ==="
64echo
65
66_make_test_img -b "$TEST_IMG".base -F $IMGFMT
67
68$QEMU_IO -c "write -P 0 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
69$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \
70    "$TEST_IMG" "$TEST_IMG".orig
71$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
72$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \
73    "$TEST_IMG" "$TEST_IMG".orig
74$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
75
76$QEMU_IO -c "write -z 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
77$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \
78    "$TEST_IMG" "$TEST_IMG".orig
79$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
80$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \
81    "$TEST_IMG" "$TEST_IMG".orig
82$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
83
84
85echo
86echo "=== Converting to an overlay larger than its backing file ==="
87echo
88
89TEST_IMG="$TEST_IMG".base _make_test_img 256M
90# Needs to be at least how much an L2 table covers
91# (64 kB/entry * 64 kB / 8 B/entry = 512 MB)
92# That way, qcow2 will yield at least two status request responses.
93# With just a single response, it would always say "Allocated in the
94# backing file", so the optimization qemu-img convert tries to do is
95# done automatically.  Once it has to be queried twice, however (and
96# one of the queries is completely after the end of the backing file),
97# the block layer will automatically add a ZERO flag that qemu-img
98# convert used to follow up with a zero write to the target.
99# We do not want such a zero write, however, because we are past the
100# end of the backing file on the target as well, so we do not need to
101# write anything there.
102_make_test_img -b "$TEST_IMG".base 768M -F $IMGFMT
103
104# Use compat=0.10 as the output so there is no zero cluster support
105$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o compat=0.10 \
106    -o backing_fmt=$IMGFMT "$TEST_IMG" "$TEST_IMG".orig
107# See that nothing has been allocated past 64M
108$QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map
109
110echo
111
112# Just before the end of the backing file
113$QEMU_IO -c 'write -P 0x11 255M 1M' "$TEST_IMG".base 2>&1 | _filter_qemu_io
114# Somewhere in the second L2 table
115$QEMU_IO -c 'write -P 0x22 600M 1M' "$TEST_IMG" 2>&1 | _filter_qemu_io
116
117$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o compat=0.10 \
118    -o backing_fmt=$IMGFMT "$TEST_IMG" "$TEST_IMG".orig
119
120$QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map
121$QEMU_IO -c 'read -P 0x11 255M 1M' \
122         -c 'read -P 0x22 600M 1M' \
123         "$TEST_IMG".orig \
124    | _filter_qemu_io
125
126
127echo
128echo "=== Concatenate multiple source images ==="
129echo
130
131TEST_IMG="$TEST_IMG".1 _make_test_img 4M
132TEST_IMG="$TEST_IMG".2 _make_test_img 4M
133TEST_IMG="$TEST_IMG".3 _make_test_img 4M
134
135$QEMU_IO -c "write -P 0x11 0 64k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
136$QEMU_IO -c "write -P 0x22 0 64k" "$TEST_IMG".2 2>&1 | _filter_qemu_io | _filter_testdir
137$QEMU_IO -c "write -P 0x33 0 64k" "$TEST_IMG".3 2>&1 | _filter_qemu_io | _filter_testdir
138
139$QEMU_IMG convert -O $IMGFMT "$TEST_IMG".[123] "$TEST_IMG"
140$QEMU_IMG map "$TEST_IMG" | _filter_qemu_img_map
141$QEMU_IO -c "read -P 0x11 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
142$QEMU_IO -c "read -P 0x22 4M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
143$QEMU_IO -c "read -P 0x33 8M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
144
145$QEMU_IMG convert -c -O $IMGFMT "$TEST_IMG".[123] "$TEST_IMG"
146$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
147$QEMU_IO -c "read -P 0x11 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
148$QEMU_IO -c "read -P 0x22 4M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
149$QEMU_IO -c "read -P 0x33 8M 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
150
151# -B can't be combined with concatenation
152$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base "$TEST_IMG".[123] "$TEST_IMG"
153$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base "$TEST_IMG".[123] "$TEST_IMG"
154
155
156echo
157echo "=== Compression with misaligned allocations and image sizes ==="
158echo
159
160TEST_IMG="$TEST_IMG".1 _make_test_img 1023k -o cluster_size=1024
161TEST_IMG="$TEST_IMG".2 _make_test_img 1023k -o cluster_size=1024
162
163$QEMU_IO -c "write -P 0x11   16k  16k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
164$QEMU_IO -c "write -P 0x22  130k 130k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
165$QEMU_IO -c "write -P 0x33 1022k   1k" "$TEST_IMG".1 2>&1 | _filter_qemu_io | _filter_testdir
166$QEMU_IO -c "write -P 0x44    0k   1k" "$TEST_IMG".2 2>&1 | _filter_qemu_io | _filter_testdir
167
168$QEMU_IMG convert -c -O $IMGFMT "$TEST_IMG".[12] "$TEST_IMG"
169$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
170$QEMU_IO -c "read -P 0       0k   16k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
171$QEMU_IO -c "read -P 0x11   16k   16k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
172$QEMU_IO -c "read -P 0      32k   98k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
173$QEMU_IO -c "read -P 0x22  130k  130k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
174$QEMU_IO -c "read -P 0     260k  762k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
175$QEMU_IO -c "read -P 0x33 1022k    1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
176$QEMU_IO -c "read -P 0x44 1023k    1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
177$QEMU_IO -c "read -P 0    1024k 1022k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
178
179
180echo
181echo "=== Full allocation with -S 0 ==="
182echo
183
184# Standalone image
185_make_test_img 64M
186$QEMU_IO -c "write -P 0x22 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
187$QEMU_IO -c "write -P 0 3M 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
188
189echo
190echo convert -S 0:
191$QEMU_IMG convert -O $IMGFMT -S 0 "$TEST_IMG" "$TEST_IMG".orig
192$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
193$QEMU_IO -c "read -P 0 3M 61M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
194$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
195
196echo
197echo convert -c -S 0:
198$QEMU_IMG convert -O $IMGFMT -c -S 0 "$TEST_IMG" "$TEST_IMG".orig
199$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
200$QEMU_IO -c "read -P 0 3M 61M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
201$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
202
203# With backing file
204TEST_IMG="$TEST_IMG".base _make_test_img 64M
205$QEMU_IO -c "write -P 0x11 0 32M" "$TEST_IMG".base 2>&1 | _filter_qemu_io | _filter_testdir
206
207_make_test_img -b "$TEST_IMG".base 64M -F $IMGFMT
208$QEMU_IO -c "write -P 0x22 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
209
210echo
211echo convert -S 0 with source backing file:
212$QEMU_IMG convert -O $IMGFMT -S 0 "$TEST_IMG" "$TEST_IMG".orig
213$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
214$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
215$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
216$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
217
218echo
219echo convert -c -S 0 with source backing file:
220$QEMU_IMG convert -O $IMGFMT -c -S 0 "$TEST_IMG" "$TEST_IMG".orig
221$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
222$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
223$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
224$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
225
226# With keeping the backing file
227echo
228echo convert -S 0 -B ...
229$QEMU_IMG convert -O $IMGFMT -S 0 "$TEST_IMG" "$TEST_IMG".orig
230$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
231$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
232$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
233$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
234
235echo
236echo convert -c -S 0 -B ...
237$QEMU_IMG convert -O $IMGFMT -c -S 0 "$TEST_IMG" "$TEST_IMG".orig
238$QEMU_IO -c "read -P 0x22 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
239$QEMU_IO -c "read -P 0x11 3M 29M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
240$QEMU_IO -c "read -P 0 32M 32M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
241$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
242
243
244echo
245echo "=== Non-zero -S ==="
246echo
247
248_make_test_img 64M -o cluster_size=1k
249$QEMU_IO -c "write -P 0 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
250$QEMU_IO -c "write 0 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
251$QEMU_IO -c "write 8k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
252$QEMU_IO -c "write 17k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
253
254for min_sparse in 4k 8k; do
255    echo
256    echo convert -S $min_sparse
257    $QEMU_IMG convert -O $IMGFMT -o cluster_size=1k -S $min_sparse "$TEST_IMG" "$TEST_IMG".orig
258    $QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
259
260    echo
261    echo convert -c -S $min_sparse
262    # For compressed images, -S values other than 0 are ignored
263    $QEMU_IMG convert -O $IMGFMT -o cluster_size=1k -c -S $min_sparse "$TEST_IMG" "$TEST_IMG".orig
264    $QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
265done
266
267
268echo
269echo '=== -n to a non-zero image ==='
270echo
271
272# Keep source zero
273_make_test_img 64M
274
275# Output is not zero, but has bdrv_has_zero_init() == 1
276TEST_IMG="$TEST_IMG".orig _make_test_img 64M
277$QEMU_IO -c "write -P 42 0 64k" "$TEST_IMG".orig | _filter_qemu_io
278
279# Convert with -n, which should not assume that the target is zeroed
280$QEMU_IMG convert -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG".orig
281
282$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG".orig
283
284echo
285echo '=== -n to an empty image ==='
286echo
287
288TEST_IMG="$TEST_IMG".orig _make_test_img 64M
289
290# Convert with -n, which should not result in a fully allocated image, not even
291# with compat=0.10 (because the target doesn't have a backing file)
292for compat in "1.1" "0.10"; do
293    IMGOPTS="compat=$compat" _make_test_img 64M
294    $QEMU_IMG convert -O $IMGFMT -n "$TEST_IMG".orig "$TEST_IMG"
295    $QEMU_IMG map --output=json "$TEST_IMG"
296done
297
298echo
299echo '=== -n to an empty image with a backing file ==='
300echo
301
302TEST_IMG="$TEST_IMG".orig _make_test_img 64M
303TEST_IMG="$TEST_IMG".base _make_test_img 64M
304
305# Convert with -n, which should still not result in a fully allocated image for
306# compat=1.1 (because it can use zero clusters), but it should be fully
307# allocated with compat=0.10
308for compat in "1.1" "0.10"; do
309    IMGOPTS="compat=$compat" _make_test_img -b "$TEST_IMG".base -F $IMGFMT 64M
310    $QEMU_IMG convert -O $IMGFMT -n "$TEST_IMG".orig "$TEST_IMG"
311    $QEMU_IMG map --output=json "$TEST_IMG"
312done
313
314echo
315echo '=== -n -B to an image without a backing file ==='
316echo
317
318# Base for the output
319TEST_IMG="$TEST_IMG".base _make_test_img 64M
320
321# Output that does have $TEST_IMG.base set as its (implicit) backing file
322TEST_IMG="$TEST_IMG".orig _make_test_img 64M
323
324# Convert with -n, which should not confuse -B with "target BDS has a
325# backing file"
326$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -n "$TEST_IMG" "$TEST_IMG".orig
327
328echo
329echo '=== -n incompatible with -o ==='
330echo
331
332$QEMU_IMG convert -O $IMGFMT -o preallocation=metadata -n \
333	  "$TEST_IMG" "$TEST_IMG".orig && echo "unexpected success"
334
335# success, all done
336echo '*** done'
337rm -f $seq.full
338status=0
339