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

151 (8073B)


      1#!/usr/bin/env python3
      2# group: rw
      3#
      4# Tests for active mirroring
      5#
      6# Copyright (C) 2018 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
     22import os
     23import iotests
     24from iotests import qemu_img
     25
     26source_img = os.path.join(iotests.test_dir, 'source.' + iotests.imgfmt)
     27target_img = os.path.join(iotests.test_dir, 'target.' + iotests.imgfmt)
     28
     29class TestActiveMirror(iotests.QMPTestCase):
     30    image_len = 128 * 1024 * 1024 # MB
     31    potential_writes_in_flight = True
     32
     33    def setUp(self):
     34        qemu_img('create', '-f', iotests.imgfmt, source_img, '128M')
     35        qemu_img('create', '-f', iotests.imgfmt, target_img, '128M')
     36
     37        blk_source = {'id': 'source',
     38                      'if': 'none',
     39                      'node-name': 'source-node',
     40                      'driver': iotests.imgfmt,
     41                      'file': {'driver': 'blkdebug',
     42                               'image': {'driver': 'file',
     43                                         'filename': source_img}}}
     44
     45        blk_target = {'node-name': 'target-node',
     46                      'driver': iotests.imgfmt,
     47                      'file': {'driver': 'file',
     48                               'filename': target_img}}
     49
     50        self.vm = iotests.VM()
     51        self.vm.add_drive_raw(self.vm.qmp_to_opts(blk_source))
     52        self.vm.add_blockdev(self.vm.qmp_to_opts(blk_target))
     53        self.vm.add_device('virtio-blk,drive=source')
     54        self.vm.launch()
     55
     56    def tearDown(self):
     57        self.vm.shutdown()
     58
     59        if not self.potential_writes_in_flight:
     60            self.assertTrue(iotests.compare_images(source_img, target_img),
     61                            'mirror target does not match source')
     62
     63        os.remove(source_img)
     64        os.remove(target_img)
     65
     66    def doActiveIO(self, sync_source_and_target):
     67        # Fill the source image
     68        self.vm.hmp_qemu_io('source',
     69                            'write -P 1 0 %i' % self.image_len);
     70
     71        # Start some background requests
     72        for offset in range(1 * self.image_len // 8, 3 * self.image_len // 8, 1024 * 1024):
     73            self.vm.hmp_qemu_io('source', 'aio_write -P 2 %i 1M' % offset)
     74        for offset in range(2 * self.image_len // 8, 3 * self.image_len // 8, 1024 * 1024):
     75            self.vm.hmp_qemu_io('source', 'aio_write -z %i 1M' % offset)
     76
     77        # Start the block job
     78        result = self.vm.qmp('blockdev-mirror',
     79                             job_id='mirror',
     80                             filter_node_name='mirror-node',
     81                             device='source-node',
     82                             target='target-node',
     83                             sync='full',
     84                             copy_mode='write-blocking')
     85        self.assert_qmp(result, 'return', {})
     86
     87        # Start some more requests
     88        for offset in range(3 * self.image_len // 8, 5 * self.image_len // 8, 1024 * 1024):
     89            self.vm.hmp_qemu_io('source', 'aio_write -P 3 %i 1M' % offset)
     90        for offset in range(4 * self.image_len // 8, 5 * self.image_len // 8, 1024 * 1024):
     91            self.vm.hmp_qemu_io('source', 'aio_write -z %i 1M' % offset)
     92
     93        # Wait for the READY event
     94        self.wait_ready(drive='mirror')
     95
     96        # Now start some final requests; all of these (which land on
     97        # the source) should be settled using the active mechanism.
     98        # The mirror code itself asserts that the source BDS's dirty
     99        # bitmap will stay clean between READY and COMPLETED.
    100        for offset in range(5 * self.image_len // 8, 7 * self.image_len // 8, 1024 * 1024):
    101            self.vm.hmp_qemu_io('source', 'aio_write -P 3 %i 1M' % offset)
    102        for offset in range(6 * self.image_len // 8, 7 * self.image_len // 8, 1024 * 1024):
    103            self.vm.hmp_qemu_io('source', 'aio_write -z %i 1M' % offset)
    104
    105        if sync_source_and_target:
    106            # If source and target should be in sync after the mirror,
    107            # we have to flush before completion
    108            self.vm.hmp_qemu_io('source', 'aio_flush')
    109            self.potential_writes_in_flight = False
    110
    111        self.complete_and_wait(drive='mirror', wait_ready=False)
    112
    113    def testActiveIO(self):
    114        self.doActiveIO(False)
    115
    116    def testActiveIOFlushed(self):
    117        self.doActiveIO(True)
    118
    119    def testUnalignedActiveIO(self):
    120        # Fill the source image
    121        result = self.vm.hmp_qemu_io('source', 'write -P 1 0 2M')
    122
    123        # Start the block job (very slowly)
    124        result = self.vm.qmp('blockdev-mirror',
    125                             job_id='mirror',
    126                             filter_node_name='mirror-node',
    127                             device='source-node',
    128                             target='target-node',
    129                             sync='full',
    130                             copy_mode='write-blocking',
    131                             buf_size=(1048576 // 4),
    132                             speed=1)
    133        self.assert_qmp(result, 'return', {})
    134
    135        # Start an unaligned request to a dirty area
    136        result = self.vm.hmp_qemu_io('source', 'write -P 2 %i 1' % (1048576 + 42))
    137
    138        # Let the job finish
    139        result = self.vm.qmp('block-job-set-speed', device='mirror', speed=0)
    140        self.assert_qmp(result, 'return', {})
    141        self.complete_and_wait(drive='mirror')
    142
    143        self.potential_writes_in_flight = False
    144
    145    def testIntersectingActiveIO(self):
    146        # Fill the source image
    147        result = self.vm.hmp_qemu_io('source', 'write -P 1 0 2M')
    148
    149        # Start the block job (very slowly)
    150        result = self.vm.qmp('blockdev-mirror',
    151                             job_id='mirror',
    152                             filter_node_name='mirror-node',
    153                             device='source-node',
    154                             target='target-node',
    155                             sync='full',
    156                             copy_mode='write-blocking',
    157                             speed=1)
    158
    159        self.vm.hmp_qemu_io('source', 'break write_aio A')
    160        self.vm.hmp_qemu_io('source', 'aio_write 0 1M')  # 1
    161        self.vm.hmp_qemu_io('source', 'wait_break A')
    162        self.vm.hmp_qemu_io('source', 'aio_write 0 2M')  # 2
    163        self.vm.hmp_qemu_io('source', 'aio_write 0 2M')  # 3
    164
    165        # Now 2 and 3 are in mirror_wait_on_conflicts, waiting for 1
    166
    167        self.vm.hmp_qemu_io('source', 'break write_aio B')
    168        self.vm.hmp_qemu_io('source', 'aio_write 1M 2M')  # 4
    169        self.vm.hmp_qemu_io('source', 'wait_break B')
    170
    171        # 4 doesn't wait for 2 and 3, because they didn't yet set
    172        # in_flight_bitmap. So, nothing prevents 4 to go except for our
    173        # break-point B.
    174
    175        self.vm.hmp_qemu_io('source', 'resume A')
    176
    177        # Now we resumed 1, so 2 and 3 goes to the next iteration of while loop
    178        # in mirror_wait_on_conflicts(). They don't exit, as bitmap is dirty
    179        # due to request 4.
    180        # In the past at that point 2 and 3 would wait for each other producing
    181        # a dead-lock. Now this is fixed and they will wait for request 4.
    182
    183        self.vm.hmp_qemu_io('source', 'resume B')
    184
    185        # After resuming 4, one of 2 and 3 goes first and set in_flight_bitmap,
    186        # so the other will wait for it.
    187
    188        result = self.vm.qmp('block-job-set-speed', device='mirror', speed=0)
    189        self.assert_qmp(result, 'return', {})
    190        self.complete_and_wait(drive='mirror')
    191
    192        self.potential_writes_in_flight = False
    193
    194
    195if __name__ == '__main__':
    196    iotests.main(supported_fmts=['qcow2', 'raw'],
    197                 supported_protocols=['file'])