1903cb1bfSPhilippe Mathieu-Daudé#!/usr/bin/env python3 2*9dd003a9SVladimir Sementsov-Ogievskiy# group: rw quick 348057fc2SMax Reitz# 448057fc2SMax Reitz# Very specific tests for adjacent commit/stream block jobs 548057fc2SMax Reitz# 648057fc2SMax Reitz# Copyright (C) 2019 Red Hat, Inc. 748057fc2SMax Reitz# 848057fc2SMax Reitz# This program is free software; you can redistribute it and/or modify 948057fc2SMax Reitz# it under the terms of the GNU General Public License as published by 1048057fc2SMax Reitz# the Free Software Foundation; either version 2 of the License, or 1148057fc2SMax Reitz# (at your option) any later version. 1248057fc2SMax Reitz# 1348057fc2SMax Reitz# This program is distributed in the hope that it will be useful, 1448057fc2SMax Reitz# but WITHOUT ANY WARRANTY; without even the implied warranty of 1548057fc2SMax Reitz# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1648057fc2SMax Reitz# GNU General Public License for more details. 1748057fc2SMax Reitz# 1848057fc2SMax Reitz# You should have received a copy of the GNU General Public License 1948057fc2SMax Reitz# along with this program. If not, see <http://www.gnu.org/licenses/>. 2048057fc2SMax Reitz# 2148057fc2SMax Reitz# Creator/Owner: Max Reitz <mreitz@redhat.com> 2248057fc2SMax Reitz 2348057fc2SMax Reitzimport iotests 2448057fc2SMax Reitzfrom iotests import log, qemu_img, qemu_io_silent, \ 2548057fc2SMax Reitz filter_qmp_testfiles, filter_qmp_imgfmt 2648057fc2SMax Reitz 2748057fc2SMax Reitz# Returns a node for blockdev-add 2848057fc2SMax Reitzdef node(node_name, path, backing=None, fmt=None, throttle=None): 2948057fc2SMax Reitz if fmt is None: 3048057fc2SMax Reitz fmt = iotests.imgfmt 3148057fc2SMax Reitz 3248057fc2SMax Reitz res = { 3348057fc2SMax Reitz 'node-name': node_name, 3448057fc2SMax Reitz 'driver': fmt, 3548057fc2SMax Reitz 'file': { 3648057fc2SMax Reitz 'driver': 'file', 3748057fc2SMax Reitz 'filename': path 3848057fc2SMax Reitz } 3948057fc2SMax Reitz } 4048057fc2SMax Reitz 4148057fc2SMax Reitz if backing is not None: 4248057fc2SMax Reitz res['backing'] = backing 4348057fc2SMax Reitz 4448057fc2SMax Reitz if throttle: 4548057fc2SMax Reitz res['file'] = { 4648057fc2SMax Reitz 'driver': 'throttle', 4748057fc2SMax Reitz 'throttle-group': throttle, 4848057fc2SMax Reitz 'file': res['file'] 4948057fc2SMax Reitz } 5048057fc2SMax Reitz 5148057fc2SMax Reitz return res 5248057fc2SMax Reitz 5348057fc2SMax Reitz# Finds a node in the debug block graph 5448057fc2SMax Reitzdef find_graph_node(graph, node_id): 5548057fc2SMax Reitz return next(node for node in graph['nodes'] if node['id'] == node_id) 5648057fc2SMax Reitz 5748057fc2SMax Reitz 5848057fc2SMax Reitzdef test_concurrent_finish(write_to_stream_node): 5948057fc2SMax Reitz log('') 6048057fc2SMax Reitz log('=== Commit and stream finish concurrently (letting %s write) ===' % \ 6148057fc2SMax Reitz ('stream' if write_to_stream_node else 'commit')) 6248057fc2SMax Reitz log('') 6348057fc2SMax Reitz 6448057fc2SMax Reitz # All chosen in such a way that when the commit job wants to 6548057fc2SMax Reitz # finish, it polls and thus makes stream finish concurrently -- 6648057fc2SMax Reitz # and the other way around, depending on whether the commit job 6748057fc2SMax Reitz # is finalized before stream completes or not. 6848057fc2SMax Reitz 6948057fc2SMax Reitz with iotests.FilePath('node4.img') as node4_path, \ 7048057fc2SMax Reitz iotests.FilePath('node3.img') as node3_path, \ 7148057fc2SMax Reitz iotests.FilePath('node2.img') as node2_path, \ 7248057fc2SMax Reitz iotests.FilePath('node1.img') as node1_path, \ 7348057fc2SMax Reitz iotests.FilePath('node0.img') as node0_path, \ 7448057fc2SMax Reitz iotests.VM() as vm: 7548057fc2SMax Reitz 7648057fc2SMax Reitz # It is important to use raw for the base layer (so that 7748057fc2SMax Reitz # permissions are just handed through to the protocol layer) 7848057fc2SMax Reitz assert qemu_img('create', '-f', 'raw', node0_path, '64M') == 0 7948057fc2SMax Reitz 8048057fc2SMax Reitz stream_throttle=None 8148057fc2SMax Reitz commit_throttle=None 8248057fc2SMax Reitz 8348057fc2SMax Reitz for path in [node1_path, node2_path, node3_path, node4_path]: 8448057fc2SMax Reitz assert qemu_img('create', '-f', iotests.imgfmt, path, '64M') == 0 8548057fc2SMax Reitz 8648057fc2SMax Reitz if write_to_stream_node: 8748057fc2SMax Reitz # This is what (most of the time) makes commit finish 8848057fc2SMax Reitz # earlier and then pull in stream 8948057fc2SMax Reitz assert qemu_io_silent(node2_path, 9048057fc2SMax Reitz '-c', 'write %iK 64K' % (65536 - 192), 9148057fc2SMax Reitz '-c', 'write %iK 64K' % (65536 - 64)) == 0 9248057fc2SMax Reitz 9348057fc2SMax Reitz stream_throttle='tg' 9448057fc2SMax Reitz else: 9548057fc2SMax Reitz # And this makes stream finish earlier 9648057fc2SMax Reitz assert qemu_io_silent(node1_path, 9748057fc2SMax Reitz '-c', 'write %iK 64K' % (65536 - 64)) == 0 9848057fc2SMax Reitz 9948057fc2SMax Reitz commit_throttle='tg' 10048057fc2SMax Reitz 10148057fc2SMax Reitz vm.launch() 10248057fc2SMax Reitz 10348057fc2SMax Reitz vm.qmp_log('object-add', 10448057fc2SMax Reitz qom_type='throttle-group', 10548057fc2SMax Reitz id='tg', 10648057fc2SMax Reitz props={ 10748057fc2SMax Reitz 'x-iops-write': 1, 10848057fc2SMax Reitz 'x-iops-write-max': 1 10948057fc2SMax Reitz }) 11048057fc2SMax Reitz 11148057fc2SMax Reitz vm.qmp_log('blockdev-add', 11248057fc2SMax Reitz filters=[filter_qmp_testfiles, filter_qmp_imgfmt], 11348057fc2SMax Reitz **node('node4', node4_path, throttle=stream_throttle, 11448057fc2SMax Reitz backing=node('node3', node3_path, 11548057fc2SMax Reitz backing=node('node2', node2_path, 11648057fc2SMax Reitz backing=node('node1', node1_path, 11748057fc2SMax Reitz backing=node('node0', node0_path, throttle=commit_throttle, 11848057fc2SMax Reitz fmt='raw')))))) 11948057fc2SMax Reitz 12048057fc2SMax Reitz vm.qmp_log('block-commit', 12148057fc2SMax Reitz job_id='commit', 12248057fc2SMax Reitz device='node4', 12348057fc2SMax Reitz filter_node_name='commit-filter', 12448057fc2SMax Reitz top_node='node1', 12548057fc2SMax Reitz base_node='node0', 12648057fc2SMax Reitz auto_finalize=False) 12748057fc2SMax Reitz 12848057fc2SMax Reitz vm.qmp_log('block-stream', 12948057fc2SMax Reitz job_id='stream', 13048057fc2SMax Reitz device='node3', 13148057fc2SMax Reitz base_node='commit-filter') 13248057fc2SMax Reitz 13348057fc2SMax Reitz if write_to_stream_node: 13448057fc2SMax Reitz vm.run_job('commit', auto_finalize=False, auto_dismiss=True) 13548057fc2SMax Reitz vm.run_job('stream', auto_finalize=True, auto_dismiss=True) 13648057fc2SMax Reitz else: 13748057fc2SMax Reitz # No, the jobs do not really finish concurrently here, 13848057fc2SMax Reitz # the stream job does complete strictly before commit. 13948057fc2SMax Reitz # But still, this is close enough for what we want to 14048057fc2SMax Reitz # test. 14148057fc2SMax Reitz vm.run_job('stream', auto_finalize=True, auto_dismiss=True) 14248057fc2SMax Reitz vm.run_job('commit', auto_finalize=False, auto_dismiss=True) 14348057fc2SMax Reitz 14448057fc2SMax Reitz # Assert that the backing node of node3 is node 0 now 14548057fc2SMax Reitz graph = vm.qmp('x-debug-query-block-graph')['return'] 14648057fc2SMax Reitz for edge in graph['edges']: 14748057fc2SMax Reitz if edge['name'] == 'backing' and \ 14848057fc2SMax Reitz find_graph_node(graph, edge['parent'])['name'] == 'node3': 14948057fc2SMax Reitz assert find_graph_node(graph, edge['child'])['name'] == 'node0' 15048057fc2SMax Reitz break 15148057fc2SMax Reitz 15248057fc2SMax Reitz 15348057fc2SMax Reitzdef main(): 15448057fc2SMax Reitz log('Running tests:') 15548057fc2SMax Reitz test_concurrent_finish(True) 15648057fc2SMax Reitz test_concurrent_finish(False) 15748057fc2SMax Reitz 15848057fc2SMax Reitzif __name__ == '__main__': 1595e089febSJohn Snow # Need backing file and change-backing-file support 1605e089febSJohn Snow iotests.script_main(main, 1615e089febSJohn Snow supported_fmts=['qcow2', 'qed'], 1625e089febSJohn Snow supported_platforms=['linux']) 163