1#!/usr/bin/env python3 2# group: quick 3# 4# Test bitmap merges. 5# 6# Copyright (c) 2018 John Snow for Red Hat, Inc. 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# owner=jsnow@redhat.com 22 23import iotests 24from iotests import log 25 26iotests.script_initialize(supported_fmts=['generic']) 27size = 64 * 1024 * 1024 28granularity = 64 * 1024 29 30patterns = [("0x5d", "0", "64k"), 31 ("0xd5", "1M", "64k"), 32 ("0xdc", "32M", "64k"), 33 ("0xcd", "0x3ff0000", "64k")] # 64M - 64K 34 35overwrite = [("0xab", "0", "64k"), # Full overwrite 36 ("0xad", "0x00f8000", "64k"), # Partial-left (1M-32K) 37 ("0x1d", "0x2008000", "64k"), # Partial-right (32M+32K) 38 ("0xea", "0x3fe0000", "64k")] # Adjacent-left (64M - 128K) 39 40def query_bitmaps(vm): 41 res = vm.qmp("query-block") 42 return { "bitmaps": { device['device']: device.get('dirty-bitmaps', []) for 43 device in res['return'] } } 44 45with iotests.FilePath('img') as img_path, \ 46 iotests.VM() as vm: 47 48 log('--- Preparing image & VM ---\n') 49 iotests.qemu_img_create('-f', iotests.imgfmt, img_path, str(size)) 50 vm.add_drive(img_path) 51 vm.launch() 52 53 log('\n--- Adding preliminary bitmaps A & B ---\n') 54 vm.qmp_log("block-dirty-bitmap-add", node="drive0", 55 name="bitmapA", granularity=granularity) 56 vm.qmp_log("block-dirty-bitmap-add", node="drive0", 57 name="bitmapB", granularity=granularity) 58 59 # Dirties 4 clusters. count=262144 60 log('\n--- Emulating writes ---\n') 61 for p in patterns: 62 cmd = "write -P%s %s %s" % p 63 log(cmd) 64 log(vm.hmp_qemu_io("drive0", cmd)) 65 66 log(query_bitmaps(vm), indent=2) 67 68 log('\n--- Submitting & Aborting Transaction ---\n') 69 vm.qmp_log("transaction", indent=2, actions=[ 70 { "type": "block-dirty-bitmap-disable", 71 "data": { "node": "drive0", "name": "bitmapB" }}, 72 { "type": "block-dirty-bitmap-add", 73 "data": { "node": "drive0", "name": "bitmapC", 74 "granularity": granularity }}, 75 { "type": "block-dirty-bitmap-clear", 76 "data": { "node": "drive0", "name": "bitmapA" }}, 77 { "type": "abort", "data": {}} 78 ]) 79 log(query_bitmaps(vm), indent=2) 80 81 log('\n--- Disabling B & Adding C ---\n') 82 vm.qmp_log("transaction", indent=2, actions=[ 83 { "type": "block-dirty-bitmap-disable", 84 "data": { "node": "drive0", "name": "bitmapB" }}, 85 { "type": "block-dirty-bitmap-add", 86 "data": { "node": "drive0", "name": "bitmapC", 87 "granularity": granularity }}, 88 # Purely extraneous, but test that it works: 89 { "type": "block-dirty-bitmap-disable", 90 "data": { "node": "drive0", "name": "bitmapC" }}, 91 { "type": "block-dirty-bitmap-enable", 92 "data": { "node": "drive0", "name": "bitmapC" }}, 93 ]) 94 95 log('\n--- Emulating further writes ---\n') 96 # Dirties 6 clusters, 3 of which are new in contrast to "A". 97 # A = 64 * 1024 * (4 + 3) = 458752 98 # C = 64 * 1024 * 6 = 393216 99 for p in overwrite: 100 cmd = "write -P%s %s %s" % p 101 log(cmd) 102 log(vm.hmp_qemu_io("drive0", cmd)) 103 104 log('\n--- Disabling A & C ---\n') 105 vm.qmp_log("transaction", indent=2, actions=[ 106 { "type": "block-dirty-bitmap-disable", 107 "data": { "node": "drive0", "name": "bitmapA" }}, 108 { "type": "block-dirty-bitmap-disable", 109 "data": { "node": "drive0", "name": "bitmapC" }} 110 ]) 111 112 # A: 7 clusters 113 # B: 4 clusters 114 # C: 6 clusters 115 log(query_bitmaps(vm), indent=2) 116 117 log('\n--- Submitting & Aborting Merge Transaction ---\n') 118 vm.qmp_log("transaction", indent=2, actions=[ 119 { "type": "block-dirty-bitmap-add", 120 "data": { "node": "drive0", "name": "bitmapD", 121 "disabled": True, "granularity": granularity }}, 122 { "type": "block-dirty-bitmap-merge", 123 "data": { "node": "drive0", "target": "bitmapD", 124 "bitmaps": ["bitmapB", "bitmapC"] }}, 125 { "type": "abort", "data": {}} 126 ]) 127 log(query_bitmaps(vm), indent=2) 128 129 log('\n--- Creating D as a merge of B & C ---\n') 130 # Good hygiene: create a disabled bitmap as a merge target. 131 vm.qmp_log("transaction", indent=2, actions=[ 132 { "type": "block-dirty-bitmap-add", 133 "data": { "node": "drive0", "name": "bitmapD", 134 "disabled": True, "granularity": granularity }}, 135 { "type": "block-dirty-bitmap-merge", 136 "data": { "node": "drive0", "target": "bitmapD", 137 "bitmaps": ["bitmapB", "bitmapC"] }} 138 ]) 139 140 # A and D should now both have 7 clusters apiece. 141 # B and C remain unchanged with 4 and 6 respectively. 142 log(query_bitmaps(vm), indent=2) 143 144 # A and D should be equivalent. 145 # Some formats round the size of the disk, so don't print the checksums. 146 check_a = vm.qmp('x-debug-block-dirty-bitmap-sha256', 147 node="drive0", name="bitmapA")['return']['sha256'] 148 check_d = vm.qmp('x-debug-block-dirty-bitmap-sha256', 149 node="drive0", name="bitmapD")['return']['sha256'] 150 assert(check_a == check_d) 151 152 log('\n--- Removing bitmaps A, B, C, and D ---\n') 153 vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapA") 154 vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapB") 155 vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapC") 156 vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapD") 157 158 log('\n--- Final Query ---\n') 159 log(query_bitmaps(vm), indent=2) 160 161 log('\n--- Done ---\n') 162 vm.shutdown() 163