qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

iotests: Add test for concurrent stream/commit

We already have 030 for that in general, but this tests very specific
cases of both jobs finishing concurrently.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>

authored by

Max Reitz and committed by
Kevin Wolf
48057fc2 0513f984

+197
+163
tests/qemu-iotests/258
··· 1 + #!/usr/bin/env python 2 + # 3 + # Very specific tests for adjacent commit/stream block jobs 4 + # 5 + # Copyright (C) 2019 Red Hat, Inc. 6 + # 7 + # This program is free software; you can redistribute it and/or modify 8 + # it under the terms of the GNU General Public License as published by 9 + # the Free Software Foundation; either version 2 of the License, or 10 + # (at your option) any later version. 11 + # 12 + # This program is distributed in the hope that it will be useful, 13 + # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + # GNU General Public License for more details. 16 + # 17 + # You should have received a copy of the GNU General Public License 18 + # along with this program. If not, see <http://www.gnu.org/licenses/>. 19 + # 20 + # Creator/Owner: Max Reitz <mreitz@redhat.com> 21 + 22 + import iotests 23 + from iotests import log, qemu_img, qemu_io_silent, \ 24 + filter_qmp_testfiles, filter_qmp_imgfmt 25 + 26 + # Need backing file and change-backing-file support 27 + iotests.verify_image_format(supported_fmts=['qcow2', 'qed']) 28 + iotests.verify_platform(['linux']) 29 + 30 + 31 + # Returns a node for blockdev-add 32 + def node(node_name, path, backing=None, fmt=None, throttle=None): 33 + if fmt is None: 34 + fmt = iotests.imgfmt 35 + 36 + res = { 37 + 'node-name': node_name, 38 + 'driver': fmt, 39 + 'file': { 40 + 'driver': 'file', 41 + 'filename': path 42 + } 43 + } 44 + 45 + if backing is not None: 46 + res['backing'] = backing 47 + 48 + if throttle: 49 + res['file'] = { 50 + 'driver': 'throttle', 51 + 'throttle-group': throttle, 52 + 'file': res['file'] 53 + } 54 + 55 + return res 56 + 57 + # Finds a node in the debug block graph 58 + def find_graph_node(graph, node_id): 59 + return next(node for node in graph['nodes'] if node['id'] == node_id) 60 + 61 + 62 + def test_concurrent_finish(write_to_stream_node): 63 + log('') 64 + log('=== Commit and stream finish concurrently (letting %s write) ===' % \ 65 + ('stream' if write_to_stream_node else 'commit')) 66 + log('') 67 + 68 + # All chosen in such a way that when the commit job wants to 69 + # finish, it polls and thus makes stream finish concurrently -- 70 + # and the other way around, depending on whether the commit job 71 + # is finalized before stream completes or not. 72 + 73 + with iotests.FilePath('node4.img') as node4_path, \ 74 + iotests.FilePath('node3.img') as node3_path, \ 75 + iotests.FilePath('node2.img') as node2_path, \ 76 + iotests.FilePath('node1.img') as node1_path, \ 77 + iotests.FilePath('node0.img') as node0_path, \ 78 + iotests.VM() as vm: 79 + 80 + # It is important to use raw for the base layer (so that 81 + # permissions are just handed through to the protocol layer) 82 + assert qemu_img('create', '-f', 'raw', node0_path, '64M') == 0 83 + 84 + stream_throttle=None 85 + commit_throttle=None 86 + 87 + for path in [node1_path, node2_path, node3_path, node4_path]: 88 + assert qemu_img('create', '-f', iotests.imgfmt, path, '64M') == 0 89 + 90 + if write_to_stream_node: 91 + # This is what (most of the time) makes commit finish 92 + # earlier and then pull in stream 93 + assert qemu_io_silent(node2_path, 94 + '-c', 'write %iK 64K' % (65536 - 192), 95 + '-c', 'write %iK 64K' % (65536 - 64)) == 0 96 + 97 + stream_throttle='tg' 98 + else: 99 + # And this makes stream finish earlier 100 + assert qemu_io_silent(node1_path, 101 + '-c', 'write %iK 64K' % (65536 - 64)) == 0 102 + 103 + commit_throttle='tg' 104 + 105 + vm.launch() 106 + 107 + vm.qmp_log('object-add', 108 + qom_type='throttle-group', 109 + id='tg', 110 + props={ 111 + 'x-iops-write': 1, 112 + 'x-iops-write-max': 1 113 + }) 114 + 115 + vm.qmp_log('blockdev-add', 116 + filters=[filter_qmp_testfiles, filter_qmp_imgfmt], 117 + **node('node4', node4_path, throttle=stream_throttle, 118 + backing=node('node3', node3_path, 119 + backing=node('node2', node2_path, 120 + backing=node('node1', node1_path, 121 + backing=node('node0', node0_path, throttle=commit_throttle, 122 + fmt='raw')))))) 123 + 124 + vm.qmp_log('block-commit', 125 + job_id='commit', 126 + device='node4', 127 + filter_node_name='commit-filter', 128 + top_node='node1', 129 + base_node='node0', 130 + auto_finalize=False) 131 + 132 + vm.qmp_log('block-stream', 133 + job_id='stream', 134 + device='node3', 135 + base_node='commit-filter') 136 + 137 + if write_to_stream_node: 138 + vm.run_job('commit', auto_finalize=False, auto_dismiss=True) 139 + vm.run_job('stream', auto_finalize=True, auto_dismiss=True) 140 + else: 141 + # No, the jobs do not really finish concurrently here, 142 + # the stream job does complete strictly before commit. 143 + # But still, this is close enough for what we want to 144 + # test. 145 + vm.run_job('stream', auto_finalize=True, auto_dismiss=True) 146 + vm.run_job('commit', auto_finalize=False, auto_dismiss=True) 147 + 148 + # Assert that the backing node of node3 is node 0 now 149 + graph = vm.qmp('x-debug-query-block-graph')['return'] 150 + for edge in graph['edges']: 151 + if edge['name'] == 'backing' and \ 152 + find_graph_node(graph, edge['parent'])['name'] == 'node3': 153 + assert find_graph_node(graph, edge['child'])['name'] == 'node0' 154 + break 155 + 156 + 157 + def main(): 158 + log('Running tests:') 159 + test_concurrent_finish(True) 160 + test_concurrent_finish(False) 161 + 162 + if __name__ == '__main__': 163 + main()
+33
tests/qemu-iotests/258.out
··· 1 + Running tests: 2 + 3 + === Commit and stream finish concurrently (letting stream write) === 4 + 5 + {"execute": "object-add", "arguments": {"id": "tg", "props": {"x-iops-write": 1, "x-iops-write-max": 1}, "qom-type": "throttle-group"}} 6 + {"return": {}} 7 + {"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"backing": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-node0.img"}, "node-name": "node0"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node1.img"}, "node-name": "node1"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node2.img"}, "node-name": "node2"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node3.img"}, "node-name": "node3"}, "driver": "IMGFMT", "file": {"driver": "throttle", "file": {"driver": "file", "filename": "TEST_DIR/PID-node4.img"}, "throttle-group": "tg"}, "node-name": "node4"}} 8 + {"return": {}} 9 + {"execute": "block-commit", "arguments": {"auto-finalize": false, "base-node": "node0", "device": "node4", "filter-node-name": "commit-filter", "job-id": "commit", "top-node": "node1"}} 10 + {"return": {}} 11 + {"execute": "block-stream", "arguments": {"base-node": "commit-filter", "device": "node3", "job-id": "stream"}} 12 + {"return": {}} 13 + {"execute": "job-finalize", "arguments": {"id": "commit"}} 14 + {"return": {}} 15 + {"data": {"id": "commit", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} 16 + {"data": {"device": "commit", "len": 67108864, "offset": 67108864, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} 17 + {"data": {"device": "stream", "len": 67108864, "offset": 67108864, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} 18 + 19 + === Commit and stream finish concurrently (letting commit write) === 20 + 21 + {"execute": "object-add", "arguments": {"id": "tg", "props": {"x-iops-write": 1, "x-iops-write-max": 1}, "qom-type": "throttle-group"}} 22 + {"return": {}} 23 + {"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"backing": {"driver": "raw", "file": {"driver": "throttle", "file": {"driver": "file", "filename": "TEST_DIR/PID-node0.img"}, "throttle-group": "tg"}, "node-name": "node0"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node1.img"}, "node-name": "node1"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node2.img"}, "node-name": "node2"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node3.img"}, "node-name": "node3"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node4.img"}, "node-name": "node4"}} 24 + {"return": {}} 25 + {"execute": "block-commit", "arguments": {"auto-finalize": false, "base-node": "node0", "device": "node4", "filter-node-name": "commit-filter", "job-id": "commit", "top-node": "node1"}} 26 + {"return": {}} 27 + {"execute": "block-stream", "arguments": {"base-node": "commit-filter", "device": "node3", "job-id": "stream"}} 28 + {"return": {}} 29 + {"data": {"device": "stream", "len": 67108864, "offset": 67108864, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} 30 + {"execute": "job-finalize", "arguments": {"id": "commit"}} 31 + {"return": {}} 32 + {"data": {"id": "commit", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} 33 + {"data": {"device": "commit", "len": 67108864, "offset": 67108864, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+1
tests/qemu-iotests/group
··· 271 271 254 rw backing quick 272 272 255 rw quick 273 273 256 rw quick 274 + 258 rw quick 274 275 262 rw quick migration