| #!/usr/bin/env python3 | |
| # group: rw quick | |
| # | |
| # 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"]) |