]>
Commit | Line | Data |
---|---|---|
7223c48c AG |
1 | #!/usr/bin/env python |
2 | # | |
3 | # Test the rate limit of QMP events | |
4 | # | |
5 | # Copyright (C) 2016 Igalia, S.L. | |
6 | # Author: Alberto Garcia <[email protected]> | |
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 | ||
22 | import os | |
23 | import iotests | |
24 | ||
25 | imgs = (os.path.join(iotests.test_dir, 'quorum0.img'), | |
26 | os.path.join(iotests.test_dir, 'quorum1.img'), | |
27 | os.path.join(iotests.test_dir, 'quorum2.img')) | |
28 | ||
29 | img_conf = (os.path.join(iotests.test_dir, 'quorum0.conf'), | |
30 | os.path.join(iotests.test_dir, 'quorum1.conf'), | |
31 | os.path.join(iotests.test_dir, 'quorum2.conf')) | |
32 | ||
33 | event_rate = 1000000000 | |
34 | sector_size = 512 | |
35 | offset = 10 | |
36 | ||
37 | class TestQuorumEvents(iotests.QMPTestCase): | |
509565f3 | 38 | read_pattern = 'quorum' |
7223c48c AG |
39 | |
40 | def create_blkdebug_file(self, blkdebug_file, bad_sector): | |
41 | file = open(blkdebug_file, 'w') | |
42 | file.write(''' | |
43 | [inject-error] | |
44 | event = "read_aio" | |
45 | errno = "5" | |
46 | sector = "%d" | |
47 | ''' % bad_sector) | |
48 | file.close() | |
49 | ||
50 | def setUp(self): | |
51 | driveopts = ['driver=quorum', 'vote-threshold=2'] | |
509565f3 | 52 | driveopts.append('read-pattern=%s' % self.read_pattern) |
7223c48c AG |
53 | for i in range(len(imgs)): |
54 | iotests.qemu_img('create', '-f', iotests.imgfmt, imgs[i], '1M') | |
55 | self.create_blkdebug_file(img_conf[i], i + offset) | |
56 | driveopts.append('children.%d.driver=%s' % (i, iotests.imgfmt)) | |
57 | driveopts.append('children.%d.file.driver=blkdebug' % i) | |
58 | driveopts.append('children.%d.file.config=%s' % (i, img_conf[i])) | |
59 | driveopts.append('children.%d.file.image.filename=%s' % (i, imgs[i])) | |
60 | driveopts.append('children.%d.node-name=img%d' % (i, i)) | |
61 | self.vm = iotests.VM() | |
62 | self.vm.add_drive(None, opts = ','.join(driveopts)) | |
63 | self.vm.launch() | |
64 | ||
65 | def tearDown(self): | |
66 | self.vm.shutdown() | |
67 | for i in range(len(imgs)): | |
68 | os.remove(imgs[i]) | |
69 | os.remove(img_conf[i]) | |
70 | ||
71 | def do_check_event(self, node, sector = 0): | |
72 | if node == None: | |
73 | self.assertEqual(self.vm.get_qmp_event(), None) | |
74 | return | |
75 | ||
76 | for event in self.vm.get_qmp_events(wait=True): | |
77 | if event['event'] == 'QUORUM_REPORT_BAD': | |
78 | self.assert_qmp(event, 'data/node-name', node) | |
79 | self.assert_qmp(event, 'data/sector-num', sector) | |
80 | ||
81 | def testQuorum(self): | |
7223c48c AG |
82 | # Generate an error and get an event |
83 | self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % | |
84 | (offset * sector_size, sector_size)) | |
85 | self.vm.qtest("clock_step 10") | |
86 | self.do_check_event('img0', offset) | |
87 | ||
88 | # I/O errors in the same child: only one event is emitted | |
89 | delay = 10 | |
90 | for i in range(3): | |
91 | self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % | |
92 | (offset * sector_size, sector_size)) | |
93 | self.vm.qtest("clock_step %d" % delay) | |
94 | self.do_check_event(None) | |
95 | ||
96 | # Wait enough so the event is finally emitted | |
97 | self.vm.qtest("clock_step %d" % (2 * event_rate)) | |
98 | self.do_check_event('img0', offset) | |
99 | ||
100 | # I/O errors in the same child: all events are emitted | |
101 | delay = 2 * event_rate | |
102 | for i in range(3): | |
103 | self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % | |
104 | (offset * sector_size, sector_size)) | |
105 | self.vm.qtest("clock_step %d" % delay) | |
106 | self.do_check_event('img0', offset) | |
107 | ||
108 | # I/O errors in different children: all events are emitted | |
109 | delay = 10 | |
110 | for i in range(len(imgs)): | |
111 | self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % | |
112 | ((offset + i) * sector_size, sector_size)) | |
113 | self.vm.qtest("clock_step %d" % delay) | |
509565f3 AG |
114 | # In fifo mode only errors in the first child are detected |
115 | if i > 0 and self.read_pattern == 'fifo': | |
116 | self.do_check_event(None) | |
117 | else: | |
118 | self.do_check_event('img%d' % i, offset + i) | |
7223c48c AG |
119 | |
120 | # I/O errors in different children: all events are emitted | |
121 | delay = 2 * event_rate | |
122 | for i in range(len(imgs)): | |
123 | self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % | |
124 | ((offset + i) * sector_size, sector_size)) | |
125 | self.vm.qtest("clock_step %d" % delay) | |
509565f3 AG |
126 | # In fifo mode only errors in the first child are detected |
127 | if i > 0 and self.read_pattern == 'fifo': | |
128 | self.do_check_event(None) | |
129 | else: | |
130 | self.do_check_event('img%d' % i, offset + i) | |
7223c48c AG |
131 | |
132 | # No more pending events | |
133 | self.do_check_event(None) | |
134 | ||
509565f3 AG |
135 | class TestFifoQuorumEvents(TestQuorumEvents): |
136 | read_pattern = 'fifo' | |
137 | ||
7223c48c | 138 | if __name__ == '__main__': |
3f647b51 | 139 | iotests.verify_quorum() |
7223c48c | 140 | iotests.main(supported_fmts=["raw"]) |