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: Max Reitz <mreitz@redhat.com> 29 30import iotests 31from iotests import log, qemu_img, qemu_io_silent 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 assert qemu_img('create', '-f', iotests.imgfmt, src_img_path, '64M') == 0 149 assert qemu_io_silent('-f', iotests.imgfmt, src_img_path, 150 '-c', 'write -P 42 0M 64M') == 0 151 152 vm.launch() 153 154 ret = vm.qmp('object-add', qom_type='throttle-group', id='tg', 155 limits={'bps-read': 4096}) 156 assert ret['return'] == {} 157 158 ret = vm.qmp('blockdev-add', 159 node_name='source', 160 driver=iotests.imgfmt, 161 file={ 162 'driver': 'file', 163 'filename': src_img_path 164 }) 165 assert ret['return'] == {} 166 167 ret = vm.qmp('blockdev-add', 168 node_name='throttled-source', 169 driver='throttle', 170 throttle_group='tg', 171 file='source') 172 assert ret['return'] == {} 173 174 ret = vm.qmp('blockdev-add', 175 node_name='target', 176 driver='null-co', 177 size=(64 * 1048576)) 178 assert ret['return'] == {} 179 180 ret = vm.qmp('blockdev-mirror', 181 job_id='mirror', 182 device='throttled-source', 183 target='target', 184 sync='full') 185 assert ret['return'] == {} 186 187 log(vm.qmp('quit')) 188 189 with iotests.Timeout(5, 'Timeout waiting for VM to quit'): 190 vm.shutdown(has_quit=True) 191