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')