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