1#!/usr/bin/env python3 2# group: rw 3# 4# Test graph changes while I/O is happening 5# 6# Copyright (C) 2022 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 22import os 23from threading import Thread 24import iotests 25from iotests import imgfmt, qemu_img, qemu_img_create, QMPTestCase, \ 26 QemuStorageDaemon 27 28 29top = os.path.join(iotests.test_dir, 'top.img') 30nbd_sock = os.path.join(iotests.sock_dir, 'nbd.sock') 31 32 33def do_qemu_img_bench() -> None: 34 """ 35 Do some I/O requests on `nbd_sock`. 36 """ 37 assert qemu_img('bench', '-f', 'raw', '-c', '2000000', 38 f'nbd+unix:///node0?socket={nbd_sock}') == 0 39 40 41class TestGraphChangesWhileIO(QMPTestCase): 42 def setUp(self) -> None: 43 # Create an overlay that can be added at runtime on top of the 44 # null-co block node that will receive I/O 45 assert qemu_img_create('-f', imgfmt, '-F', 'raw', '-b', 'null-co://', 46 top) == 0 47 48 # QSD instance with a null-co block node in an I/O thread, 49 # exported over NBD (on `nbd_sock`, export name "node0") 50 self.qsd = QemuStorageDaemon( 51 '--object', 'iothread,id=iothread0', 52 '--blockdev', 'null-co,node-name=node0,read-zeroes=true', 53 '--nbd-server', f'addr.type=unix,addr.path={nbd_sock}', 54 '--export', 'nbd,id=exp0,node-name=node0,iothread=iothread0,' + 55 'fixed-iothread=true,writable=true', 56 qmp=True 57 ) 58 59 def tearDown(self) -> None: 60 self.qsd.stop() 61 62 def test_blockdev_add_while_io(self) -> None: 63 # Run qemu-img bench in the background 64 bench_thr = Thread(target=do_qemu_img_bench) 65 bench_thr.start() 66 67 # While qemu-img bench is running, repeatedly add and remove an 68 # overlay to/from node0 69 while bench_thr.is_alive(): 70 result = self.qsd.qmp('blockdev-add', { 71 'driver': imgfmt, 72 'node-name': 'overlay', 73 'backing': 'node0', 74 'file': { 75 'driver': 'file', 76 'filename': top 77 } 78 }) 79 self.assert_qmp(result, 'return', {}) 80 81 result = self.qsd.qmp('blockdev-del', { 82 'node-name': 'overlay' 83 }) 84 self.assert_qmp(result, 'return', {}) 85 86 bench_thr.join() 87 88if __name__ == '__main__': 89 # Format must support raw backing files 90 iotests.main(supported_fmts=['qcow', 'qcow2', 'qed'], 91 supported_protocols=['file']) 92