xref: /qemu/tests/qemu-iotests/218 (revision b2a3cbb8)
1#!/usr/bin/env python3
2# group: rw quick
3#
4# This test covers what happens when a mirror block job is cancelled
5# in various phases of its existence.
6#
7# Note that this test only checks the emitted events (i.e.
8# BLOCK_JOB_COMPLETED vs. BLOCK_JOB_CANCELLED), it does not compare
9# whether the target is in sync with the source when the
10# BLOCK_JOB_COMPLETED event occurs.  This is covered by other tests
11# (such as 041).
12#
13# Copyright (C) 2018 Red Hat, Inc.
14#
15# This program is free software; you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation; either version 2 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program.  If not, see <http://www.gnu.org/licenses/>.
27#
28# Creator/Owner: Hanna Reitz <hreitz@redhat.com>
29
30import iotests
31from iotests import log, qemu_img, qemu_io
32
33iotests.script_initialize(supported_fmts=['qcow2', 'raw'])
34
35
36# Launches the VM, adds two null-co nodes (source and target), and
37# starts a blockdev-mirror job on them.
38#
39# Either both or none of speed and buf_size must be given.
40
41def start_mirror(vm, speed=None, buf_size=None):
42    vm.launch()
43
44    ret = vm.qmp('blockdev-add',
45                     node_name='source',
46                     driver='null-co',
47                     size=1048576)
48    assert ret['return'] == {}
49
50    ret = vm.qmp('blockdev-add',
51                     node_name='target',
52                     driver='null-co',
53                     size=1048576)
54    assert ret['return'] == {}
55
56    if speed is not None:
57        ret = vm.qmp('blockdev-mirror',
58                         job_id='mirror',
59                         device='source',
60                         target='target',
61                         sync='full',
62                         speed=speed,
63                         buf_size=buf_size)
64    else:
65        ret = vm.qmp('blockdev-mirror',
66                         job_id='mirror',
67                         device='source',
68                         target='target',
69                         sync='full')
70
71    assert ret['return'] == {}
72
73
74log('')
75log('=== Cancel mirror job before convergence ===')
76log('')
77
78log('--- force=false ---')
79log('')
80
81with iotests.VM() as vm:
82    # Low speed so it does not converge
83    start_mirror(vm, 65536, 65536)
84
85    log('Cancelling job')
86    log(vm.qmp('block-job-cancel', device='mirror', force=False))
87
88    log(vm.event_wait('BLOCK_JOB_CANCELLED'),
89        filters=[iotests.filter_qmp_event])
90
91log('')
92log('--- force=true ---')
93log('')
94
95with iotests.VM() as vm:
96    # Low speed so it does not converge
97    start_mirror(vm, 65536, 65536)
98
99    log('Cancelling job')
100    log(vm.qmp('block-job-cancel', device='mirror', force=True))
101
102    log(vm.event_wait('BLOCK_JOB_CANCELLED'),
103        filters=[iotests.filter_qmp_event])
104
105
106log('')
107log('=== Cancel mirror job after convergence ===')
108log('')
109
110log('--- force=false ---')
111log('')
112
113with iotests.VM() as vm:
114    start_mirror(vm)
115
116    log(vm.event_wait('BLOCK_JOB_READY'),
117        filters=[iotests.filter_qmp_event])
118
119    log('Cancelling job')
120    log(vm.qmp('block-job-cancel', device='mirror', force=False))
121
122    log(vm.event_wait('BLOCK_JOB_COMPLETED'),
123        filters=[iotests.filter_qmp_event])
124
125log('')
126log('--- force=true ---')
127log('')
128
129with iotests.VM() as vm:
130    start_mirror(vm)
131
132    log(vm.event_wait('BLOCK_JOB_READY'),
133        filters=[iotests.filter_qmp_event])
134
135    log('Cancelling job')
136    log(vm.qmp('block-job-cancel', device='mirror', force=True))
137
138    log(vm.event_wait('BLOCK_JOB_CANCELLED'),
139        filters=[iotests.filter_qmp_event])
140
141log('')
142log('=== Cancel mirror job from throttled node by quitting ===')
143log('')
144
145with iotests.VM() as vm, \
146     iotests.FilePath('src.img') as src_img_path:
147
148    qemu_img('create', '-f', iotests.imgfmt, src_img_path, '64M')
149    qemu_io('-f', iotests.imgfmt, src_img_path, '-c', 'write -P 42 0M 64M')
150
151    vm.launch()
152
153    ret = vm.qmp('object-add', qom_type='throttle-group', id='tg',
154                 limits={'bps-read': 4096})
155    assert ret['return'] == {}
156
157    ret = vm.qmp('blockdev-add',
158                 node_name='source',
159                 driver=iotests.imgfmt,
160                 file={
161                     'driver': 'file',
162                     'filename': src_img_path
163                 })
164    assert ret['return'] == {}
165
166    ret = vm.qmp('blockdev-add',
167                 node_name='throttled-source',
168                 driver='throttle',
169                 throttle_group='tg',
170                 file='source')
171    assert ret['return'] == {}
172
173    ret = vm.qmp('blockdev-add',
174                 node_name='target',
175                 driver='null-co',
176                 size=(64 * 1048576))
177    assert ret['return'] == {}
178
179    ret = vm.qmp('blockdev-mirror',
180                 job_id='mirror',
181                 device='throttled-source',
182                 target='target',
183                 sync='full')
184    assert ret['return'] == {}
185
186    log(vm.qmp('quit'))
187
188    with iotests.Timeout(5, 'Timeout waiting for VM to quit'):
189        vm.shutdown()
190