cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

258 (5870B)


      1#!/usr/bin/env python3
      2# group: rw quick
      3#
      4# Very specific tests for adjacent commit/stream block jobs
      5#
      6# Copyright (C) 2019 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# Creator/Owner: Max Reitz <mreitz@redhat.com>
     22
     23import iotests
     24from iotests import log, qemu_img, qemu_io_silent, \
     25        filter_qmp_testfiles, filter_qmp_imgfmt
     26
     27# Returns a node for blockdev-add
     28def node(node_name, path, backing=None, fmt=None, throttle=None):
     29    if fmt is None:
     30        fmt = iotests.imgfmt
     31
     32    res = {
     33        'node-name': node_name,
     34        'driver': fmt,
     35        'file': {
     36            'driver': 'file',
     37            'filename': path
     38        }
     39    }
     40
     41    if backing is not None:
     42        res['backing'] = backing
     43
     44    if throttle:
     45        res['file'] = {
     46            'driver': 'throttle',
     47            'throttle-group': throttle,
     48            'file': res['file']
     49        }
     50
     51    return res
     52
     53# Finds a node in the debug block graph
     54def find_graph_node(graph, node_id):
     55    return next(node for node in graph['nodes'] if node['id'] == node_id)
     56
     57
     58def test_concurrent_finish(write_to_stream_node):
     59    log('')
     60    log('=== Commit and stream finish concurrently (letting %s write) ===' % \
     61        ('stream' if write_to_stream_node else 'commit'))
     62    log('')
     63
     64    # All chosen in such a way that when the commit job wants to
     65    # finish, it polls and thus makes stream finish concurrently --
     66    # and the other way around, depending on whether the commit job
     67    # is finalized before stream completes or not.
     68
     69    with iotests.FilePath('node4.img') as node4_path, \
     70         iotests.FilePath('node3.img') as node3_path, \
     71         iotests.FilePath('node2.img') as node2_path, \
     72         iotests.FilePath('node1.img') as node1_path, \
     73         iotests.FilePath('node0.img') as node0_path, \
     74         iotests.VM() as vm:
     75
     76        # It is important to use raw for the base layer (so that
     77        # permissions are just handed through to the protocol layer)
     78        assert qemu_img('create', '-f', 'raw', node0_path, '64M') == 0
     79
     80        stream_throttle=None
     81        commit_throttle=None
     82
     83        for path in [node1_path, node2_path, node3_path, node4_path]:
     84            assert qemu_img('create', '-f', iotests.imgfmt, path, '64M') == 0
     85
     86        if write_to_stream_node:
     87            # This is what (most of the time) makes commit finish
     88            # earlier and then pull in stream
     89            assert qemu_io_silent(node2_path,
     90                                  '-c', 'write %iK 64K' % (65536 - 192),
     91                                  '-c', 'write %iK 64K' % (65536 -  64)) == 0
     92
     93            stream_throttle='tg'
     94        else:
     95            # And this makes stream finish earlier
     96            assert qemu_io_silent(node1_path,
     97                                  '-c', 'write %iK 64K' % (65536 - 64)) == 0
     98
     99            commit_throttle='tg'
    100
    101        vm.launch()
    102
    103        vm.qmp_log('object-add',
    104                   qom_type='throttle-group',
    105                   id='tg',
    106                   limits={
    107                       'iops-write': 1,
    108                       'iops-write-max': 1
    109                   })
    110
    111        vm.qmp_log('blockdev-add',
    112                   filters=[filter_qmp_testfiles, filter_qmp_imgfmt],
    113                   **node('node4', node4_path, throttle=stream_throttle,
    114                     backing=node('node3', node3_path,
    115                     backing=node('node2', node2_path,
    116                     backing=node('node1', node1_path,
    117                     backing=node('node0', node0_path, throttle=commit_throttle,
    118                                  fmt='raw'))))))
    119
    120        vm.qmp_log('block-commit',
    121                   job_id='commit',
    122                   device='node4',
    123                   filter_node_name='commit-filter',
    124                   top_node='node1',
    125                   base_node='node0',
    126                   auto_finalize=False)
    127
    128        vm.qmp_log('block-stream',
    129                   job_id='stream',
    130                   device='node3',
    131                   base_node='commit-filter')
    132
    133        if write_to_stream_node:
    134            vm.run_job('commit', auto_finalize=False, auto_dismiss=True)
    135            vm.run_job('stream', auto_finalize=True, auto_dismiss=True)
    136        else:
    137            # No, the jobs do not really finish concurrently here,
    138            # the stream job does complete strictly before commit.
    139            # But still, this is close enough for what we want to
    140            # test.
    141            vm.run_job('stream', auto_finalize=True, auto_dismiss=True)
    142            vm.run_job('commit', auto_finalize=False, auto_dismiss=True)
    143
    144        # Assert that the backing node of node3 is node 0 now
    145        graph = vm.qmp('x-debug-query-block-graph')['return']
    146        for edge in graph['edges']:
    147            if edge['name'] == 'backing' and \
    148               find_graph_node(graph, edge['parent'])['name'] == 'node3':
    149                assert find_graph_node(graph, edge['child'])['name'] == 'node0'
    150                break
    151
    152
    153def main():
    154    log('Running tests:')
    155    test_concurrent_finish(True)
    156    test_concurrent_finish(False)
    157
    158if __name__ == '__main__':
    159    # Need backing file and change-backing-file support
    160    iotests.script_main(main,
    161                        supported_fmts=['qcow2', 'qed'],
    162                        supported_platforms=['linux'])