1#!/usr/bin/env python3 2# 3# Tests for persistent dirty bitmaps. 4# 5# Copyright: Vladimir Sementsov-Ogievskiy 2015-2017 6# 7# This program is free software; you can redistribute it and/or modify 8# it under the terms of the GNU General Public License as published by 9# the Free Software Foundation; either version 2 of the License, or 10# (at your option) any later version. 11# 12# This program is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU General Public License for more details. 16# 17# You should have received a copy of the GNU General Public License 18# along with this program. If not, see <http://www.gnu.org/licenses/>. 19# 20 21import os 22import re 23import iotests 24from iotests import qemu_img 25 26disk = os.path.join(iotests.test_dir, 'disk') 27disk_size = 0x40000000 # 1G 28 29# regions for qemu_io: (start, count) in bytes 30regions1 = ((0x0fff00, 0x10000), 31 (0x200000, 0x100000)) 32 33regions2 = ((0x10000000, 0x20000), 34 (0x3fff0000, 0x10000)) 35 36class TestPersistentDirtyBitmap(iotests.QMPTestCase): 37 38 def setUp(self): 39 qemu_img('create', '-f', iotests.imgfmt, disk, str(disk_size)) 40 41 def tearDown(self): 42 os.remove(disk) 43 44 def mkVm(self): 45 return iotests.VM().add_drive(disk, opts='node-name=node0') 46 47 def mkVmRo(self): 48 return iotests.VM().add_drive(disk, opts='readonly=on,node-name=node0') 49 50 def getSha256(self): 51 result = self.vm.qmp('x-debug-block-dirty-bitmap-sha256', 52 node='drive0', name='bitmap0') 53 return result['return']['sha256'] 54 55 def checkBitmap(self, sha256): 56 result = self.vm.qmp('x-debug-block-dirty-bitmap-sha256', 57 node='drive0', name='bitmap0') 58 self.assert_qmp(result, 'return/sha256', sha256); 59 60 def writeRegions(self, regions): 61 for r in regions: 62 self.vm.hmp_qemu_io('drive0', 63 'write %d %d' % r) 64 65 def qmpAddBitmap(self): 66 self.vm.qmp('block-dirty-bitmap-add', node='drive0', 67 name='bitmap0', persistent=True) 68 69 def test_persistent(self): 70 self.vm = self.mkVm() 71 self.vm.launch() 72 self.qmpAddBitmap() 73 74 self.writeRegions(regions1) 75 sha256 = self.getSha256() 76 77 self.vm.shutdown() 78 79 self.vm = self.mkVmRo() 80 self.vm.launch() 81 self.vm.shutdown() 82 83 #catch 'Persistent bitmaps are lost' possible error 84 log = self.vm.get_log() 85 log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log) 86 log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log) 87 if log: 88 print(log) 89 90 self.vm = self.mkVm() 91 self.vm.launch() 92 93 self.checkBitmap(sha256) 94 self.writeRegions(regions2) 95 sha256 = self.getSha256() 96 97 self.vm.shutdown() 98 self.vm.launch() 99 100 self.checkBitmap(sha256) 101 102 self.vm.shutdown() 103 104 def test_reopen_rw(self): 105 self.vm = self.mkVm() 106 self.vm.launch() 107 self.qmpAddBitmap() 108 109 # Calculate hashes 110 111 self.writeRegions(regions1) 112 sha256_1 = self.getSha256() 113 114 self.writeRegions(regions2) 115 sha256_2 = self.getSha256() 116 assert sha256_1 != sha256_2 # Otherwise, it's not very interesting. 117 118 result = self.vm.qmp('block-dirty-bitmap-clear', node='drive0', 119 name='bitmap0') 120 self.assert_qmp(result, 'return', {}) 121 122 # Start with regions1 123 124 self.writeRegions(regions1) 125 assert sha256_1 == self.getSha256() 126 127 self.vm.shutdown() 128 129 self.vm = self.mkVmRo() 130 self.vm.launch() 131 132 assert sha256_1 == self.getSha256() 133 134 # Check that we are in RO mode and can't modify bitmap. 135 self.writeRegions(regions2) 136 assert sha256_1 == self.getSha256() 137 138 # Reopen to RW 139 result = self.vm.qmp('x-blockdev-reopen', **{ 140 'node-name': 'node0', 141 'driver': iotests.imgfmt, 142 'file': { 143 'driver': 'file', 144 'filename': disk 145 }, 146 'read-only': False 147 }) 148 self.assert_qmp(result, 'return', {}) 149 150 # Check that bitmap is reopened to RW and we can write to it. 151 self.writeRegions(regions2) 152 assert sha256_2 == self.getSha256() 153 154 self.vm.shutdown() 155 156 157if __name__ == '__main__': 158 iotests.main(supported_fmts=['qcow2'], 159 supported_protocols=['file']) 160