| #!/usr/bin/env python3 |
| # |
| # Test the rate limit of QMP events |
| # |
| # Copyright (C) 2016 Igalia, S.L. |
| # Author: Alberto Garcia <berto@igalia.com> |
| # |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 2 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| # |
| |
| import os |
| import iotests |
| |
| imgs = (os.path.join(iotests.test_dir, 'quorum0.img'), |
| os.path.join(iotests.test_dir, 'quorum1.img'), |
| os.path.join(iotests.test_dir, 'quorum2.img')) |
| |
| img_conf = (os.path.join(iotests.test_dir, 'quorum0.conf'), |
| os.path.join(iotests.test_dir, 'quorum1.conf'), |
| os.path.join(iotests.test_dir, 'quorum2.conf')) |
| |
| event_rate = 1000000000 |
| sector_size = 512 |
| offset = 10 |
| |
| class TestQuorumEvents(iotests.QMPTestCase): |
| read_pattern = 'quorum' |
| |
| def create_blkdebug_file(self, blkdebug_file, bad_sector): |
| file = open(blkdebug_file, 'w') |
| file.write(''' |
| [inject-error] |
| event = "read_aio" |
| errno = "5" |
| sector = "%d" |
| ''' % bad_sector) |
| file.close() |
| |
| @iotests.skip_if_unsupported(['quorum']) |
| def setUp(self): |
| driveopts = ['driver=quorum', 'vote-threshold=2'] |
| driveopts.append('read-pattern=%s' % self.read_pattern) |
| for i in range(len(imgs)): |
| iotests.qemu_img('create', '-f', iotests.imgfmt, imgs[i], '1M') |
| self.create_blkdebug_file(img_conf[i], i + offset) |
| driveopts.append('children.%d.driver=%s' % (i, iotests.imgfmt)) |
| driveopts.append('children.%d.file.driver=blkdebug' % i) |
| driveopts.append('children.%d.file.config=%s' % (i, img_conf[i])) |
| driveopts.append('children.%d.file.image.filename=%s' % (i, imgs[i])) |
| driveopts.append('children.%d.node-name=img%d' % (i, i)) |
| self.vm = iotests.VM() |
| self.vm.add_drive(None, opts = ','.join(driveopts)) |
| self.vm.launch() |
| |
| def tearDown(self): |
| self.vm.shutdown() |
| for i in range(len(imgs)): |
| os.remove(imgs[i]) |
| os.remove(img_conf[i]) |
| |
| def do_check_event(self, node, sector = 0): |
| if node == None: |
| self.assertEqual(self.vm.get_qmp_event(), None) |
| return |
| |
| for event in self.vm.get_qmp_events(wait=True): |
| if event['event'] == 'QUORUM_REPORT_BAD': |
| self.assert_qmp(event, 'data/node-name', node) |
| self.assert_qmp(event, 'data/sector-num', sector) |
| |
| def testQuorum(self): |
| # Generate an error and get an event |
| self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % |
| (offset * sector_size, sector_size)) |
| self.vm.qtest("clock_step 10") |
| self.do_check_event('img0', offset) |
| |
| # I/O errors in the same child: only one event is emitted |
| delay = 10 |
| for i in range(3): |
| self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % |
| (offset * sector_size, sector_size)) |
| self.vm.qtest("clock_step %d" % delay) |
| self.do_check_event(None) |
| |
| # Wait enough so the event is finally emitted |
| self.vm.qtest("clock_step %d" % (2 * event_rate)) |
| self.do_check_event('img0', offset) |
| |
| # I/O errors in the same child: all events are emitted |
| delay = 2 * event_rate |
| for i in range(3): |
| self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % |
| (offset * sector_size, sector_size)) |
| self.vm.qtest("clock_step %d" % delay) |
| self.do_check_event('img0', offset) |
| |
| # I/O errors in different children: all events are emitted |
| delay = 10 |
| for i in range(len(imgs)): |
| self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % |
| ((offset + i) * sector_size, sector_size)) |
| self.vm.qtest("clock_step %d" % delay) |
| # In fifo mode only errors in the first child are detected |
| if i > 0 and self.read_pattern == 'fifo': |
| self.do_check_event(None) |
| else: |
| self.do_check_event('img%d' % i, offset + i) |
| |
| # I/O errors in different children: all events are emitted |
| delay = 2 * event_rate |
| for i in range(len(imgs)): |
| self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % |
| ((offset + i) * sector_size, sector_size)) |
| self.vm.qtest("clock_step %d" % delay) |
| # In fifo mode only errors in the first child are detected |
| if i > 0 and self.read_pattern == 'fifo': |
| self.do_check_event(None) |
| else: |
| self.do_check_event('img%d' % i, offset + i) |
| |
| # No more pending events |
| self.do_check_event(None) |
| |
| class TestFifoQuorumEvents(TestQuorumEvents): |
| read_pattern = 'fifo' |
| |
| if __name__ == '__main__': |
| iotests.verify_quorum() |
| iotests.main(supported_fmts=["raw"], |
| supported_protocols=["file"]) |