OSDN Git Service

Merge tag 'pull-halloween-omnibus-311023-2' of https://gitlab.com/stsquad/qemu into...
[qmiga/qemu.git] / tests / qemu-iotests / 185
1 #!/usr/bin/env bash
2 # group: rw
3 #
4 # Test exiting qemu while jobs are still running
5 #
6 # Copyright (C) 2017 Red Hat, Inc.
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21
22 # creator
23 owner=kwolf@redhat.com
24
25 seq=`basename $0`
26 echo "QA output created by $seq"
27
28 status=1 # failure is the default!
29
30 _cleanup()
31 {
32     _rm_test_img "${TEST_IMG}.mid"
33     _rm_test_img "${TEST_IMG}.copy"
34     _cleanup_test_img
35     _cleanup_qemu
36
37     if [ -f "$TEST_DIR/qsd.pid" ]; then
38         kill -SIGKILL "$(cat "$TEST_DIR/qsd.pid")"
39         rm -f "$TEST_DIR/qsd.pid"
40     fi
41     rm -f "$SOCK_DIR/qsd.sock"
42 }
43 trap "_cleanup; exit \$status" 0 1 2 3 15
44
45 # get standard environment, filters and checks
46 . ./common.rc
47 . ./common.filter
48 . ./common.qemu
49
50 _supported_fmt qcow2
51 _supported_proto file
52 _supported_os Linux
53
54 size=$((64 * 1048576))
55 TEST_IMG="${TEST_IMG}.base" _make_test_img $size
56
57 echo
58 echo === Starting VM ===
59 echo
60
61 qemu_comm_method="qmp"
62
63 _launch_qemu \
64     -drive file="${TEST_IMG}.base",cache=$CACHEMODE,aio=$AIOMODE,driver=$IMGFMT,id=disk
65 h=$QEMU_HANDLE
66 _send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
67
68 echo
69 echo === Creating backing chain ===
70 echo
71
72 _send_qemu_cmd $h \
73     "{ 'execute': 'blockdev-snapshot-sync',
74        'arguments': { 'device': 'disk',
75                       'snapshot-file': '$TEST_IMG.mid',
76                       'format': '$IMGFMT',
77                       'mode': 'absolute-paths' } }" \
78     "return"
79
80 _send_qemu_cmd $h \
81     "{ 'execute': 'human-monitor-command',
82        'arguments': { 'command-line':
83                       'qemu-io disk \"write 0 4M\"' } }" \
84     "return"
85
86 _send_qemu_cmd $h \
87     "{ 'execute': 'blockdev-snapshot-sync',
88        'arguments': { 'device': 'disk',
89                       'snapshot-file': '$TEST_IMG',
90                       'format': '$IMGFMT',
91                       'mode': 'absolute-paths' } }" \
92     "return"
93
94 echo
95 echo === Start commit job and exit qemu ===
96 echo
97
98 # Note that the reference output intentionally includes the 'offset' field in
99 # BLOCK_JOB_* events for all of the following block jobs. They are predictable
100 # and any change in the offsets would hint at a bug in the job throttling code.
101 #
102 # In order to achieve these predictable offsets, all of the following tests
103 # use speed=65536. Each job will perform exactly one iteration before it has
104 # to sleep at least for a second, which is plenty of time for the 'quit' QMP
105 # command to be received (after receiving the command, the rest runs
106 # synchronously, so jobs can arbitrarily continue or complete).
107 #
108 # The buffer size for commit and streaming is 512k (waiting for 8 seconds after
109 # the first request), for active commit and mirror it's large enough to cover
110 # the full 4M, and for backup it's the qcow2 cluster size, which we know is
111 # 64k. As all of these are at least as large as the speed, we are sure that the
112 # offset advances exactly once before qemu exits.
113
114 _send_qemu_cmd $h \
115     "{ 'execute': 'block-commit',
116        'arguments': { 'device': 'disk',
117                       'base':'$TEST_IMG.base',
118                       'top': '$TEST_IMG.mid',
119                       'speed': 65536 } }" \
120     "return"
121
122 # If we don't sleep here 'quit' command races with disk I/O
123 sleep 0.5
124
125 # Ignore the JOB_STATUS_CHANGE events while shutting down the VM. Depending on
126 # the timing, jobs may or may not transition through a paused state.
127 _send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
128 wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE'
129
130 echo
131 echo === Start active commit job and exit qemu ===
132 echo
133
134 _launch_qemu \
135     -drive file="${TEST_IMG}",cache=$CACHEMODE,aio=$AIOMODE,driver=$IMGFMT,id=disk
136 h=$QEMU_HANDLE
137 _send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
138
139 _send_qemu_cmd $h \
140     "{ 'execute': 'block-commit',
141        'arguments': { 'device': 'disk',
142                       'base':'$TEST_IMG.base',
143                       'speed': 65536 } }" \
144     "return"
145
146 # If we don't sleep here 'quit' command races with disk I/O
147 sleep 0.5
148
149 _send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
150 wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE'
151
152 echo
153 echo === Start mirror job and exit qemu ===
154 echo
155
156 _launch_qemu \
157     -drive file="${TEST_IMG}",cache=$CACHEMODE,aio=$AIOMODE,driver=$IMGFMT,id=disk
158 h=$QEMU_HANDLE
159 _send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
160
161 _send_qemu_cmd $h \
162     "{ 'execute': 'drive-mirror',
163        'arguments': { 'device': 'disk',
164                       'target': '$TEST_IMG.copy',
165                       'format': '$IMGFMT',
166                       'sync': 'full',
167                       'speed': 65536 } }" \
168     "return"
169
170 # If we don't sleep here 'quit' command may be handled before
171 # the first mirror iteration is done
172 sleep 0.5
173
174 _send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
175 wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE'
176
177 echo
178 echo === Start backup job and exit qemu ===
179 echo
180
181 _launch_qemu \
182     -drive file="${TEST_IMG}",cache=$CACHEMODE,aio=$AIOMODE,driver=$IMGFMT,id=disk
183 h=$QEMU_HANDLE
184 _send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
185
186 _send_qemu_cmd $h \
187     "{ 'execute': 'drive-backup',
188        'arguments': { 'device': 'disk',
189                       'target': '$TEST_IMG.copy',
190                       'format': '$IMGFMT',
191                       'sync': 'full',
192                       'speed': 65536,
193                       'x-perf': {'max-chunk': 65536} } }" \
194     "return"
195
196 # If we don't sleep here 'quit' command races with disk I/O
197 sleep 0.5
198
199 _send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
200 wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE'
201
202 echo
203 echo === Start streaming job and exit qemu ===
204 echo
205
206 _launch_qemu \
207     -drive file="${TEST_IMG}",cache=$CACHEMODE,aio=$AIOMODE,driver=$IMGFMT,id=disk
208 h=$QEMU_HANDLE
209 _send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
210
211 _send_qemu_cmd $h \
212     "{ 'execute': 'block-stream',
213        'arguments': { 'device': 'disk',
214                       'speed': 65536 } }" \
215     "return"
216
217 # If we don't sleep here 'quit' command races with disk I/O
218 sleep 0.5
219
220 _send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
221 wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE'
222
223 _check_test_img
224
225 echo
226 echo === Start mirror to throttled QSD and exit qemu ===
227 echo
228
229 # Mirror to a throttled QSD instance (so that qemu cannot drain the
230 # throttling), wait for READY, then write some data to the device,
231 # and then quit qemu.
232 # (qemu should force-cancel the job and not wait for the data to be
233 # written to the target.)
234
235 _make_test_img $size
236
237 # Will be used by this and the next case
238 set_up_throttled_qsd() {
239     $QSD \
240         --object throttle-group,id=thrgr,limits.bps-total=1048576 \
241         --blockdev null-co,node-name=null,size=$size \
242         --blockdev throttle,node-name=throttled,throttle-group=thrgr,file=null \
243         --nbd-server addr.type=unix,addr.path="$SOCK_DIR/qsd.sock" \
244         --export nbd,id=exp,node-name=throttled,name=target,writable=true \
245         --pidfile "$TEST_DIR/qsd.pid" \
246         --daemonize
247 }
248
249 set_up_throttled_qsd
250
251 # Need a virtio-blk device so that qemu-io writes will not block the monitor
252 _launch_qemu \
253     --blockdev file,node-name=source-proto,filename="$TEST_IMG" \
254     --blockdev qcow2,node-name=source-fmt,file=source-proto \
255     --device virtio-blk,id=vblk,drive=source-fmt \
256     --blockdev "{\"driver\": \"nbd\",
257                  \"node-name\": \"target\",
258                  \"server\": {
259                      \"type\": \"unix\",
260                      \"path\": \"$SOCK_DIR/qsd.sock\"
261                  },
262                  \"export\": \"target\"}"
263
264 h=$QEMU_HANDLE
265 _send_qemu_cmd $h '{"execute": "qmp_capabilities"}' 'return'
266
267 # Use sync=top, so the first pass will not copy the whole image
268 _send_qemu_cmd $h \
269     '{"execute": "blockdev-mirror",
270       "arguments": {
271           "job-id": "mirror",
272           "device": "source-fmt",
273           "target": "target",
274           "sync": "top"
275       }}' \
276     'return' \
277     | grep -v JOB_STATUS_CHANGE # Ignore these events during creation
278
279 # This too will be used by this and the next case
280 # $1: QEMU handle
281 # $2: Image size
282 wait_for_job_and_quit() {
283     h=$1
284     size=$2
285
286     # List of expected events
287     capture_events='BLOCK_JOB_READY JOB_STATUS_CHANGE'
288     _wait_event $h 'BLOCK_JOB_READY'
289     QEMU_EVENTS= # Ignore all JOB_STATUS_CHANGE events that came before READY
290
291     # Write something to the device for post-READY mirroring.  Write it in
292     # blocks matching the cluster size, each spaced one block apart, so
293     # that the mirror job will have to spawn one request per cluster.
294     # Because the number of concurrent requests is limited (to 16), this
295     # limits the number of bytes concurrently in flight, which speeds up
296     # cancelling the job (in-flight requests still are waited for).
297     # To limit the number of bytes in flight, we could alternatively pass
298     # something for blockdev-mirror's @buf-size parameter, but
299     # block-commit does not have such a parameter, so we need to figure
300     # something out that works for both.
301
302     cluster_size=65536
303     step=$((cluster_size * 2))
304
305     echo '--- Writing data to the virtio-blk device ---'
306
307     for ofs in $(seq 0 $step $((size - step))); do
308         qemu_io_cmd="qemu-io -d vblk/virtio-backend "
309         qemu_io_cmd+="\\\"aio_write $ofs $cluster_size\\\""
310
311         # Do not include these requests in the reference output
312         # (it's just too much)
313         silent=yes _send_qemu_cmd $h \
314             "{\"execute\": \"human-monitor-command\",
315               \"arguments\": {
316                   \"command-line\": \"$qemu_io_cmd\"
317               }}" \
318             'return'
319     done
320
321     # Wait until the job's length is updated to reflect the write requests
322
323     # We have written to half of the device, so this is the expected job length
324     final_len=$((size / 2))
325     timeout=100 # unit: 0.1 seconds
326     while true; do
327         len=$(
328             _send_qemu_cmd $h \
329                 '{"execute": "query-block-jobs"}' \
330                 'return.*"len": [0-9]\+' \
331                 | grep 'return.*"len": [0-9]\+' \
332                 | sed -e 's/.*"len": \([0-9]\+\).*/\1/'
333         )
334         if [ "$len" -eq "$final_len" ]; then
335             break
336         fi
337         timeout=$((timeout - 1))
338         if [ "$timeout" -eq 0 ]; then
339             echo "ERROR: Timeout waiting for job to reach len=$final_len"
340             break
341         fi
342         sleep 0.1
343     done
344
345     sleep 1
346
347     _send_qemu_cmd $h \
348         '{"execute": "quit"}' \
349         'return'
350
351     # List of expected events
352     capture_events='BLOCK_JOB_CANCELLED JOB_STATUS_CHANGE SHUTDOWN'
353     _wait_event $h 'SHUTDOWN'
354     QEMU_EVENTS= # Ignore all JOB_STATUS_CHANGE events that came before SHUTDOWN
355     _wait_event $h 'JOB_STATUS_CHANGE' # standby
356     _wait_event $h 'JOB_STATUS_CHANGE' # ready
357     _wait_event $h 'JOB_STATUS_CHANGE' # standby
358     _wait_event $h 'JOB_STATUS_CHANGE' # ready
359     _wait_event $h 'JOB_STATUS_CHANGE' # aborting
360     # Filter the offset (depends on when exactly `quit` was issued)
361     _wait_event $h 'BLOCK_JOB_CANCELLED' \
362         | sed -e 's/"offset": [0-9]\+/"offset": (filtered)/'
363     _wait_event $h 'JOB_STATUS_CHANGE' # concluded
364     _wait_event $h 'JOB_STATUS_CHANGE' # null
365
366     wait=yes _cleanup_qemu
367
368     kill -SIGTERM "$(cat "$TEST_DIR/qsd.pid")"
369 }
370
371 wait_for_job_and_quit $h $size
372
373 echo
374 echo === Start active commit to throttled QSD and exit qemu ===
375 echo
376
377 # Same as the above, but instead of mirroring, do an active commit
378
379 _make_test_img $size
380
381 set_up_throttled_qsd
382
383 _launch_qemu \
384     --blockdev "{\"driver\": \"nbd\",
385                  \"node-name\": \"target\",
386                  \"server\": {
387                      \"type\": \"unix\",
388                      \"path\": \"$SOCK_DIR/qsd.sock\"
389                  },
390                  \"export\": \"target\"}" \
391     --blockdev file,node-name=source-proto,filename="$TEST_IMG" \
392     --blockdev qcow2,node-name=source-fmt,file=source-proto,backing=target \
393     --device virtio-blk,id=vblk,drive=source-fmt
394
395 h=$QEMU_HANDLE
396 _send_qemu_cmd $h '{"execute": "qmp_capabilities"}' 'return'
397
398 _send_qemu_cmd $h \
399     '{"execute": "block-commit",
400       "arguments": {
401           "job-id": "commit",
402           "device": "source-fmt"
403       }}' \
404     'return' \
405     | grep -v JOB_STATUS_CHANGE # Ignore these events during creation
406
407 wait_for_job_and_quit $h $size
408
409 # success, all done
410 echo "*** done"
411 rm -f $seq.full
412 status=0