1903cb1bfSPhilippe Mathieu-Daudé#!/usr/bin/env python3 29dd003a9SVladimir 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# 2142a5009dSJohn Snow# Creator/Owner: Hanna Reitz <hreitz@redhat.com> 2248057fc2SMax Reitz 2348057fc2SMax Reitzimport iotests 24*72cfb937SJohn Snowfrom iotests import log, qemu_img, qemu_io, \ 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) 78fc272d3cSJohn Snow qemu_img('create', '-f', 'raw', node0_path, '64M') 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]: 84fc272d3cSJohn Snow qemu_img('create', '-f', iotests.imgfmt, path, '64M') 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 89*72cfb937SJohn Snow qemu_io(node2_path, 9048057fc2SMax Reitz '-c', 'write %iK 64K' % (65536 - 192), 91*72cfb937SJohn Snow '-c', 'write %iK 64K' % (65536 - 64)) 9248057fc2SMax Reitz 9348057fc2SMax Reitz stream_throttle='tg' 9448057fc2SMax Reitz else: 9548057fc2SMax Reitz # And this makes stream finish earlier 96*72cfb937SJohn Snow qemu_io(node1_path, '-c', 'write %iK 64K' % (65536 - 64)) 9748057fc2SMax Reitz 9848057fc2SMax Reitz commit_throttle='tg' 9948057fc2SMax Reitz 10048057fc2SMax Reitz vm.launch() 10148057fc2SMax Reitz 10248057fc2SMax Reitz vm.qmp_log('object-add', 10348057fc2SMax Reitz qom_type='throttle-group', 10448057fc2SMax Reitz id='tg', 105fa818b2fSAlberto Garcia limits={ 106fa818b2fSAlberto Garcia 'iops-write': 1, 107fa818b2fSAlberto Garcia 'iops-write-max': 1 10848057fc2SMax Reitz }) 10948057fc2SMax Reitz 11048057fc2SMax Reitz vm.qmp_log('blockdev-add', 11148057fc2SMax Reitz filters=[filter_qmp_testfiles, filter_qmp_imgfmt], 11248057fc2SMax Reitz **node('node4', node4_path, throttle=stream_throttle, 11348057fc2SMax Reitz backing=node('node3', node3_path, 11448057fc2SMax Reitz backing=node('node2', node2_path, 11548057fc2SMax Reitz backing=node('node1', node1_path, 11648057fc2SMax Reitz backing=node('node0', node0_path, throttle=commit_throttle, 11748057fc2SMax Reitz fmt='raw')))))) 11848057fc2SMax Reitz 11948057fc2SMax Reitz vm.qmp_log('block-commit', 12048057fc2SMax Reitz job_id='commit', 12148057fc2SMax Reitz device='node4', 12248057fc2SMax Reitz filter_node_name='commit-filter', 12348057fc2SMax Reitz top_node='node1', 12448057fc2SMax Reitz base_node='node0', 12548057fc2SMax Reitz auto_finalize=False) 12648057fc2SMax Reitz 12748057fc2SMax Reitz vm.qmp_log('block-stream', 12848057fc2SMax Reitz job_id='stream', 12948057fc2SMax Reitz device='node3', 13048057fc2SMax Reitz base_node='commit-filter') 13148057fc2SMax Reitz 13248057fc2SMax Reitz if write_to_stream_node: 13348057fc2SMax Reitz vm.run_job('commit', auto_finalize=False, auto_dismiss=True) 13448057fc2SMax Reitz vm.run_job('stream', auto_finalize=True, auto_dismiss=True) 13548057fc2SMax Reitz else: 13648057fc2SMax Reitz # No, the jobs do not really finish concurrently here, 13748057fc2SMax Reitz # the stream job does complete strictly before commit. 13848057fc2SMax Reitz # But still, this is close enough for what we want to 13948057fc2SMax Reitz # test. 14048057fc2SMax Reitz vm.run_job('stream', auto_finalize=True, auto_dismiss=True) 14148057fc2SMax Reitz vm.run_job('commit', auto_finalize=False, auto_dismiss=True) 14248057fc2SMax Reitz 14348057fc2SMax Reitz # Assert that the backing node of node3 is node 0 now 14448057fc2SMax Reitz graph = vm.qmp('x-debug-query-block-graph')['return'] 14548057fc2SMax Reitz for edge in graph['edges']: 14648057fc2SMax Reitz if edge['name'] == 'backing' and \ 14748057fc2SMax Reitz find_graph_node(graph, edge['parent'])['name'] == 'node3': 14848057fc2SMax Reitz assert find_graph_node(graph, edge['child'])['name'] == 'node0' 14948057fc2SMax Reitz break 15048057fc2SMax Reitz 15148057fc2SMax Reitz 15248057fc2SMax Reitzdef main(): 15348057fc2SMax Reitz log('Running tests:') 15448057fc2SMax Reitz test_concurrent_finish(True) 15548057fc2SMax Reitz test_concurrent_finish(False) 15648057fc2SMax Reitz 15748057fc2SMax Reitzif __name__ == '__main__': 1585e089febSJohn Snow # Need backing file and change-backing-file support 1595e089febSJohn Snow iotests.script_main(main, 1605e089febSJohn Snow supported_fmts=['qcow2', 'qed'], 1615e089febSJohn Snow supported_platforms=['linux']) 162