1903cb1bfSPhilippe Mathieu-Daudé#!/usr/bin/env python3 29dd003a9SVladimir Sementsov-Ogievskiy# group: throttle 3fb13bbf2SFam Zheng# 4fb13bbf2SFam Zheng# Tests for IO throttling 5fb13bbf2SFam Zheng# 6fb13bbf2SFam Zheng# Copyright (C) 2015 Red Hat, Inc. 7a90cade0SAlberto Garcia# Copyright (C) 2015-2016 Igalia, S.L. 8fb13bbf2SFam Zheng# 9fb13bbf2SFam Zheng# This program is free software; you can redistribute it and/or modify 10fb13bbf2SFam Zheng# it under the terms of the GNU General Public License as published by 11fb13bbf2SFam Zheng# the Free Software Foundation; either version 2 of the License, or 12fb13bbf2SFam Zheng# (at your option) any later version. 13fb13bbf2SFam Zheng# 14fb13bbf2SFam Zheng# This program is distributed in the hope that it will be useful, 15fb13bbf2SFam Zheng# but WITHOUT ANY WARRANTY; without even the implied warranty of 16fb13bbf2SFam Zheng# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17fb13bbf2SFam Zheng# GNU General Public License for more details. 18fb13bbf2SFam Zheng# 19fb13bbf2SFam Zheng# You should have received a copy of the GNU General Public License 20fb13bbf2SFam Zheng# along with this program. If not, see <http://www.gnu.org/licenses/>. 21fb13bbf2SFam Zheng# 22fb13bbf2SFam Zheng 23fb13bbf2SFam Zhengimport iotests 24fb13bbf2SFam Zheng 25a90cade0SAlberto Garciansec_per_sec = 1000000000 26a90cade0SAlberto Garcia 27fb13bbf2SFam Zhengclass ThrottleTestCase(iotests.QMPTestCase): 28a377dd51SMax Reitz test_driver = "null-aio" 292db33f88SAlberto Garcia max_drives = 3 30fb13bbf2SFam Zheng 31fb13bbf2SFam Zheng def blockstats(self, device): 32fb13bbf2SFam Zheng result = self.vm.qmp("query-blockstats") 33fb13bbf2SFam Zheng for r in result['return']: 34fb13bbf2SFam Zheng if r['device'] == device: 35fb13bbf2SFam Zheng stat = r['stats'] 36fb13bbf2SFam Zheng return stat['rd_bytes'], stat['rd_operations'], stat['wr_bytes'], stat['wr_operations'] 37fb13bbf2SFam Zheng raise Exception("Device not found for blockstats: %s" % device) 38fb13bbf2SFam Zheng 39a377dd51SMax Reitz def required_drivers(self): 40a377dd51SMax Reitz return [self.test_driver] 41a377dd51SMax Reitz 42a377dd51SMax Reitz @iotests.skip_if_unsupported(required_drivers) 43fb13bbf2SFam Zheng def setUp(self): 442db33f88SAlberto Garcia self.vm = iotests.VM() 452db33f88SAlberto Garcia for i in range(0, self.max_drives): 46a377dd51SMax Reitz self.vm.add_drive(self.test_driver + "://", "file.read-zeroes=on") 47fb13bbf2SFam Zheng self.vm.launch() 48fb13bbf2SFam Zheng 49fb13bbf2SFam Zheng def tearDown(self): 50fb13bbf2SFam Zheng self.vm.shutdown() 51fb13bbf2SFam Zheng 52a90cade0SAlberto Garcia def configure_throttle(self, ndrives, params): 532db33f88SAlberto Garcia params['group'] = 'test' 54fb13bbf2SFam Zheng 552db33f88SAlberto Garcia # Set the I/O throttling parameters to all drives 562db33f88SAlberto Garcia for i in range(0, ndrives): 572db33f88SAlberto Garcia params['device'] = 'drive%d' % i 58fb13bbf2SFam Zheng result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params) 59fb13bbf2SFam Zheng self.assert_qmp(result, 'return', {}) 60fb13bbf2SFam Zheng 61a26ddb43SAlberto Garcia def do_test_throttle(self, ndrives, seconds, params, first_drive = 0): 62a90cade0SAlberto Garcia def check_limit(limit, num): 63a90cade0SAlberto Garcia # IO throttling algorithm is discrete, allow 10% error so the test 64a90cade0SAlberto Garcia # is more robust 65a90cade0SAlberto Garcia return limit == 0 or \ 66a90cade0SAlberto Garcia (num < seconds * limit * 1.1 / ndrives 67a90cade0SAlberto Garcia and num > seconds * limit * 0.9 / ndrives) 68a90cade0SAlberto Garcia 69fb13bbf2SFam Zheng # Set vm clock to a known value 70fb13bbf2SFam Zheng ns = seconds * nsec_per_sec 71fb13bbf2SFam Zheng self.vm.qtest("clock_step %d" % ns) 72fb13bbf2SFam Zheng 73a90cade0SAlberto Garcia # Submit enough requests so the throttling mechanism kicks 74a90cade0SAlberto Garcia # in. The throttled requests won't be executed until we 75a90cade0SAlberto Garcia # advance the virtual clock. 76fb13bbf2SFam Zheng rq_size = 512 779a3a9a63SMax Reitz rd_nr = max(params['bps'] // rq_size // 2, 789a3a9a63SMax Reitz params['bps_rd'] // rq_size, 799a3a9a63SMax Reitz params['iops'] // 2, 80fb13bbf2SFam Zheng params['iops_rd']) 81fb13bbf2SFam Zheng rd_nr *= seconds * 2 829a3a9a63SMax Reitz rd_nr //= ndrives 839a3a9a63SMax Reitz wr_nr = max(params['bps'] // rq_size // 2, 849a3a9a63SMax Reitz params['bps_wr'] // rq_size, 859a3a9a63SMax Reitz params['iops'] // 2, 86fb13bbf2SFam Zheng params['iops_wr']) 87fb13bbf2SFam Zheng wr_nr *= seconds * 2 889a3a9a63SMax Reitz wr_nr //= ndrives 89fb13bbf2SFam Zheng 902db33f88SAlberto Garcia # Send I/O requests to all drives 912db33f88SAlberto Garcia for i in range(rd_nr): 922db33f88SAlberto Garcia for drive in range(0, ndrives): 93a26ddb43SAlberto Garcia idx = first_drive + drive 94a26ddb43SAlberto Garcia self.vm.hmp_qemu_io("drive%d" % idx, "aio_read %d %d" % 952db33f88SAlberto Garcia (i * rq_size, rq_size)) 962db33f88SAlberto Garcia 972db33f88SAlberto Garcia for i in range(wr_nr): 982db33f88SAlberto Garcia for drive in range(0, ndrives): 99a26ddb43SAlberto Garcia idx = first_drive + drive 100a26ddb43SAlberto Garcia self.vm.hmp_qemu_io("drive%d" % idx, "aio_write %d %d" % 1012db33f88SAlberto Garcia (i * rq_size, rq_size)) 1022db33f88SAlberto Garcia 1032db33f88SAlberto Garcia # We'll store the I/O stats for each drive in these arrays 1042db33f88SAlberto Garcia start_rd_bytes = [0] * ndrives 1052db33f88SAlberto Garcia start_rd_iops = [0] * ndrives 1062db33f88SAlberto Garcia start_wr_bytes = [0] * ndrives 1072db33f88SAlberto Garcia start_wr_iops = [0] * ndrives 1082db33f88SAlberto Garcia end_rd_bytes = [0] * ndrives 1092db33f88SAlberto Garcia end_rd_iops = [0] * ndrives 1102db33f88SAlberto Garcia end_wr_bytes = [0] * ndrives 1112db33f88SAlberto Garcia end_wr_iops = [0] * ndrives 1122db33f88SAlberto Garcia 1132db33f88SAlberto Garcia # Read the stats before advancing the clock 1142db33f88SAlberto Garcia for i in range(0, ndrives): 115a26ddb43SAlberto Garcia idx = first_drive + i 1162db33f88SAlberto Garcia start_rd_bytes[i], start_rd_iops[i], start_wr_bytes[i], \ 117a26ddb43SAlberto Garcia start_wr_iops[i] = self.blockstats('drive%d' % idx) 118fb13bbf2SFam Zheng 119fb13bbf2SFam Zheng self.vm.qtest("clock_step %d" % ns) 120fb13bbf2SFam Zheng 1212db33f88SAlberto Garcia # Read the stats after advancing the clock 1222db33f88SAlberto Garcia for i in range(0, ndrives): 123a26ddb43SAlberto Garcia idx = first_drive + i 1242db33f88SAlberto Garcia end_rd_bytes[i], end_rd_iops[i], end_wr_bytes[i], \ 125a26ddb43SAlberto Garcia end_wr_iops[i] = self.blockstats('drive%d' % idx) 1262db33f88SAlberto Garcia 1272db33f88SAlberto Garcia # Check that the I/O is within the limits and evenly distributed 1282db33f88SAlberto Garcia for i in range(0, ndrives): 1292db33f88SAlberto Garcia rd_bytes = end_rd_bytes[i] - start_rd_bytes[i] 1302db33f88SAlberto Garcia rd_iops = end_rd_iops[i] - start_rd_iops[i] 1312db33f88SAlberto Garcia wr_bytes = end_wr_bytes[i] - start_wr_bytes[i] 1322db33f88SAlberto Garcia wr_iops = end_wr_iops[i] - start_wr_iops[i] 133fb13bbf2SFam Zheng 134fb13bbf2SFam Zheng self.assertTrue(check_limit(params['bps'], rd_bytes + wr_bytes)) 135fb13bbf2SFam Zheng self.assertTrue(check_limit(params['bps_rd'], rd_bytes)) 136fb13bbf2SFam Zheng self.assertTrue(check_limit(params['bps_wr'], wr_bytes)) 137fb13bbf2SFam Zheng self.assertTrue(check_limit(params['iops'], rd_iops + wr_iops)) 138fb13bbf2SFam Zheng self.assertTrue(check_limit(params['iops_rd'], rd_iops)) 139fb13bbf2SFam Zheng self.assertTrue(check_limit(params['iops_wr'], wr_iops)) 140fb13bbf2SFam Zheng 141cbaddb25SStefan Hajnoczi # Allow remaining requests to finish. We submitted twice as many to 142cbaddb25SStefan Hajnoczi # ensure the throttle limit is reached. 143cbaddb25SStefan Hajnoczi self.vm.qtest("clock_step %d" % ns) 144cbaddb25SStefan Hajnoczi 145a26ddb43SAlberto Garcia # Connect N drives to a VM and test I/O in all of them 146fb13bbf2SFam Zheng def test_all(self): 147fb13bbf2SFam Zheng params = {"bps": 4096, 148fb13bbf2SFam Zheng "bps_rd": 4096, 149fb13bbf2SFam Zheng "bps_wr": 4096, 150fb13bbf2SFam Zheng "iops": 10, 151fb13bbf2SFam Zheng "iops_rd": 10, 152fb13bbf2SFam Zheng "iops_wr": 10, 153fb13bbf2SFam Zheng } 1542db33f88SAlberto Garcia # Repeat the test with different numbers of drives 1552db33f88SAlberto Garcia for ndrives in range(1, self.max_drives + 1): 156fb13bbf2SFam Zheng # Pick each out of all possible params and test 157fb13bbf2SFam Zheng for tk in params: 158fb13bbf2SFam Zheng limits = dict([(k, 0) for k in params]) 1592db33f88SAlberto Garcia limits[tk] = params[tk] * ndrives 160a90cade0SAlberto Garcia self.configure_throttle(ndrives, limits) 161a90cade0SAlberto Garcia self.do_test_throttle(ndrives, 5, limits) 162a90cade0SAlberto Garcia 163a26ddb43SAlberto Garcia # Connect N drives to a VM and test I/O in just one of them a time 164a26ddb43SAlberto Garcia def test_one(self): 165a26ddb43SAlberto Garcia params = {"bps": 4096, 166a26ddb43SAlberto Garcia "bps_rd": 4096, 167a26ddb43SAlberto Garcia "bps_wr": 4096, 168a26ddb43SAlberto Garcia "iops": 10, 169a26ddb43SAlberto Garcia "iops_rd": 10, 170a26ddb43SAlberto Garcia "iops_wr": 10, 171a26ddb43SAlberto Garcia } 172a26ddb43SAlberto Garcia # Repeat the test for each one of the drives 173a26ddb43SAlberto Garcia for drive in range(0, self.max_drives): 174a26ddb43SAlberto Garcia # Pick each out of all possible params and test 175a26ddb43SAlberto Garcia for tk in params: 176a26ddb43SAlberto Garcia limits = dict([(k, 0) for k in params]) 177a26ddb43SAlberto Garcia limits[tk] = params[tk] * self.max_drives 178a26ddb43SAlberto Garcia self.configure_throttle(self.max_drives, limits) 179a26ddb43SAlberto Garcia self.do_test_throttle(1, 5, limits, drive) 180a26ddb43SAlberto Garcia 181a90cade0SAlberto Garcia def test_burst(self): 182a90cade0SAlberto Garcia params = {"bps": 4096, 183a90cade0SAlberto Garcia "bps_rd": 4096, 184a90cade0SAlberto Garcia "bps_wr": 4096, 185a90cade0SAlberto Garcia "iops": 10, 186a90cade0SAlberto Garcia "iops_rd": 10, 187a90cade0SAlberto Garcia "iops_wr": 10, 188a90cade0SAlberto Garcia } 189a90cade0SAlberto Garcia ndrives = 1 190a90cade0SAlberto Garcia # Pick each out of all possible params and test 191a90cade0SAlberto Garcia for tk in params: 192a90cade0SAlberto Garcia rate = params[tk] * ndrives 193a90cade0SAlberto Garcia burst_rate = rate * 7 194a90cade0SAlberto Garcia burst_length = 4 195a90cade0SAlberto Garcia 196a90cade0SAlberto Garcia # Configure the throttling settings 197a90cade0SAlberto Garcia settings = dict([(k, 0) for k in params]) 198a90cade0SAlberto Garcia settings[tk] = rate 199a90cade0SAlberto Garcia settings['%s_max' % tk] = burst_rate 200a90cade0SAlberto Garcia settings['%s_max_length' % tk] = burst_length 201a90cade0SAlberto Garcia self.configure_throttle(ndrives, settings) 202a90cade0SAlberto Garcia 203a90cade0SAlberto Garcia # Wait for the bucket to empty so we can do bursts 2049a3a9a63SMax Reitz wait_ns = nsec_per_sec * burst_length * burst_rate // rate 205a90cade0SAlberto Garcia self.vm.qtest("clock_step %d" % wait_ns) 206a90cade0SAlberto Garcia 207a90cade0SAlberto Garcia # Test I/O at the max burst rate 208a90cade0SAlberto Garcia limits = dict([(k, 0) for k in params]) 209a90cade0SAlberto Garcia limits[tk] = burst_rate 210a90cade0SAlberto Garcia self.do_test_throttle(ndrives, burst_length, limits) 211a90cade0SAlberto Garcia 212a90cade0SAlberto Garcia # Now test I/O at the normal rate 213a90cade0SAlberto Garcia limits[tk] = rate 2142db33f88SAlberto Garcia self.do_test_throttle(ndrives, 5, limits) 215fb13bbf2SFam Zheng 216ef7a6a3cSAlberto Garcia # Test that removing a drive from a throttle group should not 217ef7a6a3cSAlberto Garcia # affect the remaining members of the group. 218ef7a6a3cSAlberto Garcia # https://bugzilla.redhat.com/show_bug.cgi?id=1535914 219ef7a6a3cSAlberto Garcia def test_remove_group_member(self): 220ef7a6a3cSAlberto Garcia # Create a throttle group with two drives 221ef7a6a3cSAlberto Garcia # and set a 4 KB/s read limit. 222ef7a6a3cSAlberto Garcia params = {"bps": 0, 223ef7a6a3cSAlberto Garcia "bps_rd": 4096, 224ef7a6a3cSAlberto Garcia "bps_wr": 0, 225ef7a6a3cSAlberto Garcia "iops": 0, 226ef7a6a3cSAlberto Garcia "iops_rd": 0, 227ef7a6a3cSAlberto Garcia "iops_wr": 0 } 228ef7a6a3cSAlberto Garcia self.configure_throttle(2, params) 229ef7a6a3cSAlberto Garcia 230ef7a6a3cSAlberto Garcia # Read 4KB from drive0. This is performed immediately. 231ef7a6a3cSAlberto Garcia self.vm.hmp_qemu_io("drive0", "aio_read 0 4096") 232ef7a6a3cSAlberto Garcia 2333db3e9c6SAlberto Garcia # Read 2KB. The I/O limit has been exceeded so this 234ef7a6a3cSAlberto Garcia # request is throttled and a timer is set to wake it up. 2353db3e9c6SAlberto Garcia self.vm.hmp_qemu_io("drive0", "aio_read 0 2048") 236ef7a6a3cSAlberto Garcia 2373db3e9c6SAlberto Garcia # Read 2KB again. We're still over the I/O limit so this is 2383db3e9c6SAlberto Garcia # request is also throttled, but no new timer is set since 2393db3e9c6SAlberto Garcia # there's already one. 2403db3e9c6SAlberto Garcia self.vm.hmp_qemu_io("drive0", "aio_read 0 2048") 2413db3e9c6SAlberto Garcia 2423db3e9c6SAlberto Garcia # Read from drive1. This request is also throttled, and no 2433db3e9c6SAlberto Garcia # timer is set in drive1 because there's already one in 2443db3e9c6SAlberto Garcia # drive0. 245ef7a6a3cSAlberto Garcia self.vm.hmp_qemu_io("drive1", "aio_read 0 4096") 246ef7a6a3cSAlberto Garcia 247ef7a6a3cSAlberto Garcia # At this point only the first 4KB have been read from drive0. 248ef7a6a3cSAlberto Garcia # The other requests are throttled. 249ef7a6a3cSAlberto Garcia self.assertEqual(self.blockstats('drive0')[0], 4096) 250ef7a6a3cSAlberto Garcia self.assertEqual(self.blockstats('drive1')[0], 0) 251ef7a6a3cSAlberto Garcia 252ef7a6a3cSAlberto Garcia # Remove drive0 from the throttle group and disable its I/O limits. 253ef7a6a3cSAlberto Garcia # drive1 remains in the group with a throttled request. 254ef7a6a3cSAlberto Garcia params['bps_rd'] = 0 255ef7a6a3cSAlberto Garcia params['device'] = 'drive0' 256ef7a6a3cSAlberto Garcia result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params) 257ef7a6a3cSAlberto Garcia self.assert_qmp(result, 'return', {}) 258ef7a6a3cSAlberto Garcia 2593db3e9c6SAlberto Garcia # Removing the I/O limits from drive0 drains its two pending requests. 260ef7a6a3cSAlberto Garcia # The read request in drive1 is still throttled. 261ef7a6a3cSAlberto Garcia self.assertEqual(self.blockstats('drive0')[0], 8192) 262ef7a6a3cSAlberto Garcia self.assertEqual(self.blockstats('drive1')[0], 0) 263ef7a6a3cSAlberto Garcia 264ef7a6a3cSAlberto Garcia # Advance the clock 5 seconds. This completes the request in drive1 265ef7a6a3cSAlberto Garcia self.vm.qtest("clock_step %d" % (5 * nsec_per_sec)) 266ef7a6a3cSAlberto Garcia 267ef7a6a3cSAlberto Garcia # Now all requests have been processed. 268ef7a6a3cSAlberto Garcia self.assertEqual(self.blockstats('drive0')[0], 8192) 269ef7a6a3cSAlberto Garcia self.assertEqual(self.blockstats('drive1')[0], 4096) 270ef7a6a3cSAlberto Garcia 271fb13bbf2SFam Zhengclass ThrottleTestCoroutine(ThrottleTestCase): 272a377dd51SMax Reitz test_driver = "null-co" 273fb13bbf2SFam Zheng 274435d5ee6SAlberto Garciaclass ThrottleTestGroupNames(iotests.QMPTestCase): 275435d5ee6SAlberto Garcia max_drives = 3 276435d5ee6SAlberto Garcia 277435d5ee6SAlberto Garcia def setUp(self): 278435d5ee6SAlberto Garcia self.vm = iotests.VM() 279435d5ee6SAlberto Garcia for i in range(0, self.max_drives): 280a6f8f9f8SMax Reitz self.vm.add_drive("null-co://", 281a6862418SAndrey Shinkevich "throttling.iops-total=100,file.read-zeroes=on") 282435d5ee6SAlberto Garcia self.vm.launch() 283435d5ee6SAlberto Garcia 284435d5ee6SAlberto Garcia def tearDown(self): 285435d5ee6SAlberto Garcia self.vm.shutdown() 286435d5ee6SAlberto Garcia 287435d5ee6SAlberto Garcia def set_io_throttle(self, device, params): 288435d5ee6SAlberto Garcia params["device"] = device 289435d5ee6SAlberto Garcia result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params) 290435d5ee6SAlberto Garcia self.assert_qmp(result, 'return', {}) 291435d5ee6SAlberto Garcia 292435d5ee6SAlberto Garcia def verify_name(self, device, name): 293435d5ee6SAlberto Garcia result = self.vm.qmp("query-block") 294435d5ee6SAlberto Garcia for r in result["return"]: 295435d5ee6SAlberto Garcia if r["device"] == device: 296435d5ee6SAlberto Garcia info = r["inserted"] 297435d5ee6SAlberto Garcia if name: 298435d5ee6SAlberto Garcia self.assertEqual(info["group"], name) 299435d5ee6SAlberto Garcia else: 300d7a4228eSEduardo Habkost self.assertFalse('group' in info) 301435d5ee6SAlberto Garcia return 302435d5ee6SAlberto Garcia 303435d5ee6SAlberto Garcia raise Exception("No group information found for '%s'" % device) 304435d5ee6SAlberto Garcia 305435d5ee6SAlberto Garcia def test_group_naming(self): 306435d5ee6SAlberto Garcia params = {"bps": 0, 307435d5ee6SAlberto Garcia "bps_rd": 0, 308435d5ee6SAlberto Garcia "bps_wr": 0, 309435d5ee6SAlberto Garcia "iops": 0, 310435d5ee6SAlberto Garcia "iops_rd": 0, 311435d5ee6SAlberto Garcia "iops_wr": 0} 312435d5ee6SAlberto Garcia 313435d5ee6SAlberto Garcia # Check the drives added using the command line. 314435d5ee6SAlberto Garcia # The default throttling group name is the device name. 315435d5ee6SAlberto Garcia for i in range(self.max_drives): 316435d5ee6SAlberto Garcia devname = "drive%d" % i 317435d5ee6SAlberto Garcia self.verify_name(devname, devname) 318435d5ee6SAlberto Garcia 319435d5ee6SAlberto Garcia # Clear throttling settings => the group name is gone. 320435d5ee6SAlberto Garcia for i in range(self.max_drives): 321435d5ee6SAlberto Garcia devname = "drive%d" % i 322435d5ee6SAlberto Garcia self.set_io_throttle(devname, params) 323435d5ee6SAlberto Garcia self.verify_name(devname, None) 324435d5ee6SAlberto Garcia 325435d5ee6SAlberto Garcia # Set throttling settings using block_set_io_throttle and 326435d5ee6SAlberto Garcia # check the default group names. 327435d5ee6SAlberto Garcia params["iops"] = 10 328435d5ee6SAlberto Garcia for i in range(self.max_drives): 329435d5ee6SAlberto Garcia devname = "drive%d" % i 330435d5ee6SAlberto Garcia self.set_io_throttle(devname, params) 331435d5ee6SAlberto Garcia self.verify_name(devname, devname) 332435d5ee6SAlberto Garcia 333435d5ee6SAlberto Garcia # Set a custom group name for each device 334435d5ee6SAlberto Garcia for i in range(3): 335435d5ee6SAlberto Garcia devname = "drive%d" % i 336435d5ee6SAlberto Garcia groupname = "group%d" % i 337435d5ee6SAlberto Garcia params['group'] = groupname 338435d5ee6SAlberto Garcia self.set_io_throttle(devname, params) 339435d5ee6SAlberto Garcia self.verify_name(devname, groupname) 340435d5ee6SAlberto Garcia 341435d5ee6SAlberto Garcia # Put drive0 in group1 and check that all other devices remain 342435d5ee6SAlberto Garcia # unchanged 343435d5ee6SAlberto Garcia params['group'] = 'group1' 344435d5ee6SAlberto Garcia self.set_io_throttle('drive0', params) 345435d5ee6SAlberto Garcia self.verify_name('drive0', 'group1') 346435d5ee6SAlberto Garcia for i in range(1, self.max_drives): 347435d5ee6SAlberto Garcia devname = "drive%d" % i 348435d5ee6SAlberto Garcia groupname = "group%d" % i 349435d5ee6SAlberto Garcia self.verify_name(devname, groupname) 350435d5ee6SAlberto Garcia 351435d5ee6SAlberto Garcia # Put drive0 in group2 and check that all other devices remain 352435d5ee6SAlberto Garcia # unchanged 353435d5ee6SAlberto Garcia params['group'] = 'group2' 354435d5ee6SAlberto Garcia self.set_io_throttle('drive0', params) 355435d5ee6SAlberto Garcia self.verify_name('drive0', 'group2') 356435d5ee6SAlberto Garcia for i in range(1, self.max_drives): 357435d5ee6SAlberto Garcia devname = "drive%d" % i 358435d5ee6SAlberto Garcia groupname = "group%d" % i 359435d5ee6SAlberto Garcia self.verify_name(devname, groupname) 360435d5ee6SAlberto Garcia 361435d5ee6SAlberto Garcia # Clear throttling settings from drive0 check that all other 362435d5ee6SAlberto Garcia # devices remain unchanged 363435d5ee6SAlberto Garcia params["iops"] = 0 364435d5ee6SAlberto Garcia self.set_io_throttle('drive0', params) 365435d5ee6SAlberto Garcia self.verify_name('drive0', None) 366435d5ee6SAlberto Garcia for i in range(1, self.max_drives): 367435d5ee6SAlberto Garcia devname = "drive%d" % i 368435d5ee6SAlberto Garcia groupname = "group%d" % i 369435d5ee6SAlberto Garcia self.verify_name(devname, groupname) 370435d5ee6SAlberto Garcia 37107615626SAlberto Garciaclass ThrottleTestRemovableMedia(iotests.QMPTestCase): 37207615626SAlberto Garcia def setUp(self): 37307615626SAlberto Garcia self.vm = iotests.VM() 374*22329f0dSLaurent Vivier self.vm.add_device("{},id=virtio-scsi".format('virtio-scsi')) 37507615626SAlberto Garcia self.vm.launch() 37607615626SAlberto Garcia 37707615626SAlberto Garcia def tearDown(self): 37807615626SAlberto Garcia self.vm.shutdown() 37907615626SAlberto Garcia 38007615626SAlberto Garcia def test_removable_media(self): 38107615626SAlberto Garcia # Add a couple of dummy nodes named cd0 and cd1 382a6f8f9f8SMax Reitz result = self.vm.qmp("blockdev-add", driver="null-co", 383a6862418SAndrey Shinkevich read_zeroes=True, node_name="cd0") 38407615626SAlberto Garcia self.assert_qmp(result, 'return', {}) 385a6f8f9f8SMax Reitz result = self.vm.qmp("blockdev-add", driver="null-co", 386a6862418SAndrey Shinkevich read_zeroes=True, node_name="cd1") 38707615626SAlberto Garcia self.assert_qmp(result, 'return', {}) 38807615626SAlberto Garcia 38907615626SAlberto Garcia # Attach a CD drive with cd0 inserted 39007615626SAlberto Garcia result = self.vm.qmp("device_add", driver="scsi-cd", 39107615626SAlberto Garcia id="dev0", drive="cd0") 39207615626SAlberto Garcia self.assert_qmp(result, 'return', {}) 39307615626SAlberto Garcia 39407615626SAlberto Garcia # Set I/O limits 39507615626SAlberto Garcia args = { "id": "dev0", "iops": 100, "iops_rd": 0, "iops_wr": 0, 39607615626SAlberto Garcia "bps": 50, "bps_rd": 0, "bps_wr": 0 } 39707615626SAlberto Garcia result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **args) 39807615626SAlberto Garcia self.assert_qmp(result, 'return', {}) 39907615626SAlberto Garcia 40007615626SAlberto Garcia # Check that the I/O limits have been set 40107615626SAlberto Garcia result = self.vm.qmp("query-block") 40207615626SAlberto Garcia self.assert_qmp(result, 'return[0]/inserted/iops', 100) 40307615626SAlberto Garcia self.assert_qmp(result, 'return[0]/inserted/bps', 50) 40407615626SAlberto Garcia 40507615626SAlberto Garcia # Now eject cd0 and insert cd1 40607615626SAlberto Garcia result = self.vm.qmp("blockdev-open-tray", id='dev0') 40707615626SAlberto Garcia self.assert_qmp(result, 'return', {}) 40834ce1111SMax Reitz result = self.vm.qmp("blockdev-remove-medium", id='dev0') 40907615626SAlberto Garcia self.assert_qmp(result, 'return', {}) 41034ce1111SMax Reitz result = self.vm.qmp("blockdev-insert-medium", id='dev0', node_name='cd1') 41107615626SAlberto Garcia self.assert_qmp(result, 'return', {}) 41207615626SAlberto Garcia 41307615626SAlberto Garcia # Check that the I/O limits are still the same 41407615626SAlberto Garcia result = self.vm.qmp("query-block") 41507615626SAlberto Garcia self.assert_qmp(result, 'return[0]/inserted/iops', 100) 41607615626SAlberto Garcia self.assert_qmp(result, 'return[0]/inserted/bps', 50) 41707615626SAlberto Garcia 41807615626SAlberto Garcia # Eject cd1 41934ce1111SMax Reitz result = self.vm.qmp("blockdev-remove-medium", id='dev0') 42007615626SAlberto Garcia self.assert_qmp(result, 'return', {}) 42107615626SAlberto Garcia 42207615626SAlberto Garcia # Check that we can't set limits if the device has no medium 42307615626SAlberto Garcia result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **args) 42407615626SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 42507615626SAlberto Garcia 42607615626SAlberto Garcia # Remove the CD drive 42707615626SAlberto Garcia result = self.vm.qmp("device_del", id='dev0') 42807615626SAlberto Garcia self.assert_qmp(result, 'return', {}) 42907615626SAlberto Garcia 430435d5ee6SAlberto Garcia 431fb13bbf2SFam Zhengif __name__ == '__main__': 432a377dd51SMax Reitz if 'null-co' not in iotests.supported_formats(): 433a377dd51SMax Reitz iotests.notrun('null-co driver support missing') 434fb13bbf2SFam Zheng iotests.main(supported_fmts=["raw"]) 435