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