1
The following changes since commit 91fe7a376ad46e3cc5e82d418aad22173c948a3c:
1
The following changes since commit c4e0780ed1ffd056f205348d387a61b4136a45df:
2
2
3
Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging (2018-06-15 11:41:44 +0100)
3
Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-4.0-pull-request' into staging (2019-03-07 18:40:43 +0000)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to 6266e900b8083945cb766b45c124fb3c42932cb3:
9
for you to fetch changes up to e88153ea9a40009a8ae7648282c0eac1b7f5494f:
10
10
11
block: Remove dead deprecation warning code (2018-06-15 14:49:44 +0200)
11
qcow2 spec: Describe string header extensions (2019-03-08 12:26:46 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches:
15
15
16
- Fix options that work only with -drive or -blockdev, but not with
16
- qcow2: Support for external data files
17
both, because of QDict type confusion
17
- qcow2: Default to 4KB for the qcow2 cache entry size
18
- rbd: Add options 'auth-client-required' and 'key-secret'
18
- Apply block driver whitelist for -drive format=help
19
- Remove deprecated -drive options serial/addr/cyls/heads/secs/trans
19
- Several qemu-iotests improvements
20
- rbd, iscsi: Remove deprecated 'filename' option
21
- Fix 'qemu-img map' crash with unaligned image size
22
- Improve QMP documentation for jobs
23
20
24
----------------------------------------------------------------
21
----------------------------------------------------------------
25
Eric Blake (2):
22
Alberto Garcia (1):
26
qemu-img: Fix assert when mapping unaligned raw file
23
qcow2: Default to 4KB for the qcow2 cache entry size
27
iotests: Add test 221 to catch qemu-img map regression
24
28
25
Andrey Shinkevich (4):
29
John Snow (2):
26
iotests: open notrun files in text mode
30
jobs: fix stale wording
27
block: iterate_format with account of whitelisting
31
jobs: fix verb references in docs
28
iotests: ask QEMU for supported formats
32
29
iotests: check whitelisted formats
33
Kevin Wolf (4):
30
34
block: Remove deprecated -drive geometry options
31
Kevin Wolf (21):
35
block: Remove deprecated -drive option addr
32
qemu-iotests: Test qcow2 preallocation modes
36
block: Remove deprecated -drive option serial
33
qcow2: Simplify preallocation code
37
block: Remove dead deprecation warning code
34
qcow2: Extend spec for external data files
38
35
qcow2: Basic definitions for external data files
39
Markus Armbruster (17):
36
qcow2: Pass bs to qcow2_get_cluster_type()
40
rbd: Drop deprecated -drive parameter "filename"
37
qcow2: Prepare qcow2_get_cluster_type() for external data file
41
iscsi: Drop deprecated -drive parameter "filename"
38
qcow2: Prepare count_contiguous_clusters() for external data file
42
qobject: Move block-specific qdict code to block-qdict.c
39
qcow2: Don't assume 0 is an invalid cluster offset
43
block: Fix -blockdev for certain non-string scalars
40
qcow2: Return 0/-errno in qcow2_alloc_compressed_cluster_offset()
44
block: Fix -drive for certain non-string scalars
41
qcow2: Prepare qcow2_co_block_status() for data file
45
block: Clean up a misuse of qobject_to() in .bdrv_co_create_opts()
42
qcow2: External file I/O
46
block: Factor out qobject_input_visitor_new_flat_confused()
43
qcow2: Return error for snapshot operation with data file
47
block: Make remaining uses of qobject input visitor more robust
44
qcow2: Support external data file in qemu-img check
48
block-qdict: Simplify qdict_flatten_qdict()
45
qcow2: Add basic data-file infrastructure
49
block-qdict: Tweak qdict_flatten_qdict(), qdict_flatten_qlist()
46
qcow2: Creating images with external data file
50
block-qdict: Clean up qdict_crumple() a bit
47
qcow2: Store data file name in the image
51
block-qdict: Simplify qdict_is_list() some
48
qcow2: Implement data-file-raw create option
52
check-block-qdict: Rename qdict_flatten()'s variables for clarity
49
qemu-iotests: Preallocation with external data file
53
check-block-qdict: Cover flattening of empty lists and dictionaries
50
qemu-iotests: General tests for qcow2 with external data file
54
block: Fix -blockdev / blockdev-add for empty objects and arrays
51
qemu-iotests: amend with external data file
55
rbd: New parameter auth-client-required
52
qcow2 spec: Describe string header extensions
56
rbd: New parameter key-secret
53
57
54
Philippe Mathieu-Daudé (6):
58
Max Reitz (1):
55
tests/multiboot: Improve portability by searching bash in the $PATH
59
block: Add block-specific QDict header
56
tests/bios-tables: Improve portability by searching bash in the $PATH
60
57
qemu-iotests: Improve portability by searching bash in the $PATH
61
qapi/block-core.json | 19 ++
58
qemu-iotests: Ensure GNU sed is used
62
qapi/job.json | 23 +-
59
ahci-test: Add dependency to qemu-img tool
63
include/block/qdict.h | 34 +++
60
qemu-iotests: Add dependency to qemu-nbd tool
64
include/hw/block/block.h | 1 -
61
65
include/qapi/qmp/qdict.h | 17 --
62
Stefan Hajnoczi (1):
66
include/sysemu/blockdev.h | 3 -
63
iotests: use iotests.VM in 238
67
block.c | 1 +
64
68
block/block-backend.c | 1 -
65
qapi/block-core.json | 26 ++-
69
block/crypto.c | 12 +-
66
docs/interop/qcow2.txt | 54 +++++-
70
block/gluster.c | 1 +
67
docs/qcow2-cache.txt | 17 +-
71
block/iscsi.c | 24 +-
68
block/qcow2.h | 66 +++++--
72
block/nbd.c | 16 +-
69
include/block/block.h | 2 +-
73
block/nfs.c | 8 +-
70
include/block/block_int.h | 2 +
74
block/parallels.c | 11 +-
71
block.c | 23 ++-
75
block/qcow.c | 11 +-
72
block/qcow2-bitmap.c | 7 +-
76
block/qcow2.c | 11 +-
73
block/qcow2-cache.c | 6 +-
77
block/qed.c | 11 +-
74
block/qcow2-cluster.c | 182 +++++++++++-------
78
block/quorum.c | 1 +
75
block/qcow2-refcount.c | 88 ++++++---
79
block/rbd.c | 85 +++---
76
block/qcow2-snapshot.c | 22 ++-
80
block/sheepdog.c | 23 +-
77
block/qcow2.c | 326 +++++++++++++++++++++++++++-----
81
block/snapshot.c | 1 +
78
blockdev.c | 4 +-
82
block/ssh.c | 16 +-
79
qemu-img.c | 2 +-
83
block/vdi.c | 8 +-
80
tests/Makefile.include | 4 +-
84
block/vhdx.c | 11 +-
81
tests/data/acpi/rebuild-expected-aml.sh | 2 +-
85
block/vpc.c | 11 +-
82
tests/multiboot/run_test.sh | 2 +-
86
block/vvfat.c | 1 +
83
tests/qemu-iotests/001 | 2 +-
87
block/vxhs.c | 1 +
84
tests/qemu-iotests/002 | 2 +-
88
blockdev.c | 111 +------
85
tests/qemu-iotests/003 | 2 +-
89
device-hotplug.c | 4 -
86
tests/qemu-iotests/004 | 2 +-
90
hw/block/block.c | 27 --
87
tests/qemu-iotests/005 | 2 +-
91
hw/block/nvme.c | 1 -
88
tests/qemu-iotests/007 | 2 +-
92
hw/block/virtio-blk.c | 1 -
89
tests/qemu-iotests/008 | 2 +-
93
hw/ide/qdev.c | 1 -
90
tests/qemu-iotests/009 | 2 +-
94
hw/scsi/scsi-disk.c | 1 -
91
tests/qemu-iotests/010 | 2 +-
95
hw/usb/dev-storage.c | 1 -
92
tests/qemu-iotests/011 | 2 +-
96
qemu-img.c | 2 +-
93
tests/qemu-iotests/012 | 2 +-
97
qobject/block-qdict.c | 722 +++++++++++++++++++++++++++++++++++++++++++++
94
tests/qemu-iotests/013 | 2 +-
98
qobject/qdict.c | 628 ---------------------------------------
95
tests/qemu-iotests/014 | 2 +-
99
tests/ahci-test.c | 6 +-
96
tests/qemu-iotests/015 | 2 +-
100
tests/check-block-qdict.c | 690 +++++++++++++++++++++++++++++++++++++++++++
97
tests/qemu-iotests/017 | 2 +-
101
tests/check-qdict.c | 641 ----------------------------------------
98
tests/qemu-iotests/018 | 2 +-
102
tests/check-qobject.c | 1 +
99
tests/qemu-iotests/019 | 2 +-
103
tests/hd-geo-test.c | 37 +--
100
tests/qemu-iotests/020 | 2 +-
104
tests/ide-test.c | 8 +-
101
tests/qemu-iotests/021 | 2 +-
105
tests/test-replication.c | 1 +
102
tests/qemu-iotests/022 | 2 +-
106
util/qemu-config.c | 1 +
103
tests/qemu-iotests/023 | 2 +-
107
MAINTAINERS | 2 +
104
tests/qemu-iotests/024 | 2 +-
108
hmp-commands.hx | 1 -
105
tests/qemu-iotests/025 | 2 +-
109
qemu-doc.texi | 15 -
106
tests/qemu-iotests/026 | 2 +-
110
qemu-options.hx | 14 +-
107
tests/qemu-iotests/027 | 2 +-
111
qobject/Makefile.objs | 1 +
108
tests/qemu-iotests/028 | 2 +-
112
tests/Makefile.include | 4 +
109
tests/qemu-iotests/029 | 2 +-
113
tests/qemu-iotests/221 | 60 ++++
110
tests/qemu-iotests/031 | 2 +-
114
tests/qemu-iotests/221.out | 16 +
111
tests/qemu-iotests/031.out | 8 +-
115
tests/qemu-iotests/group | 1 +
112
tests/qemu-iotests/032 | 2 +-
116
55 files changed, 1692 insertions(+), 1668 deletions(-)
113
tests/qemu-iotests/033 | 2 +-
117
create mode 100644 include/block/qdict.h
114
tests/qemu-iotests/034 | 2 +-
118
create mode 100644 qobject/block-qdict.c
115
tests/qemu-iotests/035 | 2 +-
119
create mode 100644 tests/check-block-qdict.c
116
tests/qemu-iotests/036 | 2 +-
120
create mode 100755 tests/qemu-iotests/221
117
tests/qemu-iotests/036.out | 4 +-
121
create mode 100644 tests/qemu-iotests/221.out
118
tests/qemu-iotests/037 | 2 +-
122
119
tests/qemu-iotests/038 | 2 +-
120
tests/qemu-iotests/039 | 2 +-
121
tests/qemu-iotests/042 | 2 +-
122
tests/qemu-iotests/043 | 2 +-
123
tests/qemu-iotests/046 | 2 +-
124
tests/qemu-iotests/047 | 2 +-
125
tests/qemu-iotests/048 | 2 +-
126
tests/qemu-iotests/049 | 2 +-
127
tests/qemu-iotests/050 | 2 +-
128
tests/qemu-iotests/051 | 2 +-
129
tests/qemu-iotests/052 | 2 +-
130
tests/qemu-iotests/053 | 2 +-
131
tests/qemu-iotests/054 | 2 +-
132
tests/qemu-iotests/058 | 2 +-
133
tests/qemu-iotests/059 | 2 +-
134
tests/qemu-iotests/060 | 2 +-
135
tests/qemu-iotests/061 | 47 ++++-
136
tests/qemu-iotests/061.out | 103 +++++++++-
137
tests/qemu-iotests/062 | 2 +-
138
tests/qemu-iotests/063 | 2 +-
139
tests/qemu-iotests/064 | 2 +-
140
tests/qemu-iotests/066 | 2 +-
141
tests/qemu-iotests/067 | 2 +-
142
tests/qemu-iotests/068 | 2 +-
143
tests/qemu-iotests/069 | 2 +-
144
tests/qemu-iotests/070 | 2 +-
145
tests/qemu-iotests/071 | 2 +-
146
tests/qemu-iotests/072 | 2 +-
147
tests/qemu-iotests/073 | 2 +-
148
tests/qemu-iotests/074 | 2 +-
149
tests/qemu-iotests/075 | 2 +-
150
tests/qemu-iotests/076 | 2 +-
151
tests/qemu-iotests/077 | 2 +-
152
tests/qemu-iotests/078 | 2 +-
153
tests/qemu-iotests/079 | 2 +-
154
tests/qemu-iotests/080 | 2 +-
155
tests/qemu-iotests/081 | 2 +-
156
tests/qemu-iotests/082 | 2 +-
157
tests/qemu-iotests/082.out | 54 ++++++
158
tests/qemu-iotests/083 | 2 +-
159
tests/qemu-iotests/084 | 2 +-
160
tests/qemu-iotests/085 | 2 +-
161
tests/qemu-iotests/086 | 2 +-
162
tests/qemu-iotests/087 | 2 +-
163
tests/qemu-iotests/088 | 2 +-
164
tests/qemu-iotests/089 | 2 +-
165
tests/qemu-iotests/090 | 2 +-
166
tests/qemu-iotests/091 | 2 +-
167
tests/qemu-iotests/092 | 2 +-
168
tests/qemu-iotests/094 | 2 +-
169
tests/qemu-iotests/095 | 2 +-
170
tests/qemu-iotests/097 | 2 +-
171
tests/qemu-iotests/098 | 2 +-
172
tests/qemu-iotests/099 | 2 +-
173
tests/qemu-iotests/101 | 2 +-
174
tests/qemu-iotests/102 | 2 +-
175
tests/qemu-iotests/103 | 2 +-
176
tests/qemu-iotests/104 | 2 +-
177
tests/qemu-iotests/105 | 2 +-
178
tests/qemu-iotests/106 | 2 +-
179
tests/qemu-iotests/107 | 2 +-
180
tests/qemu-iotests/108 | 2 +-
181
tests/qemu-iotests/109 | 2 +-
182
tests/qemu-iotests/110 | 2 +-
183
tests/qemu-iotests/111 | 2 +-
184
tests/qemu-iotests/112 | 2 +-
185
tests/qemu-iotests/113 | 2 +-
186
tests/qemu-iotests/114 | 2 +-
187
tests/qemu-iotests/115 | 2 +-
188
tests/qemu-iotests/116 | 2 +-
189
tests/qemu-iotests/117 | 2 +-
190
tests/qemu-iotests/119 | 2 +-
191
tests/qemu-iotests/120 | 2 +-
192
tests/qemu-iotests/121 | 2 +-
193
tests/qemu-iotests/122 | 2 +-
194
tests/qemu-iotests/123 | 2 +-
195
tests/qemu-iotests/125 | 2 +-
196
tests/qemu-iotests/126 | 2 +-
197
tests/qemu-iotests/127 | 2 +-
198
tests/qemu-iotests/128 | 2 +-
199
tests/qemu-iotests/130 | 2 +-
200
tests/qemu-iotests/131 | 2 +-
201
tests/qemu-iotests/133 | 2 +-
202
tests/qemu-iotests/134 | 2 +-
203
tests/qemu-iotests/135 | 2 +-
204
tests/qemu-iotests/137 | 2 +-
205
tests/qemu-iotests/138 | 2 +-
206
tests/qemu-iotests/139 | 3 +
207
tests/qemu-iotests/140 | 2 +-
208
tests/qemu-iotests/141 | 2 +-
209
tests/qemu-iotests/142 | 2 +-
210
tests/qemu-iotests/143 | 2 +-
211
tests/qemu-iotests/144 | 2 +-
212
tests/qemu-iotests/145 | 2 +-
213
tests/qemu-iotests/146 | 2 +-
214
tests/qemu-iotests/150 | 2 +-
215
tests/qemu-iotests/153 | 2 +-
216
tests/qemu-iotests/154 | 2 +-
217
tests/qemu-iotests/156 | 2 +-
218
tests/qemu-iotests/157 | 2 +-
219
tests/qemu-iotests/158 | 2 +-
220
tests/qemu-iotests/159 | 2 +-
221
tests/qemu-iotests/160 | 2 +-
222
tests/qemu-iotests/161 | 2 +-
223
tests/qemu-iotests/162 | 2 +-
224
tests/qemu-iotests/170 | 2 +-
225
tests/qemu-iotests/171 | 2 +-
226
tests/qemu-iotests/172 | 2 +-
227
tests/qemu-iotests/173 | 2 +-
228
tests/qemu-iotests/174 | 2 +-
229
tests/qemu-iotests/175 | 2 +-
230
tests/qemu-iotests/176 | 2 +-
231
tests/qemu-iotests/177 | 2 +-
232
tests/qemu-iotests/178 | 2 +-
233
tests/qemu-iotests/179 | 2 +-
234
tests/qemu-iotests/181 | 2 +-
235
tests/qemu-iotests/182 | 2 +-
236
tests/qemu-iotests/183 | 2 +-
237
tests/qemu-iotests/184 | 2 +-
238
tests/qemu-iotests/185 | 2 +-
239
tests/qemu-iotests/186 | 2 +-
240
tests/qemu-iotests/187 | 2 +-
241
tests/qemu-iotests/188 | 2 +-
242
tests/qemu-iotests/189 | 2 +-
243
tests/qemu-iotests/190 | 2 +-
244
tests/qemu-iotests/191 | 2 +-
245
tests/qemu-iotests/192 | 2 +-
246
tests/qemu-iotests/195 | 2 +-
247
tests/qemu-iotests/197 | 2 +-
248
tests/qemu-iotests/198 | 2 +-
249
tests/qemu-iotests/200 | 2 +-
250
tests/qemu-iotests/201 | 2 +-
251
tests/qemu-iotests/204 | 2 +-
252
tests/qemu-iotests/214 | 2 +-
253
tests/qemu-iotests/215 | 2 +-
254
tests/qemu-iotests/217 | 2 +-
255
tests/qemu-iotests/220 | 2 +-
256
tests/qemu-iotests/220.out | 2 +-
257
tests/qemu-iotests/221 | 2 +-
258
tests/qemu-iotests/223 | 2 +-
259
tests/qemu-iotests/225 | 2 +-
260
tests/qemu-iotests/226 | 2 +-
261
tests/qemu-iotests/227 | 2 +-
262
tests/qemu-iotests/229 | 2 +-
263
tests/qemu-iotests/231 | 2 +-
264
tests/qemu-iotests/232 | 2 +-
265
tests/qemu-iotests/233 | 2 +-
266
tests/qemu-iotests/238 | 7 +-
267
tests/qemu-iotests/243 | 85 +++++++++
268
tests/qemu-iotests/243.out | 58 ++++++
269
tests/qemu-iotests/244 | 200 ++++++++++++++++++++
270
tests/qemu-iotests/244.out | 125 ++++++++++++
271
tests/qemu-iotests/check | 15 +-
272
tests/qemu-iotests/common.config | 2 +-
273
tests/qemu-iotests/common.filter | 38 ++--
274
tests/qemu-iotests/common.nbd | 2 +-
275
tests/qemu-iotests/common.pattern | 2 +-
276
tests/qemu-iotests/common.qemu | 2 +-
277
tests/qemu-iotests/common.rc | 15 +-
278
tests/qemu-iotests/common.tls | 2 +-
279
tests/qemu-iotests/group | 2 +
280
tests/qemu-iotests/iotests.py | 45 ++++-
281
216 files changed, 1585 insertions(+), 423 deletions(-)
282
create mode 100755 tests/qemu-iotests/243
283
create mode 100644 tests/qemu-iotests/243.out
284
create mode 100755 tests/qemu-iotests/244
285
create mode 100644 tests/qemu-iotests/244.out
286
diff view generated by jsdifflib
New patch
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
2
3
Test 238 does not require the kvm accelerator. Using the qtest
4
accelerator allows the test to run in both non-kvm and non-tcg
5
environments.
6
7
iotests.VM implicitly uses the qtest accelerator and is really the class
8
that this test should be using. Switch to that instead of
9
qemu.QEMUMachine.
10
11
Suggested-by: Thomas Huth <thuth@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
tests/qemu-iotests/238 | 7 +------
16
1 file changed, 1 insertion(+), 6 deletions(-)
17
18
diff --git a/tests/qemu-iotests/238 b/tests/qemu-iotests/238
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/238
21
+++ b/tests/qemu-iotests/238
22
@@ -XXX,XX +XXX,XX @@ import os
23
import iotests
24
from iotests import log
25
26
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
27
-
28
-from qemu import QEMUMachine
29
-
30
if iotests.qemu_default_machine == 's390-ccw-virtio':
31
virtio_scsi_device = 'virtio-scsi-ccw'
32
else:
33
virtio_scsi_device = 'virtio-scsi-pci'
34
35
-vm = QEMUMachine(iotests.qemu_prog)
36
-vm.add_args('-machine', 'accel=kvm')
37
+vm = iotests.VM()
38
vm.launch()
39
40
log(vm.qmp('blockdev-add', node_name='hd0', driver='null-co'))
41
--
42
2.20.1
43
44
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
3
QEMU 2.12 (commit 1221fe6f636754ab5f2c1c87caa77633e9123622) introduced
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
4
a new setting called l2-cache-entry-size that allows making entries on
5
the qcow2 L2 cache smaller than the cluster size.
6
7
I have been performing several tests with different cluster and entry
8
sizes and all of them show that reducing the entry size (aka L2 slice)
9
consistently improves I/O performance, notably during random I/O (all
10
tests done with sequential I/O show similar results). This is to be
11
expected because loading and evicting an L2 slice is more expensive
12
the larger the slice is.
13
14
Here are some numbers on fully populated 40GB qcow2 images. The
15
rightmost column represents the maximum L2 cache size in both cases.
16
17
Cluster size = 64 KB
18
|-------------+--------------+--------------+--------------|
19
| | 1MB L2 cache | 3MB L2 cache | 5MB L2 cache |
20
|-------------+--------------+--------------+--------------|
21
| 4KB slices | 6545 IOPS | 12045 IOPS | 55680 IOPS |
22
| 16KB slices | 5177 IOPS | 9798 IOPS | 56278 IOPS |
23
| 64KB slices | 2718 IOPS | 5326 IOPS | 57355 IOPS |
24
|-------------+--------------+--------------+--------------|
25
26
Cluster size = 256 KB
27
|--------------+----------------+--------------+-----------------|
28
| | 512KB L2 cache | 1MB L2 cache | 1280KB L2 cache |
29
|--------------+----------------+--------------+-----------------|
30
| 4KB slices | 8539 IOPS | 21071 IOPS | 55417 IOPS |
31
| 64KB slices | 3598 IOPS | 9772 IOPS | 57687 IOPS |
32
| 256KB slices | 1415 IOPS | 4120 IOPS | 58001 IOPS |
33
|--------------+----------------+--------------+-----------------|
34
35
As can be seen in the numbers, the only exception to the rule is when
36
the cache is large enough to hold all L2 tables. This is also to be
37
expected because in this case no cache entry is ever evicted so
38
reducing its size doesn't bring any benefit.
39
40
This patch sets the default L2 cache entry size to 4KB except when the
41
cache is large enough for the whole disk.
42
43
Signed-off-by: Alberto Garcia <berto@igalia.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
44
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
45
---
7
qobject/block-qdict.c | 27 +++++++++++----------------
46
docs/qcow2-cache.txt | 17 +++++++++++------
8
1 file changed, 11 insertions(+), 16 deletions(-)
47
block/qcow2.c | 12 ++++++++++++
48
2 files changed, 23 insertions(+), 6 deletions(-)
9
49
10
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
50
diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt
11
index XXXXXXX..XXXXXXX 100644
51
index XXXXXXX..XXXXXXX 100644
12
--- a/qobject/block-qdict.c
52
--- a/docs/qcow2-cache.txt
13
+++ b/qobject/block-qdict.c
53
+++ b/docs/qcow2-cache.txt
14
@@ -XXX,XX +XXX,XX @@ static int qdict_is_list(QDict *maybe_list, Error **errp)
54
@@ -XXX,XX +XXX,XX @@ refcount cache is as small as possible unless overridden by the user.
15
55
16
for (ent = qdict_first(maybe_list); ent != NULL;
56
Using smaller cache entries
17
ent = qdict_next(maybe_list, ent)) {
57
---------------------------
18
+ int is_index = !qemu_strtoi64(ent->key, NULL, 10, &val);
58
-The qcow2 L2 cache stores complete tables by default. This means that
19
59
-if QEMU needs an entry from an L2 table then the whole table is read
20
- if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) {
60
-from disk and is kept in the cache. If the cache is full then a
21
- if (is_list == -1) {
61
-complete table needs to be evicted first.
22
- is_list = 1;
62
+The qcow2 L2 cache can store complete tables. This means that if QEMU
23
- } else if (!is_list) {
63
+needs an entry from an L2 table then the whole table is read from disk
24
- error_setg(errp,
64
+and is kept in the cache. If the cache is full then a complete table
25
- "Cannot mix list and non-list keys");
65
+needs to be evicted first.
26
- return -1;
66
27
- }
67
This can be inefficient with large cluster sizes since it results in
28
+ if (is_list == -1) {
68
more disk I/O and wastes more cache memory.
29
+ is_list = is_index;
69
@@ -XXX,XX +XXX,XX @@ it smaller than the cluster size. This can be configured using the
30
+ }
70
71
-drive file=hd.qcow2,l2-cache-size=2097152,l2-cache-entry-size=4096
72
73
+Since QEMU 4.0 the value of l2-cache-entry-size defaults to 4KB (or
74
+the cluster size if it's smaller).
31
+
75
+
32
+ if (is_index != is_list) {
76
Some things to take into account:
33
+ error_setg(errp, "Cannot mix list and non-list keys");
77
34
+ return -1;
78
- The L2 cache entry size has the same restrictions as the cluster
35
+ }
79
@@ -XXX,XX +XXX,XX @@ Some things to take into account:
36
+
80
37
+ if (is_index) {
81
- Try different entry sizes to see which one gives faster performance
38
len++;
82
in your case. The block size of the host filesystem is generally a
39
if (val > max) {
83
- good default (usually 4096 bytes in the case of ext4).
40
max = val;
84
+ good default (usually 4096 bytes in the case of ext4, hence the
85
+ default).
86
87
- Only the L2 cache can be configured this way. The refcount cache
88
always uses the cluster size as the entry size.
89
@@ -XXX,XX +XXX,XX @@ Some things to take into account:
90
(as explained in the "Choosing the right cache sizes" and "How to
91
configure the cache sizes" sections in this document) then none of
92
this is necessary and you can omit the "l2-cache-entry-size"
93
- parameter altogether.
94
+ parameter altogether. In this case QEMU makes the entry size
95
+ equal to the cluster size by default.
96
97
98
Reducing the memory usage
99
diff --git a/block/qcow2.c b/block/qcow2.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/block/qcow2.c
102
+++ b/block/qcow2.c
103
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
104
BDRVQcow2State *s = bs->opaque;
105
uint64_t combined_cache_size, l2_cache_max_setting;
106
bool l2_cache_size_set, refcount_cache_size_set, combined_cache_size_set;
107
+ bool l2_cache_entry_size_set;
108
int min_refcount_cache = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
109
uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
110
uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8);
111
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
112
combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE);
113
l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_SIZE);
114
refcount_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_REFCOUNT_CACHE_SIZE);
115
+ l2_cache_entry_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_ENTRY_SIZE);
116
117
combined_cache_size = qemu_opt_get_size(opts, QCOW2_OPT_CACHE_SIZE, 0);
118
l2_cache_max_setting = qemu_opt_get_size(opts, QCOW2_OPT_L2_CACHE_SIZE,
119
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
41
}
120
}
42
- } else {
43
- if (is_list == -1) {
44
- is_list = 0;
45
- } else if (is_list) {
46
- error_setg(errp,
47
- "Cannot mix list and non-list keys");
48
- return -1;
49
- }
50
}
121
}
51
}
122
}
123
+
124
+ /*
125
+ * If the L2 cache is not enough to cover the whole disk then
126
+ * default to 4KB entries. Smaller entries reduce the cost of
127
+ * loads and evictions and increase I/O performance.
128
+ */
129
+ if (*l2_cache_size < max_l2_cache && !l2_cache_entry_size_set) {
130
+ *l2_cache_entry_size = MIN(s->cluster_size, 4096);
131
+ }
132
+
133
/* l2_cache_size and refcount_cache_size are ensured to have at least
134
* their minimum values in qcow2_update_options_prepare() */
52
135
53
--
136
--
54
2.13.6
137
2.20.1
55
138
56
139
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
2
2
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
3
Replace the binary mode with the default text one when *.notrun
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
4
files are opened for skipped tests. That change is made for the
5
compatibility with Python 3 which returns error otherwise.
6
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
10
---
7
tests/check-block-qdict.c | 14 +++++++++++++-
11
tests/qemu-iotests/iotests.py | 2 +-
8
1 file changed, 13 insertions(+), 1 deletion(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
9
13
10
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
14
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
11
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/check-block-qdict.c
16
--- a/tests/qemu-iotests/iotests.py
13
+++ b/tests/check-block-qdict.c
17
+++ b/tests/qemu-iotests/iotests.py
14
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
18
@@ -XXX,XX +XXX,XX @@ def notrun(reason):
15
QList *e = qlist_new();
19
# Each test in qemu-iotests has a number ("seq")
16
QDict *e_1_2 = qdict_new();
20
seq = os.path.basename(sys.argv[0])
17
QDict *f = qdict_new();
21
18
+ QList *y = qlist_new();
22
- open('%s/%s.notrun' % (output_dir, seq), 'wb').write(reason + '\n')
19
+ QDict *z = qdict_new();
23
+ open('%s/%s.notrun' % (output_dir, seq), 'w').write(reason + '\n')
20
QDict *root = qdict_new();
24
print('%s not run: %s' % (seq, reason))
21
25
sys.exit(0)
22
/*
23
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
24
* "c": 2,
25
* "d": 3,
26
* },
27
- * "g": 4
28
+ * "g": 4,
29
+ * "y": [{}],
30
+ * "z": {"a": []}
31
* }
32
*
33
* to
34
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
35
* "f.d": 3,
36
* "g": 4
37
* }
38
+ *
39
+ * Note that "y" and "z" get eaten.
40
*/
41
42
qdict_put_int(e_1_2, "a", 0);
43
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
44
qdict_put_int(f, "c", 2);
45
qdict_put_int(f, "d", 3);
46
47
+ qlist_append(y, qdict_new());
48
+
49
+ qdict_put(z, "a", qlist_new());
50
+
51
qdict_put(root, "e", e);
52
qdict_put(root, "f", f);
53
qdict_put_int(root, "g", 4);
54
+ qdict_put(root, "y", y);
55
+ qdict_put(root, "z", z);
56
57
qdict_flatten(root);
58
26
59
--
27
--
60
2.13.6
28
2.20.1
61
29
62
30
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
2
2
3
There are numerous QDict functions that have been introduced for and are
3
bdrv_iterate_format (which is currently only used for printing out the
4
used only by the block layer. Move their declarations into an own
4
formats supported by the block layer) doesn't take format whitelisting
5
header file to reflect that.
5
into account.
6
6
7
While qdict_extract_subqdict() is in fact used outside of the block
7
This creates a problem for tests: they enumerate supported formats to
8
layer (in util/qemu-config.c), it is still a function related very
8
decide which tests to enable, but then discover that QEMU doesn't let
9
closely to how the block layer works with nested QDicts, namely by
9
them actually use some of those formats.
10
sometimes flattening them. Therefore, its declaration is put into this
11
header as well and util/qemu-config.c includes it with a comment stating
12
exactly which function it needs.
13
10
14
Suggested-by: Markus Armbruster <armbru@redhat.com>
11
To avoid that, exclude formats that are not whitelisted from
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
enumeration, if whitelisting is in use. Since we have separate
16
Message-Id: <20180509165530.29561-7-mreitz@redhat.com>
13
whitelists for r/w and r/o, take this a parameter to
17
[Copyright note tweaked, superfluous includes dropped]
14
bdrv_iterate_format, and print two lists of supported formats (r/w and
18
Signed-off-by: Markus Armbruster <armbru@redhat.com>
15
r/o) in main qemu.
19
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
17
Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
18
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
20
---
22
include/block/qdict.h | 32 ++++++++++++++++++++++++++++++++
21
include/block/block.h | 2 +-
23
include/qapi/qmp/qdict.h | 17 -----------------
22
block.c | 23 +++++++++++++++++++----
24
block.c | 1 +
23
blockdev.c | 4 +++-
25
block/gluster.c | 1 +
24
qemu-img.c | 2 +-
26
block/iscsi.c | 1 +
25
4 files changed, 24 insertions(+), 7 deletions(-)
27
block/nbd.c | 1 +
28
block/nfs.c | 1 +
29
block/parallels.c | 1 +
30
block/qcow.c | 1 +
31
block/qcow2.c | 1 +
32
block/qed.c | 1 +
33
block/quorum.c | 1 +
34
block/rbd.c | 1 +
35
block/sheepdog.c | 1 +
36
block/snapshot.c | 1 +
37
block/ssh.c | 1 +
38
block/vhdx.c | 1 +
39
block/vpc.c | 1 +
40
block/vvfat.c | 1 +
41
block/vxhs.c | 1 +
42
blockdev.c | 1 +
43
qobject/qdict.c | 1 +
44
tests/check-qdict.c | 1 +
45
tests/check-qobject.c | 1 +
46
tests/test-replication.c | 1 +
47
util/qemu-config.c | 1 +
48
26 files changed, 56 insertions(+), 17 deletions(-)
49
create mode 100644 include/block/qdict.h
50
26
51
diff --git a/include/block/qdict.h b/include/block/qdict.h
27
diff --git a/include/block/block.h b/include/block/block.h
52
new file mode 100644
53
index XXXXXXX..XXXXXXX
54
--- /dev/null
55
+++ b/include/block/qdict.h
56
@@ -XXX,XX +XXX,XX @@
57
+/*
58
+ * Special QDict functions used by the block layer
59
+ *
60
+ * Copyright (c) 2013-2018 Red Hat, Inc.
61
+ *
62
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
63
+ * See the COPYING.LIB file in the top-level directory.
64
+ */
65
+
66
+#ifndef BLOCK_QDICT_H
67
+#define BLOCK_QDICT_H
68
+
69
+#include "qapi/qmp/qdict.h"
70
+
71
+void qdict_copy_default(QDict *dst, QDict *src, const char *key);
72
+void qdict_set_default_str(QDict *dst, const char *key, const char *val);
73
+
74
+void qdict_join(QDict *dest, QDict *src, bool overwrite);
75
+
76
+void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
77
+void qdict_array_split(QDict *src, QList **dst);
78
+int qdict_array_entries(QDict *src, const char *subqdict);
79
+QObject *qdict_crumple(const QDict *src, Error **errp);
80
+void qdict_flatten(QDict *qdict);
81
+
82
+typedef struct QDictRenames {
83
+ const char *from;
84
+ const char *to;
85
+} QDictRenames;
86
+bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
87
+
88
+#endif
89
diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
90
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
91
--- a/include/qapi/qmp/qdict.h
29
--- a/include/block/block.h
92
+++ b/include/qapi/qmp/qdict.h
30
+++ b/include/block/block.h
93
@@ -XXX,XX +XXX,XX @@ int64_t qdict_get_try_int(const QDict *qdict, const char *key,
31
@@ -XXX,XX +XXX,XX @@ void bdrv_next_cleanup(BdrvNextIterator *it);
94
bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value);
32
BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs);
95
const char *qdict_get_try_str(const QDict *qdict, const char *key);
33
bool bdrv_is_encrypted(BlockDriverState *bs);
96
34
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
97
-void qdict_copy_default(QDict *dst, QDict *src, const char *key);
35
- void *opaque);
98
-void qdict_set_default_str(QDict *dst, const char *key, const char *val);
36
+ void *opaque, bool read_only);
99
-
37
const char *bdrv_get_node_name(const BlockDriverState *bs);
100
QDict *qdict_clone_shallow(const QDict *src);
38
const char *bdrv_get_device_name(const BlockDriverState *bs);
101
-void qdict_flatten(QDict *qdict);
39
const char *bdrv_get_device_or_node_name(const BlockDriverState *bs);
102
-
103
-void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
104
-void qdict_array_split(QDict *src, QList **dst);
105
-int qdict_array_entries(QDict *src, const char *subqdict);
106
-QObject *qdict_crumple(const QDict *src, Error **errp);
107
-
108
-void qdict_join(QDict *dest, QDict *src, bool overwrite);
109
-
110
-typedef struct QDictRenames {
111
- const char *from;
112
- const char *to;
113
-} QDictRenames;
114
-bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
115
116
#endif /* QDICT_H */
117
diff --git a/block.c b/block.c
40
diff --git a/block.c b/block.c
118
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
119
--- a/block.c
42
--- a/block.c
120
+++ b/block.c
43
+++ b/block.c
121
@@ -XXX,XX +XXX,XX @@
44
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_format(const char *format_name)
122
#include "block/block_int.h"
45
return bdrv_do_find_format(format_name);
123
#include "block/blockjob.h"
46
}
124
#include "block/nbd.h"
47
125
+#include "block/qdict.h"
48
-int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
126
#include "qemu/error-report.h"
49
+static int bdrv_format_is_whitelisted(const char *format_name, bool read_only)
127
#include "module_block.h"
50
{
128
#include "qemu/module.h"
51
static const char *whitelist_rw[] = {
129
diff --git a/block/gluster.c b/block/gluster.c
52
CONFIG_BDRV_RW_WHITELIST
130
index XXXXXXX..XXXXXXX 100644
53
@@ -XXX,XX +XXX,XX @@ int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
131
--- a/block/gluster.c
54
}
132
+++ b/block/gluster.c
55
133
@@ -XXX,XX +XXX,XX @@
56
for (p = whitelist_rw; *p; p++) {
134
#include "qemu/osdep.h"
57
- if (!strcmp(drv->format_name, *p)) {
135
#include <glusterfs/api/glfs.h>
58
+ if (!strcmp(format_name, *p)) {
136
#include "block/block_int.h"
59
return 1;
137
+#include "block/qdict.h"
60
}
138
#include "qapi/error.h"
61
}
139
#include "qapi/qmp/qdict.h"
62
if (read_only) {
140
#include "qapi/qmp/qerror.h"
63
for (p = whitelist_ro; *p; p++) {
141
diff --git a/block/iscsi.c b/block/iscsi.c
64
- if (!strcmp(drv->format_name, *p)) {
142
index XXXXXXX..XXXXXXX 100644
65
+ if (!strcmp(format_name, *p)) {
143
--- a/block/iscsi.c
66
return 1;
144
+++ b/block/iscsi.c
67
}
145
@@ -XXX,XX +XXX,XX @@
68
}
146
#include "qemu/bitops.h"
69
@@ -XXX,XX +XXX,XX @@ int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
147
#include "qemu/bitmap.h"
70
return 0;
148
#include "block/block_int.h"
71
}
149
+#include "block/qdict.h"
72
150
#include "scsi/constants.h"
73
+int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
151
#include "qemu/iov.h"
74
+{
152
#include "qemu/option.h"
75
+ return bdrv_format_is_whitelisted(drv->format_name, read_only);
153
diff --git a/block/nbd.c b/block/nbd.c
76
+}
154
index XXXXXXX..XXXXXXX 100644
77
+
155
--- a/block/nbd.c
78
bool bdrv_uses_whitelist(void)
156
+++ b/block/nbd.c
79
{
157
@@ -XXX,XX +XXX,XX @@
80
return use_bdrv_whitelist;
158
81
@@ -XXX,XX +XXX,XX @@ static int qsort_strcmp(const void *a, const void *b)
159
#include "qemu/osdep.h"
82
}
160
#include "nbd-client.h"
83
161
+#include "block/qdict.h"
84
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
162
#include "qapi/error.h"
85
- void *opaque)
163
#include "qemu/uri.h"
86
+ void *opaque, bool read_only)
164
#include "block/block_int.h"
87
{
165
diff --git a/block/nfs.c b/block/nfs.c
88
BlockDriver *drv;
166
index XXXXXXX..XXXXXXX 100644
89
int count = 0;
167
--- a/block/nfs.c
90
@@ -XXX,XX +XXX,XX @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
168
+++ b/block/nfs.c
91
if (drv->format_name) {
169
@@ -XXX,XX +XXX,XX @@
92
bool found = false;
170
#include "qemu/error-report.h"
93
int i = count;
171
#include "qapi/error.h"
94
+
172
#include "block/block_int.h"
95
+ if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, read_only)) {
173
+#include "block/qdict.h"
96
+ continue;
174
#include "trace.h"
97
+ }
175
#include "qemu/iov.h"
98
+
176
#include "qemu/option.h"
99
while (formats && i && !found) {
177
diff --git a/block/parallels.c b/block/parallels.c
100
found = !strcmp(formats[--i], drv->format_name);
178
index XXXXXXX..XXXXXXX 100644
101
}
179
--- a/block/parallels.c
102
@@ -XXX,XX +XXX,XX @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
180
+++ b/block/parallels.c
103
bool found = false;
181
@@ -XXX,XX +XXX,XX @@
104
int j = count;
182
#include "qemu/osdep.h"
105
183
#include "qapi/error.h"
106
+ if (use_bdrv_whitelist &&
184
#include "block/block_int.h"
107
+ !bdrv_format_is_whitelisted(format_name, read_only)) {
185
+#include "block/qdict.h"
108
+ continue;
186
#include "sysemu/block-backend.h"
109
+ }
187
#include "qemu/module.h"
110
+
188
#include "qemu/option.h"
111
while (formats && j && !found) {
189
diff --git a/block/qcow.c b/block/qcow.c
112
found = !strcmp(formats[--j], format_name);
190
index XXXXXXX..XXXXXXX 100644
113
}
191
--- a/block/qcow.c
192
+++ b/block/qcow.c
193
@@ -XXX,XX +XXX,XX @@
194
#include "qapi/error.h"
195
#include "qemu/error-report.h"
196
#include "block/block_int.h"
197
+#include "block/qdict.h"
198
#include "sysemu/block-backend.h"
199
#include "qemu/module.h"
200
#include "qemu/option.h"
201
diff --git a/block/qcow2.c b/block/qcow2.c
202
index XXXXXXX..XXXXXXX 100644
203
--- a/block/qcow2.c
204
+++ b/block/qcow2.c
205
@@ -XXX,XX +XXX,XX @@
206
207
#include "qemu/osdep.h"
208
#include "block/block_int.h"
209
+#include "block/qdict.h"
210
#include "sysemu/block-backend.h"
211
#include "qemu/module.h"
212
#include <zlib.h>
213
diff --git a/block/qed.c b/block/qed.c
214
index XXXXXXX..XXXXXXX 100644
215
--- a/block/qed.c
216
+++ b/block/qed.c
217
@@ -XXX,XX +XXX,XX @@
218
*/
219
220
#include "qemu/osdep.h"
221
+#include "block/qdict.h"
222
#include "qapi/error.h"
223
#include "qemu/timer.h"
224
#include "qemu/bswap.h"
225
diff --git a/block/quorum.c b/block/quorum.c
226
index XXXXXXX..XXXXXXX 100644
227
--- a/block/quorum.c
228
+++ b/block/quorum.c
229
@@ -XXX,XX +XXX,XX @@
230
#include "qemu/cutils.h"
231
#include "qemu/option.h"
232
#include "block/block_int.h"
233
+#include "block/qdict.h"
234
#include "qapi/error.h"
235
#include "qapi/qapi-events-block.h"
236
#include "qapi/qmp/qdict.h"
237
diff --git a/block/rbd.c b/block/rbd.c
238
index XXXXXXX..XXXXXXX 100644
239
--- a/block/rbd.c
240
+++ b/block/rbd.c
241
@@ -XXX,XX +XXX,XX @@
242
#include "qemu/error-report.h"
243
#include "qemu/option.h"
244
#include "block/block_int.h"
245
+#include "block/qdict.h"
246
#include "crypto/secret.h"
247
#include "qemu/cutils.h"
248
#include "qapi/qmp/qstring.h"
249
diff --git a/block/sheepdog.c b/block/sheepdog.c
250
index XXXXXXX..XXXXXXX 100644
251
--- a/block/sheepdog.c
252
+++ b/block/sheepdog.c
253
@@ -XXX,XX +XXX,XX @@
254
#include "qemu/option.h"
255
#include "qemu/sockets.h"
256
#include "block/block_int.h"
257
+#include "block/qdict.h"
258
#include "sysemu/block-backend.h"
259
#include "qemu/bitops.h"
260
#include "qemu/cutils.h"
261
diff --git a/block/snapshot.c b/block/snapshot.c
262
index XXXXXXX..XXXXXXX 100644
263
--- a/block/snapshot.c
264
+++ b/block/snapshot.c
265
@@ -XXX,XX +XXX,XX @@
266
#include "qemu/osdep.h"
267
#include "block/snapshot.h"
268
#include "block/block_int.h"
269
+#include "block/qdict.h"
270
#include "qapi/error.h"
271
#include "qapi/qmp/qdict.h"
272
#include "qapi/qmp/qerror.h"
273
diff --git a/block/ssh.c b/block/ssh.c
274
index XXXXXXX..XXXXXXX 100644
275
--- a/block/ssh.c
276
+++ b/block/ssh.c
277
@@ -XXX,XX +XXX,XX @@
278
#include <libssh2_sftp.h>
279
280
#include "block/block_int.h"
281
+#include "block/qdict.h"
282
#include "qapi/error.h"
283
#include "qemu/error-report.h"
284
#include "qemu/option.h"
285
diff --git a/block/vhdx.c b/block/vhdx.c
286
index XXXXXXX..XXXXXXX 100644
287
--- a/block/vhdx.c
288
+++ b/block/vhdx.c
289
@@ -XXX,XX +XXX,XX @@
290
#include "qemu/osdep.h"
291
#include "qapi/error.h"
292
#include "block/block_int.h"
293
+#include "block/qdict.h"
294
#include "sysemu/block-backend.h"
295
#include "qemu/module.h"
296
#include "qemu/option.h"
297
diff --git a/block/vpc.c b/block/vpc.c
298
index XXXXXXX..XXXXXXX 100644
299
--- a/block/vpc.c
300
+++ b/block/vpc.c
301
@@ -XXX,XX +XXX,XX @@
302
#include "qemu/osdep.h"
303
#include "qapi/error.h"
304
#include "block/block_int.h"
305
+#include "block/qdict.h"
306
#include "sysemu/block-backend.h"
307
#include "qemu/module.h"
308
#include "qemu/option.h"
309
diff --git a/block/vvfat.c b/block/vvfat.c
310
index XXXXXXX..XXXXXXX 100644
311
--- a/block/vvfat.c
312
+++ b/block/vvfat.c
313
@@ -XXX,XX +XXX,XX @@
314
#include <dirent.h>
315
#include "qapi/error.h"
316
#include "block/block_int.h"
317
+#include "block/qdict.h"
318
#include "qemu/module.h"
319
#include "qemu/option.h"
320
#include "qemu/bswap.h"
321
diff --git a/block/vxhs.c b/block/vxhs.c
322
index XXXXXXX..XXXXXXX 100644
323
--- a/block/vxhs.c
324
+++ b/block/vxhs.c
325
@@ -XXX,XX +XXX,XX @@
326
#include <qnio/qnio_api.h>
327
#include <sys/param.h>
328
#include "block/block_int.h"
329
+#include "block/qdict.h"
330
#include "qapi/qmp/qerror.h"
331
#include "qapi/qmp/qdict.h"
332
#include "qapi/qmp/qstring.h"
333
diff --git a/blockdev.c b/blockdev.c
114
diff --git a/blockdev.c b/blockdev.c
334
index XXXXXXX..XXXXXXX 100644
115
index XXXXXXX..XXXXXXX 100644
335
--- a/blockdev.c
116
--- a/blockdev.c
336
+++ b/blockdev.c
117
+++ b/blockdev.c
337
@@ -XXX,XX +XXX,XX @@
118
@@ -XXX,XX +XXX,XX @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
338
#include "sysemu/blockdev.h"
119
if ((buf = qemu_opt_get(opts, "format")) != NULL) {
339
#include "hw/block/block.h"
120
if (is_help_option(buf)) {
340
#include "block/blockjob.h"
121
error_printf("Supported formats:");
341
+#include "block/qdict.h"
122
- bdrv_iterate_format(bdrv_format_print, NULL);
342
#include "block/throttle-groups.h"
123
+ bdrv_iterate_format(bdrv_format_print, NULL, false);
343
#include "monitor/monitor.h"
124
+ error_printf("\nSupported formats (read-only):");
344
#include "qemu/error-report.h"
125
+ bdrv_iterate_format(bdrv_format_print, NULL, true);
345
diff --git a/qobject/qdict.c b/qobject/qdict.c
126
error_printf("\n");
127
goto early_err;
128
}
129
diff --git a/qemu-img.c b/qemu-img.c
346
index XXXXXXX..XXXXXXX 100644
130
index XXXXXXX..XXXXXXX 100644
347
--- a/qobject/qdict.c
131
--- a/qemu-img.c
348
+++ b/qobject/qdict.c
132
+++ b/qemu-img.c
349
@@ -XXX,XX +XXX,XX @@
133
@@ -XXX,XX +XXX,XX @@ static void QEMU_NORETURN help(void)
350
*/
134
" 'skip=N' skip N bs-sized blocks at the start of input\n";
351
135
352
#include "qemu/osdep.h"
136
printf("%s\nSupported formats:", help_msg);
353
+#include "block/qdict.h"
137
- bdrv_iterate_format(format_print, NULL);
354
#include "qapi/qmp/qnum.h"
138
+ bdrv_iterate_format(format_print, NULL, false);
355
#include "qapi/qmp/qdict.h"
139
printf("\n\n" QEMU_HELP_BOTTOM "\n");
356
#include "qapi/qmp/qbool.h"
140
exit(EXIT_SUCCESS);
357
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
141
}
358
index XXXXXXX..XXXXXXX 100644
359
--- a/tests/check-qdict.c
360
+++ b/tests/check-qdict.c
361
@@ -XXX,XX +XXX,XX @@
362
*/
363
364
#include "qemu/osdep.h"
365
+#include "block/qdict.h"
366
#include "qapi/qmp/qdict.h"
367
#include "qapi/qmp/qlist.h"
368
#include "qapi/qmp/qnum.h"
369
diff --git a/tests/check-qobject.c b/tests/check-qobject.c
370
index XXXXXXX..XXXXXXX 100644
371
--- a/tests/check-qobject.c
372
+++ b/tests/check-qobject.c
373
@@ -XXX,XX +XXX,XX @@
374
*/
375
376
#include "qemu/osdep.h"
377
+#include "block/qdict.h"
378
#include "qapi/qmp/qbool.h"
379
#include "qapi/qmp/qdict.h"
380
#include "qapi/qmp/qlist.h"
381
diff --git a/tests/test-replication.c b/tests/test-replication.c
382
index XXXXXXX..XXXXXXX 100644
383
--- a/tests/test-replication.c
384
+++ b/tests/test-replication.c
385
@@ -XXX,XX +XXX,XX @@
386
#include "qemu/option.h"
387
#include "replication.h"
388
#include "block/block_int.h"
389
+#include "block/qdict.h"
390
#include "sysemu/block-backend.h"
391
392
#define IMG_SIZE (64 * 1024 * 1024)
393
diff --git a/util/qemu-config.c b/util/qemu-config.c
394
index XXXXXXX..XXXXXXX 100644
395
--- a/util/qemu-config.c
396
+++ b/util/qemu-config.c
397
@@ -XXX,XX +XXX,XX @@
398
#include "qemu/osdep.h"
399
+#include "block/qdict.h" /* for qdict_extract_subqdict() */
400
#include "qapi/error.h"
401
#include "qapi/qapi-commands-misc.h"
402
#include "qapi/qmp/qdict.h"
403
--
142
--
404
2.13.6
143
2.20.1
405
144
406
145
diff view generated by jsdifflib
New patch
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
1
2
3
Supported formats listed by 'qemu' may differ from those listed by
4
'qemu-img' due to whitelists. Some test cases require specific formats
5
that may be used with qemu. They can be inquired directly by running
6
'qemu -drive format=help'. The response takes whitelists into account.
7
The method supported_formats() serves for that. The method decorator
8
skip_if_unsupported() checks if all requested formats are whitelisted.
9
If not, the test case will be skipped. That has been implemented in
10
the 'check' file in the way similar to the 'test notrun' mechanism.
11
12
Suggested-by: Roman Kagan <rkagan@virtuozzo.com>
13
Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Suggested-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
tests/qemu-iotests/check | 13 ++++++++++-
19
tests/qemu-iotests/iotests.py | 43 +++++++++++++++++++++++++++++++++++
20
2 files changed, 55 insertions(+), 1 deletion(-)
21
22
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
23
index XXXXXXX..XXXXXXX 100755
24
--- a/tests/qemu-iotests/check
25
+++ b/tests/qemu-iotests/check
26
@@ -XXX,XX +XXX,XX @@ try=0
27
n_bad=0
28
bad=""
29
notrun=""
30
+casenotrun=""
31
interrupt=true
32
33
# by default don't output timestamps
34
@@ -XXX,XX +XXX,XX @@ END { if (NR > 0) {
35
echo "Not run:$notrun"
36
echo "Not run:$notrun" >>check.log
37
fi
38
+ if [ ! -z "$casenotrun" ]
39
+ then
40
+ echo "Some cases not run in:$casenotrun"
41
+ echo "Some cases not run in:$casenotrun" >>check.log
42
+ fi
43
if [ ! -z "$n_bad" -a $n_bad != 0 ]
44
then
45
echo "Failures:$bad"
46
@@ -XXX,XX +XXX,XX @@ do
47
printf " " # prettier output with timestamps.
48
fi
49
rm -f core $seq.notrun
50
+ rm -f $seq.casenotrun
51
52
start=$(_wallclock)
53
$timestamp && printf %s " [$(date "+%T")]"
54
@@ -XXX,XX +XXX,XX @@ do
55
fi
56
fi
57
fi
58
-
59
+ if [ -f $seq.casenotrun ]
60
+ then
61
+ cat $seq.casenotrun
62
+ casenotrun="$casenotrun $seq"
63
+ fi
64
fi
65
66
# come here for each test, except when $showme is true
67
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
68
index XXXXXXX..XXXXXXX 100644
69
--- a/tests/qemu-iotests/iotests.py
70
+++ b/tests/qemu-iotests/iotests.py
71
@@ -XXX,XX +XXX,XX @@ def notrun(reason):
72
print('%s not run: %s' % (seq, reason))
73
sys.exit(0)
74
75
+def case_notrun(reason):
76
+ '''Skip this test case'''
77
+ # Each test in qemu-iotests has a number ("seq")
78
+ seq = os.path.basename(sys.argv[0])
79
+
80
+ open('%s/%s.casenotrun' % (output_dir, seq), 'a').write(
81
+ ' [case not run] ' + reason + '\n')
82
+
83
def verify_image_format(supported_fmts=[], unsupported_fmts=[]):
84
assert not (supported_fmts and unsupported_fmts)
85
86
@@ -XXX,XX +XXX,XX @@ def verify_quorum():
87
if not supports_quorum():
88
notrun('quorum support missing')
89
90
+def qemu_pipe(*args):
91
+ '''Run qemu with an option to print something and exit (e.g. a help option),
92
+ and return its output'''
93
+ args = [qemu_prog] + qemu_opts + list(args)
94
+ subp = subprocess.Popen(args, stdout=subprocess.PIPE,
95
+ stderr=subprocess.STDOUT,
96
+ universal_newlines=True)
97
+ exitcode = subp.wait()
98
+ if exitcode < 0:
99
+ sys.stderr.write('qemu received signal %i: %s\n' % (-exitcode,
100
+ ' '.join(args)))
101
+ return subp.communicate()[0]
102
+
103
+def supported_formats(read_only=False):
104
+ '''Set 'read_only' to True to check ro-whitelist
105
+ Otherwise, rw-whitelist is checked'''
106
+ format_message = qemu_pipe("-drive", "format=help")
107
+ line = 1 if read_only else 0
108
+ return format_message.splitlines()[line].split(":")[1].split()
109
+
110
+def skip_if_unsupported(required_formats=[], read_only=False):
111
+ '''Skip Test Decorator
112
+ Runs the test if all the required formats are whitelisted'''
113
+ def skip_test_decorator(func):
114
+ def func_wrapper(*args, **kwargs):
115
+ usf_list = list(set(required_formats) -
116
+ set(supported_formats(read_only)))
117
+ if usf_list:
118
+ case_notrun('{}: formats {} are not whitelisted'.format(
119
+ args[0], usf_list))
120
+ else:
121
+ return func(*args, **kwargs)
122
+ return func_wrapper
123
+ return skip_test_decorator
124
+
125
def main(supported_fmts=[], supported_oses=['linux'], supported_cache_modes=[],
126
unsupported_fmts=[]):
127
'''Run tests'''
128
--
129
2.20.1
130
131
diff view generated by jsdifflib
New patch
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
1
2
3
Some test cases require specific formats. The method decorator
4
skip_if_unsupported() checks if requested formats are whitelisted.
5
The test #139 was selected for a sample output, after running
6
$ ./check -qcow2 131-140
7
8
137 3s ...
9
138 0s ...
10
139 2s ...
11
[case not run] testBlkDebug (__main__.TestBlockdevDel): formats ['blkdebug'] are not whitelisted
12
[case not run] testBlkVerify (__main__.TestBlockdevDel): formats ['blkverify'] are not whitelisted
13
[case not run] testQuorum (__main__.TestBlockdevDel): formats ['quorum'] are not whitelisted
14
140 0s ...
15
Not run: 131 135 136
16
Some cases not run in: 139
17
Passed all 7 tests
18
19
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
22
tests/qemu-iotests/139 | 3 +++
23
1 file changed, 3 insertions(+)
24
25
diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139
26
index XXXXXXX..XXXXXXX 100755
27
--- a/tests/qemu-iotests/139
28
+++ b/tests/qemu-iotests/139
29
@@ -XXX,XX +XXX,XX @@ class TestBlockdevDel(iotests.QMPTestCase):
30
# FIXME mirror0 disappears, drive-mirror doesn't take a reference
31
#self.delBlockDriverState('mirror0')
32
33
+ @iotests.skip_if_unsupported(['blkdebug'])
34
def testBlkDebug(self):
35
self.addBlkDebug('debug0', 'node0')
36
# 'node0' is used by the blkdebug node
37
@@ -XXX,XX +XXX,XX @@ class TestBlockdevDel(iotests.QMPTestCase):
38
self.delBlockDriverState('debug0')
39
self.checkBlockDriverState('node0', False)
40
41
+ @iotests.skip_if_unsupported(['blkverify'])
42
def testBlkVerify(self):
43
self.addBlkVerify('verify0', 'node0', 'node1')
44
# We cannot remove the children of a blkverify device
45
@@ -XXX,XX +XXX,XX @@ class TestBlockdevDel(iotests.QMPTestCase):
46
self.checkBlockDriverState('node0', False)
47
self.checkBlockDriverState('node1', False)
48
49
+ @iotests.skip_if_unsupported(['quorum'])
50
def testQuorum(self):
51
if not iotests.supports_quorum():
52
return
53
--
54
2.20.1
55
56
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
2
3
Bash is not always installed as /bin/bash. In particular on OpenBSD,
4
the package installs it in /usr/local/bin.
5
Use the 'env' shebang to search bash in the $PATH.
6
7
Reviewed-by: Kamil Rytarowski <n54@gmx.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
tests/multiboot/run_test.sh | 2 +-
13
1 file changed, 1 insertion(+), 1 deletion(-)
14
15
diff --git a/tests/multiboot/run_test.sh b/tests/multiboot/run_test.sh
16
index XXXXXXX..XXXXXXX 100755
17
--- a/tests/multiboot/run_test.sh
18
+++ b/tests/multiboot/run_test.sh
19
@@ -XXX,XX +XXX,XX @@
20
-#!/bin/bash
21
+#!/usr/bin/env bash
22
23
# Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
24
#
25
--
26
2.20.1
27
28
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
2
3
Bash is not always installed as /bin/bash. In particular on OpenBSD,
4
the package installs it in /usr/local/bin.
5
Use the 'env' shebang to search bash in the $PATH.
6
7
Reviewed-by: Kamil Rytarowski <n54@gmx.com>
8
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
9
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
10
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
11
Acked-by: Thomas Huth <thuth@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
tests/data/acpi/rebuild-expected-aml.sh | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
16
17
diff --git a/tests/data/acpi/rebuild-expected-aml.sh b/tests/data/acpi/rebuild-expected-aml.sh
18
index XXXXXXX..XXXXXXX 100755
19
--- a/tests/data/acpi/rebuild-expected-aml.sh
20
+++ b/tests/data/acpi/rebuild-expected-aml.sh
21
@@ -XXX,XX +XXX,XX @@
22
-#! /bin/bash
23
+#!/usr/bin/env bash
24
25
#
26
# Rebuild expected AML files for acpi unit-test
27
--
28
2.20.1
29
30
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
3
Bash is not always installed as /bin/bash. In particular on OpenBSD,
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
4
the package installs it in /usr/local/bin.
5
Use the 'env' shebang to search bash in the $PATH.
6
7
Patch created mechanically by running:
8
9
$ git grep -lE '#! ?/bin/bash' -- tests/qemu-iotests \
10
| while read f; do \
11
sed -i 's|^#!.\?/bin/bash$|#!/usr/bin/env bash|' $f; \
12
done
13
14
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
17
---
7
tests/check-block-qdict.c | 57 ++++++++++++++++++++++++-----------------------
18
tests/qemu-iotests/001 | 2 +-
8
1 file changed, 29 insertions(+), 28 deletions(-)
19
tests/qemu-iotests/002 | 2 +-
20
tests/qemu-iotests/003 | 2 +-
21
tests/qemu-iotests/004 | 2 +-
22
tests/qemu-iotests/005 | 2 +-
23
tests/qemu-iotests/007 | 2 +-
24
tests/qemu-iotests/008 | 2 +-
25
tests/qemu-iotests/009 | 2 +-
26
tests/qemu-iotests/010 | 2 +-
27
tests/qemu-iotests/011 | 2 +-
28
tests/qemu-iotests/012 | 2 +-
29
tests/qemu-iotests/013 | 2 +-
30
tests/qemu-iotests/014 | 2 +-
31
tests/qemu-iotests/015 | 2 +-
32
tests/qemu-iotests/017 | 2 +-
33
tests/qemu-iotests/018 | 2 +-
34
tests/qemu-iotests/019 | 2 +-
35
tests/qemu-iotests/020 | 2 +-
36
tests/qemu-iotests/021 | 2 +-
37
tests/qemu-iotests/022 | 2 +-
38
tests/qemu-iotests/023 | 2 +-
39
tests/qemu-iotests/024 | 2 +-
40
tests/qemu-iotests/025 | 2 +-
41
tests/qemu-iotests/026 | 2 +-
42
tests/qemu-iotests/027 | 2 +-
43
tests/qemu-iotests/028 | 2 +-
44
tests/qemu-iotests/029 | 2 +-
45
tests/qemu-iotests/031 | 2 +-
46
tests/qemu-iotests/032 | 2 +-
47
tests/qemu-iotests/033 | 2 +-
48
tests/qemu-iotests/034 | 2 +-
49
tests/qemu-iotests/035 | 2 +-
50
tests/qemu-iotests/036 | 2 +-
51
tests/qemu-iotests/037 | 2 +-
52
tests/qemu-iotests/038 | 2 +-
53
tests/qemu-iotests/039 | 2 +-
54
tests/qemu-iotests/042 | 2 +-
55
tests/qemu-iotests/043 | 2 +-
56
tests/qemu-iotests/046 | 2 +-
57
tests/qemu-iotests/047 | 2 +-
58
tests/qemu-iotests/048 | 2 +-
59
tests/qemu-iotests/049 | 2 +-
60
tests/qemu-iotests/050 | 2 +-
61
tests/qemu-iotests/051 | 2 +-
62
tests/qemu-iotests/052 | 2 +-
63
tests/qemu-iotests/053 | 2 +-
64
tests/qemu-iotests/054 | 2 +-
65
tests/qemu-iotests/058 | 2 +-
66
tests/qemu-iotests/059 | 2 +-
67
tests/qemu-iotests/060 | 2 +-
68
tests/qemu-iotests/061 | 2 +-
69
tests/qemu-iotests/062 | 2 +-
70
tests/qemu-iotests/063 | 2 +-
71
tests/qemu-iotests/064 | 2 +-
72
tests/qemu-iotests/066 | 2 +-
73
tests/qemu-iotests/067 | 2 +-
74
tests/qemu-iotests/068 | 2 +-
75
tests/qemu-iotests/069 | 2 +-
76
tests/qemu-iotests/070 | 2 +-
77
tests/qemu-iotests/071 | 2 +-
78
tests/qemu-iotests/072 | 2 +-
79
tests/qemu-iotests/073 | 2 +-
80
tests/qemu-iotests/074 | 2 +-
81
tests/qemu-iotests/075 | 2 +-
82
tests/qemu-iotests/076 | 2 +-
83
tests/qemu-iotests/077 | 2 +-
84
tests/qemu-iotests/078 | 2 +-
85
tests/qemu-iotests/079 | 2 +-
86
tests/qemu-iotests/080 | 2 +-
87
tests/qemu-iotests/081 | 2 +-
88
tests/qemu-iotests/082 | 2 +-
89
tests/qemu-iotests/083 | 2 +-
90
tests/qemu-iotests/084 | 2 +-
91
tests/qemu-iotests/085 | 2 +-
92
tests/qemu-iotests/086 | 2 +-
93
tests/qemu-iotests/087 | 2 +-
94
tests/qemu-iotests/088 | 2 +-
95
tests/qemu-iotests/089 | 2 +-
96
tests/qemu-iotests/090 | 2 +-
97
tests/qemu-iotests/091 | 2 +-
98
tests/qemu-iotests/092 | 2 +-
99
tests/qemu-iotests/094 | 2 +-
100
tests/qemu-iotests/095 | 2 +-
101
tests/qemu-iotests/097 | 2 +-
102
tests/qemu-iotests/098 | 2 +-
103
tests/qemu-iotests/099 | 2 +-
104
tests/qemu-iotests/101 | 2 +-
105
tests/qemu-iotests/102 | 2 +-
106
tests/qemu-iotests/103 | 2 +-
107
tests/qemu-iotests/104 | 2 +-
108
tests/qemu-iotests/105 | 2 +-
109
tests/qemu-iotests/106 | 2 +-
110
tests/qemu-iotests/107 | 2 +-
111
tests/qemu-iotests/108 | 2 +-
112
tests/qemu-iotests/109 | 2 +-
113
tests/qemu-iotests/110 | 2 +-
114
tests/qemu-iotests/111 | 2 +-
115
tests/qemu-iotests/112 | 2 +-
116
tests/qemu-iotests/113 | 2 +-
117
tests/qemu-iotests/114 | 2 +-
118
tests/qemu-iotests/115 | 2 +-
119
tests/qemu-iotests/116 | 2 +-
120
tests/qemu-iotests/117 | 2 +-
121
tests/qemu-iotests/119 | 2 +-
122
tests/qemu-iotests/120 | 2 +-
123
tests/qemu-iotests/121 | 2 +-
124
tests/qemu-iotests/122 | 2 +-
125
tests/qemu-iotests/123 | 2 +-
126
tests/qemu-iotests/125 | 2 +-
127
tests/qemu-iotests/126 | 2 +-
128
tests/qemu-iotests/127 | 2 +-
129
tests/qemu-iotests/128 | 2 +-
130
tests/qemu-iotests/130 | 2 +-
131
tests/qemu-iotests/131 | 2 +-
132
tests/qemu-iotests/133 | 2 +-
133
tests/qemu-iotests/134 | 2 +-
134
tests/qemu-iotests/135 | 2 +-
135
tests/qemu-iotests/137 | 2 +-
136
tests/qemu-iotests/138 | 2 +-
137
tests/qemu-iotests/140 | 2 +-
138
tests/qemu-iotests/141 | 2 +-
139
tests/qemu-iotests/142 | 2 +-
140
tests/qemu-iotests/143 | 2 +-
141
tests/qemu-iotests/144 | 2 +-
142
tests/qemu-iotests/145 | 2 +-
143
tests/qemu-iotests/146 | 2 +-
144
tests/qemu-iotests/150 | 2 +-
145
tests/qemu-iotests/153 | 2 +-
146
tests/qemu-iotests/154 | 2 +-
147
tests/qemu-iotests/156 | 2 +-
148
tests/qemu-iotests/157 | 2 +-
149
tests/qemu-iotests/158 | 2 +-
150
tests/qemu-iotests/159 | 2 +-
151
tests/qemu-iotests/160 | 2 +-
152
tests/qemu-iotests/161 | 2 +-
153
tests/qemu-iotests/162 | 2 +-
154
tests/qemu-iotests/170 | 2 +-
155
tests/qemu-iotests/171 | 2 +-
156
tests/qemu-iotests/172 | 2 +-
157
tests/qemu-iotests/173 | 2 +-
158
tests/qemu-iotests/174 | 2 +-
159
tests/qemu-iotests/175 | 2 +-
160
tests/qemu-iotests/176 | 2 +-
161
tests/qemu-iotests/177 | 2 +-
162
tests/qemu-iotests/178 | 2 +-
163
tests/qemu-iotests/179 | 2 +-
164
tests/qemu-iotests/181 | 2 +-
165
tests/qemu-iotests/182 | 2 +-
166
tests/qemu-iotests/183 | 2 +-
167
tests/qemu-iotests/184 | 2 +-
168
tests/qemu-iotests/185 | 2 +-
169
tests/qemu-iotests/186 | 2 +-
170
tests/qemu-iotests/187 | 2 +-
171
tests/qemu-iotests/188 | 2 +-
172
tests/qemu-iotests/189 | 2 +-
173
tests/qemu-iotests/190 | 2 +-
174
tests/qemu-iotests/191 | 2 +-
175
tests/qemu-iotests/192 | 2 +-
176
tests/qemu-iotests/195 | 2 +-
177
tests/qemu-iotests/197 | 2 +-
178
tests/qemu-iotests/198 | 2 +-
179
tests/qemu-iotests/200 | 2 +-
180
tests/qemu-iotests/201 | 2 +-
181
tests/qemu-iotests/204 | 2 +-
182
tests/qemu-iotests/214 | 2 +-
183
tests/qemu-iotests/215 | 2 +-
184
tests/qemu-iotests/217 | 2 +-
185
tests/qemu-iotests/220 | 2 +-
186
tests/qemu-iotests/221 | 2 +-
187
tests/qemu-iotests/223 | 2 +-
188
tests/qemu-iotests/225 | 2 +-
189
tests/qemu-iotests/226 | 2 +-
190
tests/qemu-iotests/227 | 2 +-
191
tests/qemu-iotests/229 | 2 +-
192
tests/qemu-iotests/231 | 2 +-
193
tests/qemu-iotests/232 | 2 +-
194
tests/qemu-iotests/233 | 2 +-
195
tests/qemu-iotests/check | 2 +-
196
tests/qemu-iotests/common.config | 2 +-
197
tests/qemu-iotests/common.filter | 2 +-
198
tests/qemu-iotests/common.nbd | 2 +-
199
tests/qemu-iotests/common.pattern | 2 +-
200
tests/qemu-iotests/common.qemu | 2 +-
201
tests/qemu-iotests/common.rc | 2 +-
202
tests/qemu-iotests/common.tls | 2 +-
203
185 files changed, 185 insertions(+), 185 deletions(-)
9
204
10
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
205
diff --git a/tests/qemu-iotests/001 b/tests/qemu-iotests/001
206
index XXXXXXX..XXXXXXX 100755
207
--- a/tests/qemu-iotests/001
208
+++ b/tests/qemu-iotests/001
209
@@ -XXX,XX +XXX,XX @@
210
-#!/bin/bash
211
+#!/usr/bin/env bash
212
#
213
# Test simple read/write using plain bdrv_read/bdrv_write
214
#
215
diff --git a/tests/qemu-iotests/002 b/tests/qemu-iotests/002
216
index XXXXXXX..XXXXXXX 100755
217
--- a/tests/qemu-iotests/002
218
+++ b/tests/qemu-iotests/002
219
@@ -XXX,XX +XXX,XX @@
220
-#!/bin/bash
221
+#!/usr/bin/env bash
222
#
223
# Test simple read/write using plain bdrv_pread/bdrv_pwrite
224
#
225
diff --git a/tests/qemu-iotests/003 b/tests/qemu-iotests/003
226
index XXXXXXX..XXXXXXX 100755
227
--- a/tests/qemu-iotests/003
228
+++ b/tests/qemu-iotests/003
229
@@ -XXX,XX +XXX,XX @@
230
-#!/bin/bash
231
+#!/usr/bin/env bash
232
#
233
# Test simple read/write using bdrv_aio_readv/bdrv_aio_writev
234
#
235
diff --git a/tests/qemu-iotests/004 b/tests/qemu-iotests/004
236
index XXXXXXX..XXXXXXX 100755
237
--- a/tests/qemu-iotests/004
238
+++ b/tests/qemu-iotests/004
239
@@ -XXX,XX +XXX,XX @@
240
-#!/bin/bash
241
+#!/usr/bin/env bash
242
#
243
# Make sure we can't read and write outside of the image size.
244
#
245
diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005
246
index XXXXXXX..XXXXXXX 100755
247
--- a/tests/qemu-iotests/005
248
+++ b/tests/qemu-iotests/005
249
@@ -XXX,XX +XXX,XX @@
250
-#!/bin/bash
251
+#!/usr/bin/env bash
252
#
253
# Make sure qemu-img can create 5TB images
254
#
255
diff --git a/tests/qemu-iotests/007 b/tests/qemu-iotests/007
256
index XXXXXXX..XXXXXXX 100755
257
--- a/tests/qemu-iotests/007
258
+++ b/tests/qemu-iotests/007
259
@@ -XXX,XX +XXX,XX @@
260
-#!/bin/bash
261
+#!/usr/bin/env bash
262
#
263
# Check for one possible case of qcow2 refcount corruption.
264
#
265
diff --git a/tests/qemu-iotests/008 b/tests/qemu-iotests/008
266
index XXXXXXX..XXXXXXX 100755
267
--- a/tests/qemu-iotests/008
268
+++ b/tests/qemu-iotests/008
269
@@ -XXX,XX +XXX,XX @@
270
-#!/bin/bash
271
+#!/usr/bin/env bash
272
#
273
# Test simple asynchronous read/write operations.
274
#
275
diff --git a/tests/qemu-iotests/009 b/tests/qemu-iotests/009
276
index XXXXXXX..XXXXXXX 100755
277
--- a/tests/qemu-iotests/009
278
+++ b/tests/qemu-iotests/009
279
@@ -XXX,XX +XXX,XX @@
280
-#!/bin/bash
281
+#!/usr/bin/env bash
282
#
283
# Nolan I qcow2 corruption - incorrectly reports free clusters
284
#
285
diff --git a/tests/qemu-iotests/010 b/tests/qemu-iotests/010
286
index XXXXXXX..XXXXXXX 100755
287
--- a/tests/qemu-iotests/010
288
+++ b/tests/qemu-iotests/010
289
@@ -XXX,XX +XXX,XX @@
290
-#!/bin/bash
291
+#!/usr/bin/env bash
292
#
293
# Nolan II qcow2 corruption - wrong used cluster
294
#
295
diff --git a/tests/qemu-iotests/011 b/tests/qemu-iotests/011
296
index XXXXXXX..XXXXXXX 100755
297
--- a/tests/qemu-iotests/011
298
+++ b/tests/qemu-iotests/011
299
@@ -XXX,XX +XXX,XX @@
300
-#!/bin/bash
301
+#!/usr/bin/env bash
302
#
303
# Test for AIO allocation on the same cluster
304
#
305
diff --git a/tests/qemu-iotests/012 b/tests/qemu-iotests/012
306
index XXXXXXX..XXXXXXX 100755
307
--- a/tests/qemu-iotests/012
308
+++ b/tests/qemu-iotests/012
309
@@ -XXX,XX +XXX,XX @@
310
-#!/bin/bash
311
+#!/usr/bin/env bash
312
#
313
# Make sure we can open read-only images
314
#
315
diff --git a/tests/qemu-iotests/013 b/tests/qemu-iotests/013
316
index XXXXXXX..XXXXXXX 100755
317
--- a/tests/qemu-iotests/013
318
+++ b/tests/qemu-iotests/013
319
@@ -XXX,XX +XXX,XX @@
320
-#!/bin/bash
321
+#!/usr/bin/env bash
322
#
323
# qcow2 pattern test, empty and compressed image - 4k cluster patterns
324
#
325
diff --git a/tests/qemu-iotests/014 b/tests/qemu-iotests/014
326
index XXXXXXX..XXXXXXX 100755
327
--- a/tests/qemu-iotests/014
328
+++ b/tests/qemu-iotests/014
329
@@ -XXX,XX +XXX,XX @@
330
-#!/bin/bash
331
+#!/usr/bin/env bash
332
#
333
# qcow2 pattern test, complex patterns including compression and snapshots
334
# Using patterns for 4k cluster size.
335
diff --git a/tests/qemu-iotests/015 b/tests/qemu-iotests/015
336
index XXXXXXX..XXXXXXX 100755
337
--- a/tests/qemu-iotests/015
338
+++ b/tests/qemu-iotests/015
339
@@ -XXX,XX +XXX,XX @@
340
-#!/bin/bash
341
+#!/usr/bin/env bash
342
#
343
# Combined test to grow the refcount table and test snapshots.
344
#
345
diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017
346
index XXXXXXX..XXXXXXX 100755
347
--- a/tests/qemu-iotests/017
348
+++ b/tests/qemu-iotests/017
349
@@ -XXX,XX +XXX,XX @@
350
-#!/bin/bash
351
+#!/usr/bin/env bash
352
#
353
# Simple backing file reads
354
#
355
diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018
356
index XXXXXXX..XXXXXXX 100755
357
--- a/tests/qemu-iotests/018
358
+++ b/tests/qemu-iotests/018
359
@@ -XXX,XX +XXX,XX @@
360
-#!/bin/bash
361
+#!/usr/bin/env bash
362
#
363
# Merge backing file into test image when converting the image
364
#
365
diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019
366
index XXXXXXX..XXXXXXX 100755
367
--- a/tests/qemu-iotests/019
368
+++ b/tests/qemu-iotests/019
369
@@ -XXX,XX +XXX,XX @@
370
-#!/bin/bash
371
+#!/usr/bin/env bash
372
#
373
# When using a backing file for the output image in qemu-img convert,
374
# the backing file clusters must not copied. The data must still be
375
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
376
index XXXXXXX..XXXXXXX 100755
377
--- a/tests/qemu-iotests/020
378
+++ b/tests/qemu-iotests/020
379
@@ -XXX,XX +XXX,XX @@
380
-#!/bin/bash
381
+#!/usr/bin/env bash
382
#
383
# Commit changes to backing file
384
#
385
diff --git a/tests/qemu-iotests/021 b/tests/qemu-iotests/021
386
index XXXXXXX..XXXXXXX 100755
387
--- a/tests/qemu-iotests/021
388
+++ b/tests/qemu-iotests/021
389
@@ -XXX,XX +XXX,XX @@
390
-#!/bin/bash
391
+#!/usr/bin/env bash
392
#
393
# Test handling of invalid patterns arguments to qemu-io
394
#
395
diff --git a/tests/qemu-iotests/022 b/tests/qemu-iotests/022
396
index XXXXXXX..XXXXXXX 100755
397
--- a/tests/qemu-iotests/022
398
+++ b/tests/qemu-iotests/022
399
@@ -XXX,XX +XXX,XX @@
400
-#!/bin/bash
401
+#!/usr/bin/env bash
402
#
403
# Test bdrv_load/save_vmstate using the usual patterns
404
#
405
diff --git a/tests/qemu-iotests/023 b/tests/qemu-iotests/023
406
index XXXXXXX..XXXXXXX 100755
407
--- a/tests/qemu-iotests/023
408
+++ b/tests/qemu-iotests/023
409
@@ -XXX,XX +XXX,XX @@
410
-#!/bin/bash
411
+#!/usr/bin/env bash
412
#
413
# qcow2 pattern test with various cluster sizes
414
#
415
diff --git a/tests/qemu-iotests/024 b/tests/qemu-iotests/024
416
index XXXXXXX..XXXXXXX 100755
417
--- a/tests/qemu-iotests/024
418
+++ b/tests/qemu-iotests/024
419
@@ -XXX,XX +XXX,XX @@
420
-#!/bin/bash
421
+#!/usr/bin/env bash
422
#
423
# Rebasing COW images
424
#
425
diff --git a/tests/qemu-iotests/025 b/tests/qemu-iotests/025
426
index XXXXXXX..XXXXXXX 100755
427
--- a/tests/qemu-iotests/025
428
+++ b/tests/qemu-iotests/025
429
@@ -XXX,XX +XXX,XX @@
430
-#!/bin/bash
431
+#!/usr/bin/env bash
432
#
433
# Resizing images
434
#
435
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
436
index XXXXXXX..XXXXXXX 100755
437
--- a/tests/qemu-iotests/026
438
+++ b/tests/qemu-iotests/026
439
@@ -XXX,XX +XXX,XX @@
440
-#!/bin/bash
441
+#!/usr/bin/env bash
442
#
443
# qcow2 error path testing
444
#
445
diff --git a/tests/qemu-iotests/027 b/tests/qemu-iotests/027
446
index XXXXXXX..XXXXXXX 100755
447
--- a/tests/qemu-iotests/027
448
+++ b/tests/qemu-iotests/027
449
@@ -XXX,XX +XXX,XX @@
450
-#!/bin/bash
451
+#!/usr/bin/env bash
452
#
453
# Test that sub-cluster allocating writes zero the rest of the cluster
454
#
455
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
456
index XXXXXXX..XXXXXXX 100755
457
--- a/tests/qemu-iotests/028
458
+++ b/tests/qemu-iotests/028
459
@@ -XXX,XX +XXX,XX @@
460
-#!/bin/bash
461
+#!/usr/bin/env bash
462
#
463
# Test that backing files can be smaller than the image
464
#
465
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
466
index XXXXXXX..XXXXXXX 100755
467
--- a/tests/qemu-iotests/029
468
+++ b/tests/qemu-iotests/029
469
@@ -XXX,XX +XXX,XX @@
470
-#!/bin/bash
471
+#!/usr/bin/env bash
472
#
473
# qcow2 internal snapshots/VM state tests
474
#
475
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
476
index XXXXXXX..XXXXXXX 100755
477
--- a/tests/qemu-iotests/031
478
+++ b/tests/qemu-iotests/031
479
@@ -XXX,XX +XXX,XX @@
480
-#!/bin/bash
481
+#!/usr/bin/env bash
482
#
483
# Test that all qcow2 header extensions survive a header rewrite
484
#
485
diff --git a/tests/qemu-iotests/032 b/tests/qemu-iotests/032
486
index XXXXXXX..XXXXXXX 100755
487
--- a/tests/qemu-iotests/032
488
+++ b/tests/qemu-iotests/032
489
@@ -XXX,XX +XXX,XX @@
490
-#!/bin/bash
491
+#!/usr/bin/env bash
492
#
493
# Test that AIO requests are drained before an image is closed. This used
494
# to segfault because the request coroutine kept running even after the
495
diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033
496
index XXXXXXX..XXXXXXX 100755
497
--- a/tests/qemu-iotests/033
498
+++ b/tests/qemu-iotests/033
499
@@ -XXX,XX +XXX,XX @@
500
-#!/bin/bash
501
+#!/usr/bin/env bash
502
#
503
# Test aligned and misaligned write zeroes operations.
504
#
505
diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034
506
index XXXXXXX..XXXXXXX 100755
507
--- a/tests/qemu-iotests/034
508
+++ b/tests/qemu-iotests/034
509
@@ -XXX,XX +XXX,XX @@
510
-#!/bin/bash
511
+#!/usr/bin/env bash
512
#
513
# Test bdrv_pwrite_zeroes with backing files (see also 154)
514
#
515
diff --git a/tests/qemu-iotests/035 b/tests/qemu-iotests/035
516
index XXXXXXX..XXXXXXX 100755
517
--- a/tests/qemu-iotests/035
518
+++ b/tests/qemu-iotests/035
519
@@ -XXX,XX +XXX,XX @@
520
-#!/bin/bash
521
+#!/usr/bin/env bash
522
#
523
# Let a few AIO requests run in parallel and have them access different L2
524
# tables so that the cache has a chance to get used up.
525
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
526
index XXXXXXX..XXXXXXX 100755
527
--- a/tests/qemu-iotests/036
528
+++ b/tests/qemu-iotests/036
529
@@ -XXX,XX +XXX,XX @@
530
-#!/bin/bash
531
+#!/usr/bin/env bash
532
#
533
# Test qcow2 feature bits
534
#
535
diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037
536
index XXXXXXX..XXXXXXX 100755
537
--- a/tests/qemu-iotests/037
538
+++ b/tests/qemu-iotests/037
539
@@ -XXX,XX +XXX,XX @@
540
-#!/bin/bash
541
+#!/usr/bin/env bash
542
#
543
# Test COW from backing files
544
#
545
diff --git a/tests/qemu-iotests/038 b/tests/qemu-iotests/038
546
index XXXXXXX..XXXXXXX 100755
547
--- a/tests/qemu-iotests/038
548
+++ b/tests/qemu-iotests/038
549
@@ -XXX,XX +XXX,XX @@
550
-#!/bin/bash
551
+#!/usr/bin/env bash
552
#
553
# Test COW from backing files with AIO
554
#
555
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
556
index XXXXXXX..XXXXXXX 100755
557
--- a/tests/qemu-iotests/039
558
+++ b/tests/qemu-iotests/039
559
@@ -XXX,XX +XXX,XX @@
560
-#!/bin/bash
561
+#!/usr/bin/env bash
562
#
563
# Test qcow2 lazy refcounts
564
#
565
diff --git a/tests/qemu-iotests/042 b/tests/qemu-iotests/042
566
index XXXXXXX..XXXXXXX 100755
567
--- a/tests/qemu-iotests/042
568
+++ b/tests/qemu-iotests/042
569
@@ -XXX,XX +XXX,XX @@
570
-#!/bin/bash
571
+#!/usr/bin/env bash
572
#
573
# Test qemu-img operation on zero size images
574
#
575
diff --git a/tests/qemu-iotests/043 b/tests/qemu-iotests/043
576
index XXXXXXX..XXXXXXX 100755
577
--- a/tests/qemu-iotests/043
578
+++ b/tests/qemu-iotests/043
579
@@ -XXX,XX +XXX,XX @@
580
-#!/bin/bash
581
+#!/usr/bin/env bash
582
#
583
# Test that qemu-img info --backing-chain detects infinite loops
584
#
585
diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046
586
index XXXXXXX..XXXXXXX 100755
587
--- a/tests/qemu-iotests/046
588
+++ b/tests/qemu-iotests/046
589
@@ -XXX,XX +XXX,XX @@
590
-#!/bin/bash
591
+#!/usr/bin/env bash
592
#
593
# Test concurrent cluster allocations
594
#
595
diff --git a/tests/qemu-iotests/047 b/tests/qemu-iotests/047
596
index XXXXXXX..XXXXXXX 100755
597
--- a/tests/qemu-iotests/047
598
+++ b/tests/qemu-iotests/047
599
@@ -XXX,XX +XXX,XX @@
600
-#!/bin/bash
601
+#!/usr/bin/env bash
602
#
603
# Regression test for commit b7ab0fea (which was a corruption fix,
604
# despite the commit message claiming otherwise)
605
diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048
606
index XXXXXXX..XXXXXXX 100755
607
--- a/tests/qemu-iotests/048
608
+++ b/tests/qemu-iotests/048
609
@@ -XXX,XX +XXX,XX @@
610
-#!/bin/bash
611
+#!/usr/bin/env bash
612
##
613
## qemu-img compare test
614
##
615
diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049
616
index XXXXXXX..XXXXXXX 100755
617
--- a/tests/qemu-iotests/049
618
+++ b/tests/qemu-iotests/049
619
@@ -XXX,XX +XXX,XX @@
620
-#!/bin/bash
621
+#!/usr/bin/env bash
622
#
623
# Check qemu-img option parsing
624
#
625
diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050
626
index XXXXXXX..XXXXXXX 100755
627
--- a/tests/qemu-iotests/050
628
+++ b/tests/qemu-iotests/050
629
@@ -XXX,XX +XXX,XX @@
630
-#!/bin/bash
631
+#!/usr/bin/env bash
632
#
633
# Test qemu-img rebase with zero clusters
634
#
635
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
636
index XXXXXXX..XXXXXXX 100755
637
--- a/tests/qemu-iotests/051
638
+++ b/tests/qemu-iotests/051
639
@@ -XXX,XX +XXX,XX @@
640
-#!/bin/bash
641
+#!/usr/bin/env bash
642
#
643
# Test command line configuration of block devices and driver-specific options
644
#
645
diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052
646
index XXXXXXX..XXXXXXX 100755
647
--- a/tests/qemu-iotests/052
648
+++ b/tests/qemu-iotests/052
649
@@ -XXX,XX +XXX,XX @@
650
-#!/bin/bash
651
+#!/usr/bin/env bash
652
#
653
# Test bdrv_read/bdrv_write using BDRV_O_SNAPSHOT
654
#
655
diff --git a/tests/qemu-iotests/053 b/tests/qemu-iotests/053
656
index XXXXXXX..XXXXXXX 100755
657
--- a/tests/qemu-iotests/053
658
+++ b/tests/qemu-iotests/053
659
@@ -XXX,XX +XXX,XX @@
660
-#!/bin/bash
661
+#!/usr/bin/env bash
662
#
663
# Test qemu-img convert when image length is not a multiple of cluster size
664
#
665
diff --git a/tests/qemu-iotests/054 b/tests/qemu-iotests/054
666
index XXXXXXX..XXXXXXX 100755
667
--- a/tests/qemu-iotests/054
668
+++ b/tests/qemu-iotests/054
669
@@ -XXX,XX +XXX,XX @@
670
-#!/bin/bash
671
+#!/usr/bin/env bash
672
#
673
# Test huge qcow2 images
674
#
675
diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058
676
index XXXXXXX..XXXXXXX 100755
677
--- a/tests/qemu-iotests/058
678
+++ b/tests/qemu-iotests/058
679
@@ -XXX,XX +XXX,XX @@
680
-#!/bin/bash
681
+#!/usr/bin/env bash
682
#
683
# Test export internal snapshot by qemu-nbd, convert it by qemu-img.
684
#
685
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
686
index XXXXXXX..XXXXXXX 100755
687
--- a/tests/qemu-iotests/059
688
+++ b/tests/qemu-iotests/059
689
@@ -XXX,XX +XXX,XX @@
690
-#!/bin/bash
691
+#!/usr/bin/env bash
692
#
693
# Test case for vmdk
694
#
695
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
696
index XXXXXXX..XXXXXXX 100755
697
--- a/tests/qemu-iotests/060
698
+++ b/tests/qemu-iotests/060
699
@@ -XXX,XX +XXX,XX @@
700
-#!/bin/bash
701
+#!/usr/bin/env bash
702
#
703
# Test case for image corruption (overlapping data structures) in qcow2
704
#
705
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
706
index XXXXXXX..XXXXXXX 100755
707
--- a/tests/qemu-iotests/061
708
+++ b/tests/qemu-iotests/061
709
@@ -XXX,XX +XXX,XX @@
710
-#!/bin/bash
711
+#!/usr/bin/env bash
712
#
713
# Test case for image option amendment in qcow2.
714
#
715
diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062
716
index XXXXXXX..XXXXXXX 100755
717
--- a/tests/qemu-iotests/062
718
+++ b/tests/qemu-iotests/062
719
@@ -XXX,XX +XXX,XX @@
720
-#!/bin/bash
721
+#!/usr/bin/env bash
722
#
723
# Test case for snapshotting images with unallocated zero clusters in
724
# qcow2
725
diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063
726
index XXXXXXX..XXXXXXX 100755
727
--- a/tests/qemu-iotests/063
728
+++ b/tests/qemu-iotests/063
729
@@ -XXX,XX +XXX,XX @@
730
-#!/bin/bash
731
+#!/usr/bin/env bash
732
#
733
# test of qemu-img convert -n - convert without creation
734
#
735
diff --git a/tests/qemu-iotests/064 b/tests/qemu-iotests/064
736
index XXXXXXX..XXXXXXX 100755
737
--- a/tests/qemu-iotests/064
738
+++ b/tests/qemu-iotests/064
739
@@ -XXX,XX +XXX,XX @@
740
-#!/bin/bash
741
+#!/usr/bin/env bash
742
#
743
# Test VHDX read/write from a sample image created with Hyper-V
744
#
745
diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066
746
index XXXXXXX..XXXXXXX 100755
747
--- a/tests/qemu-iotests/066
748
+++ b/tests/qemu-iotests/066
749
@@ -XXX,XX +XXX,XX @@
750
-#!/bin/bash
751
+#!/usr/bin/env bash
752
#
753
# Test case for preallocated zero clusters in qcow2
754
#
755
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
756
index XXXXXXX..XXXXXXX 100755
757
--- a/tests/qemu-iotests/067
758
+++ b/tests/qemu-iotests/067
759
@@ -XXX,XX +XXX,XX @@
760
-#!/bin/bash
761
+#!/usr/bin/env bash
762
#
763
# Test automatic deletion of BDSes created by -drive/drive_add
764
#
765
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
766
index XXXXXXX..XXXXXXX 100755
767
--- a/tests/qemu-iotests/068
768
+++ b/tests/qemu-iotests/068
769
@@ -XXX,XX +XXX,XX @@
770
-#!/bin/bash
771
+#!/usr/bin/env bash
772
#
773
# Test case for loading a saved VM state from a qcow2 image
774
#
775
diff --git a/tests/qemu-iotests/069 b/tests/qemu-iotests/069
776
index XXXXXXX..XXXXXXX 100755
777
--- a/tests/qemu-iotests/069
778
+++ b/tests/qemu-iotests/069
779
@@ -XXX,XX +XXX,XX @@
780
-#!/bin/bash
781
+#!/usr/bin/env bash
782
#
783
# Test case for deleting a backing file
784
#
785
diff --git a/tests/qemu-iotests/070 b/tests/qemu-iotests/070
786
index XXXXXXX..XXXXXXX 100755
787
--- a/tests/qemu-iotests/070
788
+++ b/tests/qemu-iotests/070
789
@@ -XXX,XX +XXX,XX @@
790
-#!/bin/bash
791
+#!/usr/bin/env bash
792
#
793
# Test VHDX log replay from an image with a journal that needs to be
794
# replayed
795
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
796
index XXXXXXX..XXXXXXX 100755
797
--- a/tests/qemu-iotests/071
798
+++ b/tests/qemu-iotests/071
799
@@ -XXX,XX +XXX,XX @@
800
-#!/bin/bash
801
+#!/usr/bin/env bash
802
#
803
# Test case for the QMP blkdebug and blkverify interfaces
804
#
805
diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072
806
index XXXXXXX..XXXXXXX 100755
807
--- a/tests/qemu-iotests/072
808
+++ b/tests/qemu-iotests/072
809
@@ -XXX,XX +XXX,XX @@
810
-#!/bin/bash
811
+#!/usr/bin/env bash
812
#
813
# Test case for nested image formats
814
#
815
diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073
816
index XXXXXXX..XXXXXXX 100755
817
--- a/tests/qemu-iotests/073
818
+++ b/tests/qemu-iotests/073
819
@@ -XXX,XX +XXX,XX @@
820
-#!/bin/bash
821
+#!/usr/bin/env bash
822
#
823
# Test count_contiguous_clusters in qcow2
824
#
825
diff --git a/tests/qemu-iotests/074 b/tests/qemu-iotests/074
826
index XXXXXXX..XXXXXXX 100755
827
--- a/tests/qemu-iotests/074
828
+++ b/tests/qemu-iotests/074
829
@@ -XXX,XX +XXX,XX @@
830
-#!/bin/bash
831
+#!/usr/bin/env bash
832
##
833
## qemu-img compare test (qcow2 only ones)
834
##
835
diff --git a/tests/qemu-iotests/075 b/tests/qemu-iotests/075
836
index XXXXXXX..XXXXXXX 100755
837
--- a/tests/qemu-iotests/075
838
+++ b/tests/qemu-iotests/075
839
@@ -XXX,XX +XXX,XX @@
840
-#!/bin/bash
841
+#!/usr/bin/env bash
842
#
843
# cloop format input validation tests
844
#
845
diff --git a/tests/qemu-iotests/076 b/tests/qemu-iotests/076
846
index XXXXXXX..XXXXXXX 100755
847
--- a/tests/qemu-iotests/076
848
+++ b/tests/qemu-iotests/076
849
@@ -XXX,XX +XXX,XX @@
850
-#!/bin/bash
851
+#!/usr/bin/env bash
852
#
853
# parallels format input validation tests
854
#
855
diff --git a/tests/qemu-iotests/077 b/tests/qemu-iotests/077
856
index XXXXXXX..XXXXXXX 100755
857
--- a/tests/qemu-iotests/077
858
+++ b/tests/qemu-iotests/077
859
@@ -XXX,XX +XXX,XX @@
860
-#!/bin/bash
861
+#!/usr/bin/env bash
862
#
863
# Test concurrent pread/pwrite
864
#
865
diff --git a/tests/qemu-iotests/078 b/tests/qemu-iotests/078
866
index XXXXXXX..XXXXXXX 100755
867
--- a/tests/qemu-iotests/078
868
+++ b/tests/qemu-iotests/078
869
@@ -XXX,XX +XXX,XX @@
870
-#!/bin/bash
871
+#!/usr/bin/env bash
872
#
873
# bochs format input validation tests
874
#
875
diff --git a/tests/qemu-iotests/079 b/tests/qemu-iotests/079
876
index XXXXXXX..XXXXXXX 100755
877
--- a/tests/qemu-iotests/079
878
+++ b/tests/qemu-iotests/079
879
@@ -XXX,XX +XXX,XX @@
880
-#!/bin/bash
881
+#!/usr/bin/env bash
882
#
883
# Test qcow2 preallocation with different cluster_sizes
884
#
885
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
886
index XXXXXXX..XXXXXXX 100755
887
--- a/tests/qemu-iotests/080
888
+++ b/tests/qemu-iotests/080
889
@@ -XXX,XX +XXX,XX @@
890
-#!/bin/bash
891
+#!/usr/bin/env bash
892
#
893
# qcow2 format input validation tests
894
#
895
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
896
index XXXXXXX..XXXXXXX 100755
897
--- a/tests/qemu-iotests/081
898
+++ b/tests/qemu-iotests/081
899
@@ -XXX,XX +XXX,XX @@
900
-#!/bin/bash
901
+#!/usr/bin/env bash
902
#
903
# Test Quorum block driver
904
#
905
diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082
906
index XXXXXXX..XXXXXXX 100755
907
--- a/tests/qemu-iotests/082
908
+++ b/tests/qemu-iotests/082
909
@@ -XXX,XX +XXX,XX @@
910
-#!/bin/bash
911
+#!/usr/bin/env bash
912
#
913
# Test qemu-img command line parsing
914
#
915
diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083
916
index XXXXXXX..XXXXXXX 100755
917
--- a/tests/qemu-iotests/083
918
+++ b/tests/qemu-iotests/083
919
@@ -XXX,XX +XXX,XX @@
920
-#!/bin/bash
921
+#!/usr/bin/env bash
922
#
923
# Test NBD client unexpected disconnect
924
#
925
diff --git a/tests/qemu-iotests/084 b/tests/qemu-iotests/084
926
index XXXXXXX..XXXXXXX 100755
927
--- a/tests/qemu-iotests/084
928
+++ b/tests/qemu-iotests/084
929
@@ -XXX,XX +XXX,XX @@
930
-#!/bin/bash
931
+#!/usr/bin/env bash
932
#
933
# Test case for VDI header corruption; image too large, and too many blocks.
934
# Also simple test for creating dynamic and static VDI images.
935
diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085
936
index XXXXXXX..XXXXXXX 100755
937
--- a/tests/qemu-iotests/085
938
+++ b/tests/qemu-iotests/085
939
@@ -XXX,XX +XXX,XX @@
940
-#!/bin/bash
941
+#!/usr/bin/env bash
942
#
943
# Live snapshot tests
944
#
945
diff --git a/tests/qemu-iotests/086 b/tests/qemu-iotests/086
946
index XXXXXXX..XXXXXXX 100755
947
--- a/tests/qemu-iotests/086
948
+++ b/tests/qemu-iotests/086
949
@@ -XXX,XX +XXX,XX @@
950
-#!/bin/bash
951
+#!/usr/bin/env bash
952
#
953
# Test qemu-img progress output
954
#
955
diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087
956
index XXXXXXX..XXXXXXX 100755
957
--- a/tests/qemu-iotests/087
958
+++ b/tests/qemu-iotests/087
959
@@ -XXX,XX +XXX,XX @@
960
-#!/bin/bash
961
+#!/usr/bin/env bash
962
#
963
# Test unsupported blockdev-add cases
964
#
965
diff --git a/tests/qemu-iotests/088 b/tests/qemu-iotests/088
966
index XXXXXXX..XXXXXXX 100755
967
--- a/tests/qemu-iotests/088
968
+++ b/tests/qemu-iotests/088
969
@@ -XXX,XX +XXX,XX @@
970
-#!/bin/bash
971
+#!/usr/bin/env bash
972
#
973
# vpc (VHD) format input validation tests
974
#
975
diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089
976
index XXXXXXX..XXXXXXX 100755
977
--- a/tests/qemu-iotests/089
978
+++ b/tests/qemu-iotests/089
979
@@ -XXX,XX +XXX,XX @@
980
-#!/bin/bash
981
+#!/usr/bin/env bash
982
#
983
# Test case for support of JSON filenames
984
#
985
diff --git a/tests/qemu-iotests/090 b/tests/qemu-iotests/090
986
index XXXXXXX..XXXXXXX 100755
987
--- a/tests/qemu-iotests/090
988
+++ b/tests/qemu-iotests/090
989
@@ -XXX,XX +XXX,XX @@
990
-#!/bin/bash
991
+#!/usr/bin/env bash
992
#
993
# Test for discarding compressed clusters on qcow2 images
994
#
995
diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
996
index XXXXXXX..XXXXXXX 100755
997
--- a/tests/qemu-iotests/091
998
+++ b/tests/qemu-iotests/091
999
@@ -XXX,XX +XXX,XX @@
1000
-#!/bin/bash
1001
+#!/usr/bin/env bash
1002
#
1003
# Live migration test
1004
#
1005
diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092
1006
index XXXXXXX..XXXXXXX 100755
1007
--- a/tests/qemu-iotests/092
1008
+++ b/tests/qemu-iotests/092
1009
@@ -XXX,XX +XXX,XX @@
1010
-#!/bin/bash
1011
+#!/usr/bin/env bash
1012
#
1013
# qcow1 format input validation tests
1014
#
1015
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
1016
index XXXXXXX..XXXXXXX 100755
1017
--- a/tests/qemu-iotests/094
1018
+++ b/tests/qemu-iotests/094
1019
@@ -XXX,XX +XXX,XX @@
1020
-#!/bin/bash
1021
+#!/usr/bin/env bash
1022
#
1023
# Test case for drive-mirror to NBD
1024
#
1025
diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095
1026
index XXXXXXX..XXXXXXX 100755
1027
--- a/tests/qemu-iotests/095
1028
+++ b/tests/qemu-iotests/095
1029
@@ -XXX,XX +XXX,XX @@
1030
-#!/bin/bash
1031
+#!/usr/bin/env bash
1032
#
1033
# Test for commit of larger active layer
1034
#
1035
diff --git a/tests/qemu-iotests/097 b/tests/qemu-iotests/097
1036
index XXXXXXX..XXXXXXX 100755
1037
--- a/tests/qemu-iotests/097
1038
+++ b/tests/qemu-iotests/097
1039
@@ -XXX,XX +XXX,XX @@
1040
-#!/bin/bash
1041
+#!/usr/bin/env bash
1042
#
1043
# Commit changes into backing chains and empty the top image if the
1044
# backing image is not explicitly specified
1045
diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098
1046
index XXXXXXX..XXXXXXX 100755
1047
--- a/tests/qemu-iotests/098
1048
+++ b/tests/qemu-iotests/098
1049
@@ -XXX,XX +XXX,XX @@
1050
-#!/bin/bash
1051
+#!/usr/bin/env bash
1052
#
1053
# Test qcow2's bdrv_make_empty for images without internal snapshots
1054
#
1055
diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099
1056
index XXXXXXX..XXXXXXX 100755
1057
--- a/tests/qemu-iotests/099
1058
+++ b/tests/qemu-iotests/099
1059
@@ -XXX,XX +XXX,XX @@
1060
-#!/bin/bash
1061
+#!/usr/bin/env bash
1062
#
1063
# Test valid filenames for blkdebug and blkverify representatively for
1064
# other protocols (such as NBD) when queried
1065
diff --git a/tests/qemu-iotests/101 b/tests/qemu-iotests/101
1066
index XXXXXXX..XXXXXXX 100755
1067
--- a/tests/qemu-iotests/101
1068
+++ b/tests/qemu-iotests/101
1069
@@ -XXX,XX +XXX,XX @@
1070
-#!/bin/bash
1071
+#!/usr/bin/env bash
1072
#
1073
# Test short file I/O
1074
#
1075
diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102
1076
index XXXXXXX..XXXXXXX 100755
1077
--- a/tests/qemu-iotests/102
1078
+++ b/tests/qemu-iotests/102
1079
@@ -XXX,XX +XXX,XX @@
1080
-#!/bin/bash
1081
+#!/usr/bin/env bash
1082
#
1083
# Test case for qemu-io -c map and qemu-img map
1084
#
1085
diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103
1086
index XXXXXXX..XXXXXXX 100755
1087
--- a/tests/qemu-iotests/103
1088
+++ b/tests/qemu-iotests/103
1089
@@ -XXX,XX +XXX,XX @@
1090
-#!/bin/bash
1091
+#!/usr/bin/env bash
1092
#
1093
# Test case for qcow2 metadata cache size specification
1094
#
1095
diff --git a/tests/qemu-iotests/104 b/tests/qemu-iotests/104
1096
index XXXXXXX..XXXXXXX 100755
1097
--- a/tests/qemu-iotests/104
1098
+++ b/tests/qemu-iotests/104
1099
@@ -XXX,XX +XXX,XX @@
1100
-#!/bin/bash
1101
+#!/usr/bin/env bash
1102
#
1103
# Test image creation with aligned and unaligned sizes
1104
#
1105
diff --git a/tests/qemu-iotests/105 b/tests/qemu-iotests/105
1106
index XXXXXXX..XXXXXXX 100755
1107
--- a/tests/qemu-iotests/105
1108
+++ b/tests/qemu-iotests/105
1109
@@ -XXX,XX +XXX,XX @@
1110
-#!/bin/bash
1111
+#!/usr/bin/env bash
1112
#
1113
# Create, read, write big image
1114
#
1115
diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106
1116
index XXXXXXX..XXXXXXX 100755
1117
--- a/tests/qemu-iotests/106
1118
+++ b/tests/qemu-iotests/106
1119
@@ -XXX,XX +XXX,XX @@
1120
-#!/bin/bash
1121
+#!/usr/bin/env bash
1122
#
1123
# Test preallocated resize of raw images
1124
#
1125
diff --git a/tests/qemu-iotests/107 b/tests/qemu-iotests/107
1126
index XXXXXXX..XXXXXXX 100755
1127
--- a/tests/qemu-iotests/107
1128
+++ b/tests/qemu-iotests/107
1129
@@ -XXX,XX +XXX,XX @@
1130
-#!/bin/bash
1131
+#!/usr/bin/env bash
1132
#
1133
# Tests updates of the qcow2 L1 table
1134
#
1135
diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108
1136
index XXXXXXX..XXXXXXX 100755
1137
--- a/tests/qemu-iotests/108
1138
+++ b/tests/qemu-iotests/108
1139
@@ -XXX,XX +XXX,XX @@
1140
-#!/bin/bash
1141
+#!/usr/bin/env bash
1142
#
1143
# Test case for repairing qcow2 images which cannot be repaired using
1144
# the on-disk refcount structures
1145
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
1146
index XXXXXXX..XXXXXXX 100755
1147
--- a/tests/qemu-iotests/109
1148
+++ b/tests/qemu-iotests/109
1149
@@ -XXX,XX +XXX,XX @@
1150
-#!/bin/bash
1151
+#!/usr/bin/env bash
1152
#
1153
# Test writing image headers of other formats into raw images
1154
#
1155
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
1156
index XXXXXXX..XXXXXXX 100755
1157
--- a/tests/qemu-iotests/110
1158
+++ b/tests/qemu-iotests/110
1159
@@ -XXX,XX +XXX,XX @@
1160
-#!/bin/bash
1161
+#!/usr/bin/env bash
1162
#
1163
# Test case for relative backing file names in complex BDS trees
1164
#
1165
diff --git a/tests/qemu-iotests/111 b/tests/qemu-iotests/111
1166
index XXXXXXX..XXXXXXX 100755
1167
--- a/tests/qemu-iotests/111
1168
+++ b/tests/qemu-iotests/111
1169
@@ -XXX,XX +XXX,XX @@
1170
-#!/bin/bash
1171
+#!/usr/bin/env bash
1172
#
1173
# Test case for non-existing backing file when creating a qcow2 image
1174
# and not specifying the size
1175
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
1176
index XXXXXXX..XXXXXXX 100755
1177
--- a/tests/qemu-iotests/112
1178
+++ b/tests/qemu-iotests/112
1179
@@ -XXX,XX +XXX,XX @@
1180
-#!/bin/bash
1181
+#!/usr/bin/env bash
1182
#
1183
# Test cases for different refcount_bits values
1184
#
1185
diff --git a/tests/qemu-iotests/113 b/tests/qemu-iotests/113
1186
index XXXXXXX..XXXXXXX 100755
1187
--- a/tests/qemu-iotests/113
1188
+++ b/tests/qemu-iotests/113
1189
@@ -XXX,XX +XXX,XX @@
1190
-#!/bin/bash
1191
+#!/usr/bin/env bash
1192
#
1193
# Test case for accessing creation options on image formats and
1194
# protocols not supporting image creation
1195
diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114
1196
index XXXXXXX..XXXXXXX 100755
1197
--- a/tests/qemu-iotests/114
1198
+++ b/tests/qemu-iotests/114
1199
@@ -XXX,XX +XXX,XX @@
1200
-#!/bin/bash
1201
+#!/usr/bin/env bash
1202
#
1203
# Test invalid backing file format in qcow2 images
1204
#
1205
diff --git a/tests/qemu-iotests/115 b/tests/qemu-iotests/115
1206
index XXXXXXX..XXXXXXX 100755
1207
--- a/tests/qemu-iotests/115
1208
+++ b/tests/qemu-iotests/115
1209
@@ -XXX,XX +XXX,XX @@
1210
-#!/bin/bash
1211
+#!/usr/bin/env bash
1212
#
1213
# Test case for non-self-referential qcow2 refcount blocks
1214
#
1215
diff --git a/tests/qemu-iotests/116 b/tests/qemu-iotests/116
1216
index XXXXXXX..XXXXXXX 100755
1217
--- a/tests/qemu-iotests/116
1218
+++ b/tests/qemu-iotests/116
1219
@@ -XXX,XX +XXX,XX @@
1220
-#!/bin/bash
1221
+#!/usr/bin/env bash
1222
#
1223
# Test error code paths for invalid QED images
1224
#
1225
diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117
1226
index XXXXXXX..XXXXXXX 100755
1227
--- a/tests/qemu-iotests/117
1228
+++ b/tests/qemu-iotests/117
1229
@@ -XXX,XX +XXX,XX @@
1230
-#!/bin/bash
1231
+#!/usr/bin/env bash
1232
#
1233
# Test case for shared BDS between backend trees
1234
#
1235
diff --git a/tests/qemu-iotests/119 b/tests/qemu-iotests/119
1236
index XXXXXXX..XXXXXXX 100755
1237
--- a/tests/qemu-iotests/119
1238
+++ b/tests/qemu-iotests/119
1239
@@ -XXX,XX +XXX,XX @@
1240
-#!/bin/bash
1241
+#!/usr/bin/env bash
1242
#
1243
# NBD test case for overriding BDRV_O_PROTOCOL by explicitly specifying
1244
# a driver
1245
diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120
1246
index XXXXXXX..XXXXXXX 100755
1247
--- a/tests/qemu-iotests/120
1248
+++ b/tests/qemu-iotests/120
1249
@@ -XXX,XX +XXX,XX @@
1250
-#!/bin/bash
1251
+#!/usr/bin/env bash
1252
#
1253
# Non-NBD test cases for overriding BDRV_O_PROTOCOL by explicitly
1254
# specifying a driver
1255
diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121
1256
index XXXXXXX..XXXXXXX 100755
1257
--- a/tests/qemu-iotests/121
1258
+++ b/tests/qemu-iotests/121
1259
@@ -XXX,XX +XXX,XX @@
1260
-#!/bin/bash
1261
+#!/usr/bin/env bash
1262
#
1263
# Test cases for qcow2 refcount table growth
1264
#
1265
diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122
1266
index XXXXXXX..XXXXXXX 100755
1267
--- a/tests/qemu-iotests/122
1268
+++ b/tests/qemu-iotests/122
1269
@@ -XXX,XX +XXX,XX @@
1270
-#!/bin/bash
1271
+#!/usr/bin/env bash
1272
#
1273
# Test some qemu-img convert cases
1274
#
1275
diff --git a/tests/qemu-iotests/123 b/tests/qemu-iotests/123
1276
index XXXXXXX..XXXXXXX 100755
1277
--- a/tests/qemu-iotests/123
1278
+++ b/tests/qemu-iotests/123
1279
@@ -XXX,XX +XXX,XX @@
1280
-#!/bin/bash
1281
+#!/usr/bin/env bash
1282
#
1283
# Test case for qemu-img convert to NBD
1284
#
1285
diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125
1286
index XXXXXXX..XXXXXXX 100755
1287
--- a/tests/qemu-iotests/125
1288
+++ b/tests/qemu-iotests/125
1289
@@ -XXX,XX +XXX,XX @@
1290
-#!/bin/bash
1291
+#!/usr/bin/env bash
1292
#
1293
# Test preallocated growth of qcow2 images
1294
#
1295
diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126
1296
index XXXXXXX..XXXXXXX 100755
1297
--- a/tests/qemu-iotests/126
1298
+++ b/tests/qemu-iotests/126
1299
@@ -XXX,XX +XXX,XX @@
1300
-#!/bin/bash
1301
+#!/usr/bin/env bash
1302
#
1303
# Tests handling of colons in filenames (which may be confused with protocol
1304
# prefixes)
1305
diff --git a/tests/qemu-iotests/127 b/tests/qemu-iotests/127
1306
index XXXXXXX..XXXXXXX 100755
1307
--- a/tests/qemu-iotests/127
1308
+++ b/tests/qemu-iotests/127
1309
@@ -XXX,XX +XXX,XX @@
1310
-#!/bin/bash
1311
+#!/usr/bin/env bash
1312
#
1313
# Test case for mirroring with dataplane
1314
#
1315
diff --git a/tests/qemu-iotests/128 b/tests/qemu-iotests/128
1316
index XXXXXXX..XXXXXXX 100755
1317
--- a/tests/qemu-iotests/128
1318
+++ b/tests/qemu-iotests/128
1319
@@ -XXX,XX +XXX,XX @@
1320
-#!/bin/bash
1321
+#!/usr/bin/env bash
1322
#
1323
# Test that opening O_DIRECT succeeds when image file I/O produces EIO
1324
#
1325
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
1326
index XXXXXXX..XXXXXXX 100755
1327
--- a/tests/qemu-iotests/130
1328
+++ b/tests/qemu-iotests/130
1329
@@ -XXX,XX +XXX,XX @@
1330
-#!/bin/bash
1331
+#!/usr/bin/env bash
1332
#
1333
# Test that temporary backing file overrides (on the command line or in
1334
# blockdev-add) don't replace the original path stored in the image during
1335
diff --git a/tests/qemu-iotests/131 b/tests/qemu-iotests/131
1336
index XXXXXXX..XXXXXXX 100755
1337
--- a/tests/qemu-iotests/131
1338
+++ b/tests/qemu-iotests/131
1339
@@ -XXX,XX +XXX,XX @@
1340
-#!/bin/bash
1341
+#!/usr/bin/env bash
1342
#
1343
# parallels format validation tests (created by QEMU)
1344
#
1345
diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133
1346
index XXXXXXX..XXXXXXX 100755
1347
--- a/tests/qemu-iotests/133
1348
+++ b/tests/qemu-iotests/133
1349
@@ -XXX,XX +XXX,XX @@
1350
-#!/bin/bash
1351
+#!/usr/bin/env bash
1352
#
1353
# Test for reopen
1354
#
1355
diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134
1356
index XXXXXXX..XXXXXXX 100755
1357
--- a/tests/qemu-iotests/134
1358
+++ b/tests/qemu-iotests/134
1359
@@ -XXX,XX +XXX,XX @@
1360
-#!/bin/bash
1361
+#!/usr/bin/env bash
1362
#
1363
# Test encrypted read/write using plain bdrv_read/bdrv_write
1364
#
1365
diff --git a/tests/qemu-iotests/135 b/tests/qemu-iotests/135
1366
index XXXXXXX..XXXXXXX 100755
1367
--- a/tests/qemu-iotests/135
1368
+++ b/tests/qemu-iotests/135
1369
@@ -XXX,XX +XXX,XX @@
1370
-#!/bin/bash
1371
+#!/usr/bin/env bash
1372
#
1373
# Test VPC open of image with large Max Table Entries value.
1374
#
1375
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
1376
index XXXXXXX..XXXXXXX 100755
1377
--- a/tests/qemu-iotests/137
1378
+++ b/tests/qemu-iotests/137
1379
@@ -XXX,XX +XXX,XX @@
1380
-#!/bin/bash
1381
+#!/usr/bin/env bash
1382
#
1383
# Test qcow2 reopen
1384
#
1385
diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138
1386
index XXXXXXX..XXXXXXX 100755
1387
--- a/tests/qemu-iotests/138
1388
+++ b/tests/qemu-iotests/138
1389
@@ -XXX,XX +XXX,XX @@
1390
-#!/bin/bash
1391
+#!/usr/bin/env bash
1392
#
1393
# General test case for qcow2's image check
1394
#
1395
diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140
1396
index XXXXXXX..XXXXXXX 100755
1397
--- a/tests/qemu-iotests/140
1398
+++ b/tests/qemu-iotests/140
1399
@@ -XXX,XX +XXX,XX @@
1400
-#!/bin/bash
1401
+#!/usr/bin/env bash
1402
#
1403
# Test case for ejecting a BlockBackend with an NBD server attached to it
1404
#
1405
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
1406
index XXXXXXX..XXXXXXX 100755
1407
--- a/tests/qemu-iotests/141
1408
+++ b/tests/qemu-iotests/141
1409
@@ -XXX,XX +XXX,XX @@
1410
-#!/bin/bash
1411
+#!/usr/bin/env bash
1412
#
1413
# Test case for ejecting BDSs with block jobs still running on them
1414
#
1415
diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142
1416
index XXXXXXX..XXXXXXX 100755
1417
--- a/tests/qemu-iotests/142
1418
+++ b/tests/qemu-iotests/142
1419
@@ -XXX,XX +XXX,XX @@
1420
-#!/bin/bash
1421
+#!/usr/bin/env bash
1422
#
1423
# Test for configuring cache modes of arbitrary nodes (requires O_DIRECT)
1424
#
1425
diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143
1426
index XXXXXXX..XXXXXXX 100755
1427
--- a/tests/qemu-iotests/143
1428
+++ b/tests/qemu-iotests/143
1429
@@ -XXX,XX +XXX,XX @@
1430
-#!/bin/bash
1431
+#!/usr/bin/env bash
1432
#
1433
# Test case for connecting to a non-existing NBD export name
1434
#
1435
diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144
1436
index XXXXXXX..XXXXXXX 100755
1437
--- a/tests/qemu-iotests/144
1438
+++ b/tests/qemu-iotests/144
1439
@@ -XXX,XX +XXX,XX @@
1440
-#!/bin/bash
1441
+#!/usr/bin/env bash
1442
# Check live snapshot, followed by active commit, and another snapshot.
1443
#
1444
# This test is to catch the error case of BZ #1300209:
1445
diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145
1446
index XXXXXXX..XXXXXXX 100755
1447
--- a/tests/qemu-iotests/145
1448
+++ b/tests/qemu-iotests/145
1449
@@ -XXX,XX +XXX,XX @@
1450
-#!/bin/bash
1451
+#!/usr/bin/env bash
1452
#
1453
# Test the combination of -incoming and snapshot=on
1454
#
1455
diff --git a/tests/qemu-iotests/146 b/tests/qemu-iotests/146
1456
index XXXXXXX..XXXXXXX 100755
1457
--- a/tests/qemu-iotests/146
1458
+++ b/tests/qemu-iotests/146
1459
@@ -XXX,XX +XXX,XX @@
1460
-#!/bin/bash
1461
+#!/usr/bin/env bash
1462
#
1463
# Test VHD image format creator detection and override
1464
#
1465
diff --git a/tests/qemu-iotests/150 b/tests/qemu-iotests/150
1466
index XXXXXXX..XXXXXXX 100755
1467
--- a/tests/qemu-iotests/150
1468
+++ b/tests/qemu-iotests/150
1469
@@ -XXX,XX +XXX,XX @@
1470
-#!/bin/bash
1471
+#!/usr/bin/env bash
1472
#
1473
# Test that qemu-img convert -S 0 fully allocates the target image
1474
#
1475
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
1476
index XXXXXXX..XXXXXXX 100755
1477
--- a/tests/qemu-iotests/153
1478
+++ b/tests/qemu-iotests/153
1479
@@ -XXX,XX +XXX,XX @@
1480
-#!/bin/bash
1481
+#!/usr/bin/env bash
1482
#
1483
# Test image locking
1484
#
1485
diff --git a/tests/qemu-iotests/154 b/tests/qemu-iotests/154
1486
index XXXXXXX..XXXXXXX 100755
1487
--- a/tests/qemu-iotests/154
1488
+++ b/tests/qemu-iotests/154
1489
@@ -XXX,XX +XXX,XX @@
1490
-#!/bin/bash
1491
+#!/usr/bin/env bash
1492
#
1493
# qcow2 specific bdrv_pwrite_zeroes tests with backing files (complements 034)
1494
#
1495
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
1496
index XXXXXXX..XXXXXXX 100755
1497
--- a/tests/qemu-iotests/156
1498
+++ b/tests/qemu-iotests/156
1499
@@ -XXX,XX +XXX,XX @@
1500
-#!/bin/bash
1501
+#!/usr/bin/env bash
1502
#
1503
# Tests oVirt-like storage migration:
1504
# - Create snapshot
1505
diff --git a/tests/qemu-iotests/157 b/tests/qemu-iotests/157
1506
index XXXXXXX..XXXXXXX 100755
1507
--- a/tests/qemu-iotests/157
1508
+++ b/tests/qemu-iotests/157
1509
@@ -XXX,XX +XXX,XX @@
1510
-#!/bin/bash
1511
+#!/usr/bin/env bash
1512
#
1513
# Test command line configuration of block devices with qdev
1514
#
1515
diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158
1516
index XXXXXXX..XXXXXXX 100755
1517
--- a/tests/qemu-iotests/158
1518
+++ b/tests/qemu-iotests/158
1519
@@ -XXX,XX +XXX,XX @@
1520
-#!/bin/bash
1521
+#!/usr/bin/env bash
1522
#
1523
# Test encrypted read/write using backing files
1524
#
1525
diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159
1526
index XXXXXXX..XXXXXXX 100755
1527
--- a/tests/qemu-iotests/159
1528
+++ b/tests/qemu-iotests/159
1529
@@ -XXX,XX +XXX,XX @@
1530
-#! /bin/bash
1531
+#!/usr/bin/env bash
1532
#
1533
# qemu-img dd test with different block sizes
1534
#
1535
diff --git a/tests/qemu-iotests/160 b/tests/qemu-iotests/160
1536
index XXXXXXX..XXXXXXX 100755
1537
--- a/tests/qemu-iotests/160
1538
+++ b/tests/qemu-iotests/160
1539
@@ -XXX,XX +XXX,XX @@
1540
-#! /bin/bash
1541
+#!/usr/bin/env bash
1542
#
1543
# qemu-img dd test for the skip option
1544
#
1545
diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161
1546
index XXXXXXX..XXXXXXX 100755
1547
--- a/tests/qemu-iotests/161
1548
+++ b/tests/qemu-iotests/161
1549
@@ -XXX,XX +XXX,XX @@
1550
-#!/bin/bash
1551
+#!/usr/bin/env bash
1552
#
1553
# Test reopening a backing image after block-stream and block-commit
1554
#
1555
diff --git a/tests/qemu-iotests/162 b/tests/qemu-iotests/162
1556
index XXXXXXX..XXXXXXX 100755
1557
--- a/tests/qemu-iotests/162
1558
+++ b/tests/qemu-iotests/162
1559
@@ -XXX,XX +XXX,XX @@
1560
-#!/bin/bash
1561
+#!/usr/bin/env bash
1562
#
1563
# Test case for specifying runtime options of the wrong type to some
1564
# block drivers
1565
diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170
1566
index XXXXXXX..XXXXXXX 100755
1567
--- a/tests/qemu-iotests/170
1568
+++ b/tests/qemu-iotests/170
1569
@@ -XXX,XX +XXX,XX @@
1570
-#! /bin/bash
1571
+#!/usr/bin/env bash
1572
#
1573
# qemu-img dd test
1574
#
1575
diff --git a/tests/qemu-iotests/171 b/tests/qemu-iotests/171
1576
index XXXXXXX..XXXXXXX 100755
1577
--- a/tests/qemu-iotests/171
1578
+++ b/tests/qemu-iotests/171
1579
@@ -XXX,XX +XXX,XX @@
1580
-#!/bin/bash
1581
+#!/usr/bin/env bash
1582
#
1583
# Test 'offset' and 'size' options of the raw driver. Make sure we can't
1584
# (or can) read and write outside of the image size.
1585
diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172
1586
index XXXXXXX..XXXXXXX 100755
1587
--- a/tests/qemu-iotests/172
1588
+++ b/tests/qemu-iotests/172
1589
@@ -XXX,XX +XXX,XX @@
1590
-#!/bin/bash
1591
+#!/usr/bin/env bash
1592
#
1593
# Test floppy configuration
1594
#
1595
diff --git a/tests/qemu-iotests/173 b/tests/qemu-iotests/173
1596
index XXXXXXX..XXXXXXX 100755
1597
--- a/tests/qemu-iotests/173
1598
+++ b/tests/qemu-iotests/173
1599
@@ -XXX,XX +XXX,XX @@
1600
-#!/bin/bash
1601
+#!/usr/bin/env bash
1602
#
1603
# Test QAPI commands looking up protocol based images with relative
1604
# filename backing strings
1605
diff --git a/tests/qemu-iotests/174 b/tests/qemu-iotests/174
1606
index XXXXXXX..XXXXXXX 100755
1607
--- a/tests/qemu-iotests/174
1608
+++ b/tests/qemu-iotests/174
1609
@@ -XXX,XX +XXX,XX @@
1610
-#!/bin/bash
1611
+#!/usr/bin/env bash
1612
#
1613
# Test that qemu-io fail with non-zero exit code
1614
#
1615
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
1616
index XXXXXXX..XXXXXXX 100755
1617
--- a/tests/qemu-iotests/175
1618
+++ b/tests/qemu-iotests/175
1619
@@ -XXX,XX +XXX,XX @@
1620
-#!/bin/bash
1621
+#!/usr/bin/env bash
1622
#
1623
# Test creating raw image preallocation mode
1624
#
1625
diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176
1626
index XXXXXXX..XXXXXXX 100755
1627
--- a/tests/qemu-iotests/176
1628
+++ b/tests/qemu-iotests/176
1629
@@ -XXX,XX +XXX,XX @@
1630
-#!/bin/bash
1631
+#!/usr/bin/env bash
1632
#
1633
# Commit changes into backing chains and empty the top image if the
1634
# backing image is not explicitly specified.
1635
diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177
1636
index XXXXXXX..XXXXXXX 100755
1637
--- a/tests/qemu-iotests/177
1638
+++ b/tests/qemu-iotests/177
1639
@@ -XXX,XX +XXX,XX @@
1640
-#!/bin/bash
1641
+#!/usr/bin/env bash
1642
#
1643
# Test corner cases with unusual block geometries
1644
#
1645
diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178
1646
index XXXXXXX..XXXXXXX 100755
1647
--- a/tests/qemu-iotests/178
1648
+++ b/tests/qemu-iotests/178
1649
@@ -XXX,XX +XXX,XX @@
1650
-#!/bin/bash
1651
+#!/usr/bin/env bash
1652
#
1653
# qemu-img measure sub-command tests
1654
#
1655
diff --git a/tests/qemu-iotests/179 b/tests/qemu-iotests/179
1656
index XXXXXXX..XXXXXXX 100755
1657
--- a/tests/qemu-iotests/179
1658
+++ b/tests/qemu-iotests/179
1659
@@ -XXX,XX +XXX,XX @@
1660
-#!/bin/bash
1661
+#!/usr/bin/env bash
1662
#
1663
# Test case for write zeroes with unmap
1664
#
1665
diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181
1666
index XXXXXXX..XXXXXXX 100755
1667
--- a/tests/qemu-iotests/181
1668
+++ b/tests/qemu-iotests/181
1669
@@ -XXX,XX +XXX,XX @@
1670
-#!/bin/bash
1671
+#!/usr/bin/env bash
1672
#
1673
# Test postcopy live migration with shared storage
1674
#
1675
diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182
1676
index XXXXXXX..XXXXXXX 100755
1677
--- a/tests/qemu-iotests/182
1678
+++ b/tests/qemu-iotests/182
1679
@@ -XXX,XX +XXX,XX @@
1680
-#!/bin/bash
1681
+#!/usr/bin/env bash
1682
#
1683
# Test image locking for POSIX locks
1684
#
1685
diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183
1686
index XXXXXXX..XXXXXXX 100755
1687
--- a/tests/qemu-iotests/183
1688
+++ b/tests/qemu-iotests/183
1689
@@ -XXX,XX +XXX,XX @@
1690
-#!/bin/bash
1691
+#!/usr/bin/env bash
1692
#
1693
# Test old-style block migration (migrate -b)
1694
#
1695
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
1696
index XXXXXXX..XXXXXXX 100755
1697
--- a/tests/qemu-iotests/184
1698
+++ b/tests/qemu-iotests/184
1699
@@ -XXX,XX +XXX,XX @@
1700
-#!/bin/bash
1701
+#!/usr/bin/env bash
1702
#
1703
# Test I/O throttle block filter driver interface
1704
#
1705
diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185
1706
index XXXXXXX..XXXXXXX 100755
1707
--- a/tests/qemu-iotests/185
1708
+++ b/tests/qemu-iotests/185
1709
@@ -XXX,XX +XXX,XX @@
1710
-#!/bin/bash
1711
+#!/usr/bin/env bash
1712
#
1713
# Test exiting qemu while jobs are still running
1714
#
1715
diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186
1716
index XXXXXXX..XXXXXXX 100755
1717
--- a/tests/qemu-iotests/186
1718
+++ b/tests/qemu-iotests/186
1719
@@ -XXX,XX +XXX,XX @@
1720
-#!/bin/bash
1721
+#!/usr/bin/env bash
1722
#
1723
# Test 'info block' with all kinds of configurations
1724
#
1725
diff --git a/tests/qemu-iotests/187 b/tests/qemu-iotests/187
1726
index XXXXXXX..XXXXXXX 100755
1727
--- a/tests/qemu-iotests/187
1728
+++ b/tests/qemu-iotests/187
1729
@@ -XXX,XX +XXX,XX @@
1730
-#!/bin/bash
1731
+#!/usr/bin/env bash
1732
#
1733
# Test switching between read-only and read-write
1734
#
1735
diff --git a/tests/qemu-iotests/188 b/tests/qemu-iotests/188
1736
index XXXXXXX..XXXXXXX 100755
1737
--- a/tests/qemu-iotests/188
1738
+++ b/tests/qemu-iotests/188
1739
@@ -XXX,XX +XXX,XX @@
1740
-#!/bin/bash
1741
+#!/usr/bin/env bash
1742
#
1743
# Test encrypted read/write using plain bdrv_read/bdrv_write
1744
#
1745
diff --git a/tests/qemu-iotests/189 b/tests/qemu-iotests/189
1746
index XXXXXXX..XXXXXXX 100755
1747
--- a/tests/qemu-iotests/189
1748
+++ b/tests/qemu-iotests/189
1749
@@ -XXX,XX +XXX,XX @@
1750
-#!/bin/bash
1751
+#!/usr/bin/env bash
1752
#
1753
# Test encrypted read/write using backing files
1754
#
1755
diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190
1756
index XXXXXXX..XXXXXXX 100755
1757
--- a/tests/qemu-iotests/190
1758
+++ b/tests/qemu-iotests/190
1759
@@ -XXX,XX +XXX,XX @@
1760
-#!/bin/bash
1761
+#!/usr/bin/env bash
1762
#
1763
# qemu-img measure sub-command tests on huge qcow2 files
1764
#
1765
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
1766
index XXXXXXX..XXXXXXX 100755
1767
--- a/tests/qemu-iotests/191
1768
+++ b/tests/qemu-iotests/191
1769
@@ -XXX,XX +XXX,XX @@
1770
-#!/bin/bash
1771
+#!/usr/bin/env bash
1772
#
1773
# Test commit block job where top has two parents
1774
#
1775
diff --git a/tests/qemu-iotests/192 b/tests/qemu-iotests/192
1776
index XXXXXXX..XXXXXXX 100755
1777
--- a/tests/qemu-iotests/192
1778
+++ b/tests/qemu-iotests/192
1779
@@ -XXX,XX +XXX,XX @@
1780
-#!/bin/bash
1781
+#!/usr/bin/env bash
1782
#
1783
# Test NBD export with -incoming (non-shared storage migration use case from
1784
# libvirt)
1785
diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195
1786
index XXXXXXX..XXXXXXX 100755
1787
--- a/tests/qemu-iotests/195
1788
+++ b/tests/qemu-iotests/195
1789
@@ -XXX,XX +XXX,XX @@
1790
-#!/bin/bash
1791
+#!/usr/bin/env bash
1792
#
1793
# Test change-backing-file command
1794
#
1795
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
1796
index XXXXXXX..XXXXXXX 100755
1797
--- a/tests/qemu-iotests/197
1798
+++ b/tests/qemu-iotests/197
1799
@@ -XXX,XX +XXX,XX @@
1800
-#!/bin/bash
1801
+#!/usr/bin/env bash
1802
#
1803
# Test case for copy-on-read into qcow2
1804
#
1805
diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198
1806
index XXXXXXX..XXXXXXX 100755
1807
--- a/tests/qemu-iotests/198
1808
+++ b/tests/qemu-iotests/198
1809
@@ -XXX,XX +XXX,XX @@
1810
-#!/bin/bash
1811
+#!/usr/bin/env bash
1812
#
1813
# Test commit of encrypted qcow2 files
1814
#
1815
diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200
1816
index XXXXXXX..XXXXXXX 100755
1817
--- a/tests/qemu-iotests/200
1818
+++ b/tests/qemu-iotests/200
1819
@@ -XXX,XX +XXX,XX @@
1820
-#!/bin/bash
1821
+#!/usr/bin/env bash
1822
#
1823
# Block job co-routine race condition test.
1824
#
1825
diff --git a/tests/qemu-iotests/201 b/tests/qemu-iotests/201
1826
index XXXXXXX..XXXXXXX 100755
1827
--- a/tests/qemu-iotests/201
1828
+++ b/tests/qemu-iotests/201
1829
@@ -XXX,XX +XXX,XX @@
1830
-#!/bin/bash
1831
+#!/usr/bin/env bash
1832
#
1833
# Test savevm and loadvm after live migration with postcopy flag
1834
#
1835
diff --git a/tests/qemu-iotests/204 b/tests/qemu-iotests/204
1836
index XXXXXXX..XXXXXXX 100755
1837
--- a/tests/qemu-iotests/204
1838
+++ b/tests/qemu-iotests/204
1839
@@ -XXX,XX +XXX,XX @@
1840
-#!/bin/bash
1841
+#!/usr/bin/env bash
1842
#
1843
# Test corner cases with unusual block geometries
1844
#
1845
diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214
1846
index XXXXXXX..XXXXXXX 100755
1847
--- a/tests/qemu-iotests/214
1848
+++ b/tests/qemu-iotests/214
1849
@@ -XXX,XX +XXX,XX @@
1850
-#!/bin/bash
1851
+#!/usr/bin/env bash
1852
#
1853
# Test qcow2 image compression
1854
#
1855
diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215
1856
index XXXXXXX..XXXXXXX 100755
1857
--- a/tests/qemu-iotests/215
1858
+++ b/tests/qemu-iotests/215
1859
@@ -XXX,XX +XXX,XX @@
1860
-#!/bin/bash
1861
+#!/usr/bin/env bash
1862
#
1863
# Test case for copy-on-read into qcow2, using the COR filter driver
1864
#
1865
diff --git a/tests/qemu-iotests/217 b/tests/qemu-iotests/217
1866
index XXXXXXX..XXXXXXX 100755
1867
--- a/tests/qemu-iotests/217
1868
+++ b/tests/qemu-iotests/217
1869
@@ -XXX,XX +XXX,XX @@
1870
-#!/bin/bash
1871
+#!/usr/bin/env bash
1872
#
1873
# I/O errors when working with internal qcow2 snapshots, and repairing
1874
# the result
1875
diff --git a/tests/qemu-iotests/220 b/tests/qemu-iotests/220
1876
index XXXXXXX..XXXXXXX 100755
1877
--- a/tests/qemu-iotests/220
1878
+++ b/tests/qemu-iotests/220
1879
@@ -XXX,XX +XXX,XX @@
1880
-#!/bin/bash
1881
+#!/usr/bin/env bash
1882
#
1883
# max limits on compression in huge qcow2 files
1884
#
1885
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
1886
index XXXXXXX..XXXXXXX 100755
1887
--- a/tests/qemu-iotests/221
1888
+++ b/tests/qemu-iotests/221
1889
@@ -XXX,XX +XXX,XX @@
1890
-#!/bin/bash
1891
+#!/usr/bin/env bash
1892
#
1893
# Test qemu-img vs. unaligned images
1894
#
1895
diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223
1896
index XXXXXXX..XXXXXXX 100755
1897
--- a/tests/qemu-iotests/223
1898
+++ b/tests/qemu-iotests/223
1899
@@ -XXX,XX +XXX,XX @@
1900
-#!/bin/bash
1901
+#!/usr/bin/env bash
1902
#
1903
# Test reading dirty bitmap over NBD
1904
#
1905
diff --git a/tests/qemu-iotests/225 b/tests/qemu-iotests/225
1906
index XXXXXXX..XXXXXXX 100755
1907
--- a/tests/qemu-iotests/225
1908
+++ b/tests/qemu-iotests/225
1909
@@ -XXX,XX +XXX,XX @@
1910
-#!/bin/bash
1911
+#!/usr/bin/env bash
1912
#
1913
# Test vmdk backing file correlation
1914
#
1915
diff --git a/tests/qemu-iotests/226 b/tests/qemu-iotests/226
1916
index XXXXXXX..XXXXXXX 100755
1917
--- a/tests/qemu-iotests/226
1918
+++ b/tests/qemu-iotests/226
1919
@@ -XXX,XX +XXX,XX @@
1920
-#!/bin/bash
1921
+#!/usr/bin/env bash
1922
#
1923
# This test covers expected filetypes for the file, host_cdrom and
1924
# host_device drivers.
1925
diff --git a/tests/qemu-iotests/227 b/tests/qemu-iotests/227
1926
index XXXXXXX..XXXXXXX 100755
1927
--- a/tests/qemu-iotests/227
1928
+++ b/tests/qemu-iotests/227
1929
@@ -XXX,XX +XXX,XX @@
1930
-#!/bin/bash
1931
+#!/usr/bin/env bash
1932
#
1933
# Test query-blockstats with different ways to create a BB
1934
#
1935
diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229
1936
index XXXXXXX..XXXXXXX 100755
1937
--- a/tests/qemu-iotests/229
1938
+++ b/tests/qemu-iotests/229
1939
@@ -XXX,XX +XXX,XX @@
1940
-#!/bin/bash
1941
+#!/usr/bin/env bash
1942
#
1943
# Test for force canceling a running blockjob that is paused in
1944
# an error state.
1945
diff --git a/tests/qemu-iotests/231 b/tests/qemu-iotests/231
1946
index XXXXXXX..XXXXXXX 100755
1947
--- a/tests/qemu-iotests/231
1948
+++ b/tests/qemu-iotests/231
1949
@@ -XXX,XX +XXX,XX @@
1950
-#!/bin/bash
1951
+#!/usr/bin/env bash
1952
#
1953
# Test legacy and modern option parsing for rbd/ceph. This will not
1954
# actually connect to a ceph server, but rather looks for the appropriate
1955
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
1956
index XXXXXXX..XXXXXXX 100755
1957
--- a/tests/qemu-iotests/232
1958
+++ b/tests/qemu-iotests/232
1959
@@ -XXX,XX +XXX,XX @@
1960
-#!/bin/bash
1961
+#!/usr/bin/env bash
1962
#
1963
# Test for auto-read-only
1964
#
1965
diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233
1966
index XXXXXXX..XXXXXXX 100755
1967
--- a/tests/qemu-iotests/233
1968
+++ b/tests/qemu-iotests/233
1969
@@ -XXX,XX +XXX,XX @@
1970
-#!/bin/bash
1971
+#!/usr/bin/env bash
1972
#
1973
# Test NBD TLS certificate / authorization integration
1974
#
1975
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
1976
index XXXXXXX..XXXXXXX 100755
1977
--- a/tests/qemu-iotests/check
1978
+++ b/tests/qemu-iotests/check
1979
@@ -XXX,XX +XXX,XX @@
1980
-#!/bin/bash
1981
+#!/usr/bin/env bash
1982
#
1983
# Copyright (C) 2009 Red Hat, Inc.
1984
# Copyright (c) 2000-2002,2006 Silicon Graphics, Inc. All Rights Reserved.
1985
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
11
index XXXXXXX..XXXXXXX 100644
1986
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/check-block-qdict.c
1987
--- a/tests/qemu-iotests/common.config
13
+++ b/tests/check-block-qdict.c
1988
+++ b/tests/qemu-iotests/common.config
14
@@ -XXX,XX +XXX,XX @@ static void qdict_defaults_test(void)
1989
@@ -XXX,XX +XXX,XX @@
15
1990
-#!/bin/bash
16
static void qdict_flatten_test(void)
1991
+#!/usr/bin/env bash
17
{
1992
#
18
- QList *list1 = qlist_new();
1993
# Copyright (C) 2009 Red Hat, Inc.
19
- QList *list2 = qlist_new();
1994
# Copyright (c) 2000-2003,2006 Silicon Graphics, Inc. All Rights Reserved.
20
- QDict *dict1 = qdict_new();
1995
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
21
- QDict *dict2 = qdict_new();
1996
index XXXXXXX..XXXXXXX 100644
22
- QDict *dict3 = qdict_new();
1997
--- a/tests/qemu-iotests/common.filter
23
+ QList *e_1 = qlist_new();
1998
+++ b/tests/qemu-iotests/common.filter
24
+ QList *e = qlist_new();
1999
@@ -XXX,XX +XXX,XX @@
25
+ QDict *e_1_2 = qdict_new();
2000
-#!/bin/bash
26
+ QDict *f = qdict_new();
2001
+#!/usr/bin/env bash
27
+ QDict *root = qdict_new();
2002
#
28
2003
# Copyright (C) 2009 Red Hat, Inc.
29
/*
2004
# Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
30
* Test the flattening of
2005
diff --git a/tests/qemu-iotests/common.nbd b/tests/qemu-iotests/common.nbd
31
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
2006
index XXXXXXX..XXXXXXX 100644
32
* }
2007
--- a/tests/qemu-iotests/common.nbd
33
*/
2008
+++ b/tests/qemu-iotests/common.nbd
34
2009
@@ -XXX,XX +XXX,XX @@
35
- qdict_put_int(dict1, "a", 0);
2010
-#!/bin/bash
36
- qdict_put_int(dict1, "b", 1);
2011
+#!/usr/bin/env bash
37
+ qdict_put_int(e_1_2, "a", 0);
2012
# -*- shell-script-mode -*-
38
+ qdict_put_int(e_1_2, "b", 1);
2013
#
39
2014
# Helpers for NBD server related config
40
- qlist_append_int(list1, 23);
2015
diff --git a/tests/qemu-iotests/common.pattern b/tests/qemu-iotests/common.pattern
41
- qlist_append_int(list1, 66);
2016
index XXXXXXX..XXXXXXX 100644
42
- qlist_append(list1, dict1);
2017
--- a/tests/qemu-iotests/common.pattern
43
- qlist_append_int(list2, 42);
2018
+++ b/tests/qemu-iotests/common.pattern
44
- qlist_append(list2, list1);
2019
@@ -XXX,XX +XXX,XX @@
45
+ qlist_append_int(e_1, 23);
2020
-#!/bin/bash
46
+ qlist_append_int(e_1, 66);
2021
+#!/usr/bin/env bash
47
+ qlist_append(e_1, e_1_2);
2022
#
48
+ qlist_append_int(e, 42);
2023
# Copyright (C) 2009 Red Hat, Inc.
49
+ qlist_append(e, e_1);
2024
#
50
2025
diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu
51
- qdict_put_int(dict2, "c", 2);
2026
index XXXXXXX..XXXXXXX 100644
52
- qdict_put_int(dict2, "d", 3);
2027
--- a/tests/qemu-iotests/common.qemu
53
- qdict_put(dict3, "e", list2);
2028
+++ b/tests/qemu-iotests/common.qemu
54
- qdict_put(dict3, "f", dict2);
2029
@@ -XXX,XX +XXX,XX @@
55
- qdict_put_int(dict3, "g", 4);
2030
-#!/bin/bash
56
+ qdict_put_int(f, "c", 2);
2031
+#!/usr/bin/env bash
57
+ qdict_put_int(f, "d", 3);
2032
#
58
2033
# This allows for launching of multiple QEMU instances, with independent
59
- qdict_flatten(dict3);
2034
# communication possible to each instance.
60
+ qdict_put(root, "e", e);
2035
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
61
+ qdict_put(root, "f", f);
2036
index XXXXXXX..XXXXXXX 100644
62
+ qdict_put_int(root, "g", 4);
2037
--- a/tests/qemu-iotests/common.rc
63
2038
+++ b/tests/qemu-iotests/common.rc
64
- g_assert(qdict_get_int(dict3, "e.0") == 42);
2039
@@ -XXX,XX +XXX,XX @@
65
- g_assert(qdict_get_int(dict3, "e.1.0") == 23);
2040
-#!/bin/bash
66
- g_assert(qdict_get_int(dict3, "e.1.1") == 66);
2041
+#!/usr/bin/env bash
67
- g_assert(qdict_get_int(dict3, "e.1.2.a") == 0);
2042
#
68
- g_assert(qdict_get_int(dict3, "e.1.2.b") == 1);
2043
# Copyright (C) 2009 Red Hat, Inc.
69
- g_assert(qdict_get_int(dict3, "f.c") == 2);
2044
# Copyright (c) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
70
- g_assert(qdict_get_int(dict3, "f.d") == 3);
2045
diff --git a/tests/qemu-iotests/common.tls b/tests/qemu-iotests/common.tls
71
- g_assert(qdict_get_int(dict3, "g") == 4);
2046
index XXXXXXX..XXXXXXX 100644
72
+ qdict_flatten(root);
2047
--- a/tests/qemu-iotests/common.tls
73
2048
+++ b/tests/qemu-iotests/common.tls
74
- g_assert(qdict_size(dict3) == 8);
2049
@@ -XXX,XX +XXX,XX @@
75
+ g_assert(qdict_get_int(root, "e.0") == 42);
2050
-#!/bin/bash
76
+ g_assert(qdict_get_int(root, "e.1.0") == 23);
2051
+#!/usr/bin/env bash
77
+ g_assert(qdict_get_int(root, "e.1.1") == 66);
2052
#
78
+ g_assert(qdict_get_int(root, "e.1.2.a") == 0);
2053
# Helpers for TLS related config
79
+ g_assert(qdict_get_int(root, "e.1.2.b") == 1);
2054
#
80
+ g_assert(qdict_get_int(root, "f.c") == 2);
81
+ g_assert(qdict_get_int(root, "f.d") == 3);
82
+ g_assert(qdict_get_int(root, "g") == 4);
83
84
- qobject_unref(dict3);
85
+ g_assert(qdict_size(root) == 8);
86
+
87
+ qobject_unref(root);
88
}
89
90
static void qdict_array_split_test(void)
91
--
2055
--
92
2.13.6
2056
2.20.1
93
2057
94
2058
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
These point to the job versions now, not the blockjob versions which
3
Various sed regexp from common.filter use sed GNU extensions.
4
don't really exist anymore.
4
Instead of spending time to write these regex to be POSIX compliant,
5
verify the GNU sed is available and use it.
5
6
6
Except set-speed, which does. It sticks out like a sore thumb. This
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
patch doesn't fix that, but it doesn't make it any worse, either.
8
9
Signed-off-by: John Snow <jsnow@redhat.com>
10
Reviewed-by: Jeff Cody <jcody@redhat.com>
11
Reviewed-by: Markus Armbruster <armbru@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
9
---
14
qapi/job.json | 12 ++++++------
10
tests/qemu-iotests/common.filter | 36 ++++++++++++++++----------------
15
1 file changed, 6 insertions(+), 6 deletions(-)
11
tests/qemu-iotests/common.rc | 13 ++++++++++++
12
2 files changed, 31 insertions(+), 18 deletions(-)
16
13
17
diff --git a/qapi/job.json b/qapi/job.json
14
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/qapi/job.json
16
--- a/tests/qemu-iotests/common.filter
20
+++ b/qapi/job.json
17
+++ b/tests/qemu-iotests/common.filter
21
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@
22
#
19
#
23
# Represents command verbs that can be applied to a job.
20
_filter_date()
21
{
22
- sed \
23
+ $SED \
24
-e 's/[A-Z][a-z][a-z] [A-z][a-z][a-z] *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]$/DATE/'
25
}
26
27
_filter_generated_node_ids()
28
{
29
- sed -re 's/\#block[0-9]{3,}/NODE_NAME/'
30
+ $SED -re 's/\#block[0-9]{3,}/NODE_NAME/'
31
}
32
33
_filter_qom_path()
34
{
35
- sed -e 's#\(Attached to: *\) /.*#\1 PATH#'
36
+ $SED -e 's#\(Attached to: *\) /.*#\1 PATH#'
37
}
38
39
# replace occurrences of the actual TEST_DIR value with TEST_DIR
40
_filter_testdir()
41
{
42
- sed -e "s#$TEST_DIR/#TEST_DIR/#g"
43
+ $SED -e "s#$TEST_DIR/#TEST_DIR/#g"
44
}
45
46
# replace occurrences of the actual IMGFMT value with IMGFMT
47
_filter_imgfmt()
48
{
49
- sed -e "s#$IMGFMT#IMGFMT#g"
50
+ $SED -e "s#$IMGFMT#IMGFMT#g"
51
}
52
53
# Replace error message when the format is not supported and delete
54
# the output lines after the first one
55
_filter_qemu_img_check()
56
{
57
- sed -e '/allocated.*fragmented.*compressed clusters/d' \
58
+ $SED -e '/allocated.*fragmented.*compressed clusters/d' \
59
-e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \
60
-e '/Image end offset: [0-9]\+/d'
61
}
62
@@ -XXX,XX +XXX,XX @@ _filter_qemu_img_check()
63
# Removes \r from messages
64
_filter_win32()
65
{
66
- sed -e 's/\r//g'
67
+ $SED -e 's/\r//g'
68
}
69
70
# sanitize qemu-io output
71
_filter_qemu_io()
72
{
73
- _filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \
74
+ _filter_win32 | $SED -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \
75
-e "s/: line [0-9][0-9]*: *[0-9][0-9]*\( Aborted\| Killed\)/:\1/" \
76
-e "s/qemu-io> //g"
77
}
78
@@ -XXX,XX +XXX,XX @@ _filter_qemu_io()
79
# replace occurrences of QEMU_PROG with "qemu"
80
_filter_qemu()
81
{
82
- sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \
83
+ $SED -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \
84
-e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#' \
85
-e $'s#\r##' # QEMU monitor uses \r\n line endings
86
}
87
@@ -XXX,XX +XXX,XX @@ _filter_qemu()
88
_filter_qmp()
89
{
90
_filter_win32 | \
91
- sed -e 's#\("\(micro\)\?seconds": \)[0-9]\+#\1 TIMESTAMP#g' \
92
+ $SED -e 's#\("\(micro\)\?seconds": \)[0-9]\+#\1 TIMESTAMP#g' \
93
-e 's#^{"QMP":.*}$#QMP_VERSION#' \
94
-e '/^ "QMP": {\s*$/, /^ }\s*$/ c\' \
95
-e ' QMP_VERSION'
96
@@ -XXX,XX +XXX,XX @@ _filter_qmp()
97
# readline makes HMP command strings so long that git complains
98
_filter_hmp()
99
{
100
- sed -e $'s/^\\((qemu) \\)\\?.*\e\\[D/\\1/g' \
101
+ $SED -e $'s/^\\((qemu) \\)\\?.*\e\\[D/\\1/g' \
102
-e $'s/\e\\[K//g'
103
}
104
105
# replace block job offset
106
_filter_block_job_offset()
107
{
108
- sed -e 's/, "offset": [0-9]\+,/, "offset": OFFSET,/'
109
+ $SED -e 's/, "offset": [0-9]\+,/, "offset": OFFSET,/'
110
}
111
112
# replace block job len
113
_filter_block_job_len()
114
{
115
- sed -e 's/, "len": [0-9]\+,/, "len": LEN,/g'
116
+ $SED -e 's/, "len": [0-9]\+,/, "len": LEN,/g'
117
}
118
119
# replace actual image size (depends on the host filesystem)
120
_filter_actual_image_size()
121
{
122
- sed -s 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g'
123
+ $SED -s 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g'
124
}
125
126
# replace driver-specific options in the "Formatting..." line
127
_filter_img_create()
128
{
129
- sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
130
+ $SED -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
131
-e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
132
-e "s#$TEST_DIR#TEST_DIR#g" \
133
-e "s#$IMGFMT#IMGFMT#g" \
134
@@ -XXX,XX +XXX,XX @@ _filter_img_info()
135
136
discard=0
137
regex_json_spec_start='^ *"format-specific": \{'
138
- sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
139
+ $SED -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
140
-e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
141
-e "s#$TEST_DIR#TEST_DIR#g" \
142
-e "s#$IMGFMT#IMGFMT#g" \
143
@@ -XXX,XX +XXX,XX @@ _filter_img_info()
144
# human and json output
145
_filter_qemu_img_map()
146
{
147
- sed -e 's/\([0-9a-fx]* *[0-9a-fx]* *\)[0-9a-fx]* */\1/g' \
148
+ $SED -e 's/\([0-9a-fx]* *[0-9a-fx]* *\)[0-9a-fx]* */\1/g' \
149
-e 's/"offset": [0-9]\+/"offset": OFFSET/g' \
150
-e 's/Mapped to *//' | _filter_testdir | _filter_imgfmt
151
}
152
@@ -XXX,XX +XXX,XX @@ _filter_nbd()
153
# receive callbacks sometimes, making them unreliable.
154
#
155
# Filter out the TCP port number since this changes between runs.
156
- sed -e '/nbd\/.*\.c:/d' \
157
+ $SED -e '/nbd\/.*\.c:/d' \
158
-e 's#127\.0\.0\.1:[0-9]*#127.0.0.1:PORT#g' \
159
-e "s#?socket=$TEST_DIR#?socket=TEST_DIR#g" \
160
-e 's#\(foo\|PORT/\?\|.sock\): Failed to .*$#\1#'
161
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
162
index XXXXXXX..XXXXXXX 100644
163
--- a/tests/qemu-iotests/common.rc
164
+++ b/tests/qemu-iotests/common.rc
165
@@ -XXX,XX +XXX,XX @@
166
# along with this program. If not, see <http://www.gnu.org/licenses/>.
24
#
167
#
25
-# @cancel: see @block-job-cancel
168
26
+# @cancel: see @job-cancel
169
+SED=
27
#
170
+for sed in sed gsed; do
28
-# @pause: see @block-job-pause
171
+ ($sed --version | grep 'GNU sed') > /dev/null 2>&1
29
+# @pause: see @job-pause
172
+ if [ "$?" -eq 0 ]; then
30
#
173
+ SED=$sed
31
-# @resume: see @block-job-resume
174
+ break
32
+# @resume: see @job-resume
175
+ fi
33
#
176
+done
34
# @set-speed: see @block-job-set-speed
177
+if [ -z "$SED" ]; then
35
#
178
+ echo "$0: GNU sed not found"
36
-# @complete: see @block-job-complete
179
+ exit 1
37
+# @complete: see @job-complete
180
+fi
38
#
181
+
39
-# @dismiss: see @block-job-dismiss
182
dd()
40
+# @dismiss: see @job-dismiss
183
{
41
#
184
if [ "$HOSTOS" == "Linux" ]
42
-# @finalize: see @block-job-finalize
43
+# @finalize: see @job-finalize
44
#
45
# Since: 2.12
46
##
47
--
185
--
48
2.13.6
186
2.20.1
49
187
50
188
diff view generated by jsdifflib
New patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
---
4
tests/qemu-iotests/243 | 63 ++++++++++++++++++++++++++++++++++++++
5
tests/qemu-iotests/243.out | 26 ++++++++++++++++
6
tests/qemu-iotests/group | 1 +
7
3 files changed, 90 insertions(+)
8
create mode 100755 tests/qemu-iotests/243
9
create mode 100644 tests/qemu-iotests/243.out
1
10
11
diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243
12
new file mode 100755
13
index XXXXXXX..XXXXXXX
14
--- /dev/null
15
+++ b/tests/qemu-iotests/243
16
@@ -XXX,XX +XXX,XX @@
17
+#!/bin/bash
18
+#
19
+# Test qcow2 preallocation
20
+#
21
+# Copyright (C) 2019 Red Hat, Inc.
22
+#
23
+# This program is free software; you can redistribute it and/or modify
24
+# it under the terms of the GNU General Public License as published by
25
+# the Free Software Foundation; either version 2 of the License, or
26
+# (at your option) any later version.
27
+#
28
+# This program is distributed in the hope that it will be useful,
29
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
30
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31
+# GNU General Public License for more details.
32
+#
33
+# You should have received a copy of the GNU General Public License
34
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
35
+#
36
+
37
+# creator
38
+owner=kwolf@redhat.com
39
+
40
+seq=$(basename $0)
41
+echo "QA output created by $seq"
42
+
43
+status=1    # failure is the default!
44
+
45
+_cleanup()
46
+{
47
+ _cleanup_test_img
48
+}
49
+trap "_cleanup; exit \$status" 0 1 2 3 15
50
+
51
+# get standard environment, filters and checks
52
+. ./common.rc
53
+. ./common.filter
54
+
55
+_supported_fmt qcow2
56
+_supported_proto file
57
+_supported_os Linux
58
+
59
+for mode in off metadata falloc full; do
60
+
61
+ echo
62
+ echo "=== preallocation=$mode ==="
63
+ echo
64
+
65
+ IMGOPTS="preallocation=$mode" _make_test_img 64M
66
+
67
+ printf "File size: "
68
+ du -b $TEST_IMG | cut -f1
69
+
70
+ # Can't use precise numbers here because they differ between filesystems
71
+ printf "Disk usage: "
72
+ [ $(du -B1 $TEST_IMG | cut -f1) -lt 1048576 ] && echo "low" || echo "high"
73
+
74
+done
75
+
76
+# success, all done
77
+echo "*** done"
78
+rm -f $seq.full
79
+status=0
80
diff --git a/tests/qemu-iotests/243.out b/tests/qemu-iotests/243.out
81
new file mode 100644
82
index XXXXXXX..XXXXXXX
83
--- /dev/null
84
+++ b/tests/qemu-iotests/243.out
85
@@ -XXX,XX +XXX,XX @@
86
+QA output created by 243
87
+
88
+=== preallocation=off ===
89
+
90
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=off
91
+File size: 196616
92
+Disk usage: low
93
+
94
+=== preallocation=metadata ===
95
+
96
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=metadata
97
+File size: 67436544
98
+Disk usage: low
99
+
100
+=== preallocation=falloc ===
101
+
102
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=falloc
103
+File size: 67436544
104
+Disk usage: high
105
+
106
+=== preallocation=full ===
107
+
108
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=full
109
+File size: 67436544
110
+Disk usage: high
111
+*** done
112
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
113
index XXXXXXX..XXXXXXX 100644
114
--- a/tests/qemu-iotests/group
115
+++ b/tests/qemu-iotests/group
116
@@ -XXX,XX +XXX,XX @@
117
239 rw auto quick
118
240 auto quick
119
242 rw auto quick
120
+243 rw auto quick
121
--
122
2.20.1
123
124
diff view generated by jsdifflib
1
The -drive options cyls, heads, secs and trans were deprecated in
1
Image creation already involves a bdrv_co_truncate() call, which allows
2
QEMU 2.10. It's time to remove them.
2
to specify a preallocation mode. Just pass the right mode there and
3
3
remove the code that is made redundant by this.
4
hd-geo-test tested both the old version with geometry options in -drive
5
and the new one with -device. Therefore the code using -drive doesn't
6
have to be replaced there, we just need to remove the -drive test cases.
7
This in turn allows some simplification of the code.
8
4
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Markus Armbruster <armbru@redhat.com>
11
---
6
---
12
include/sysemu/blockdev.h | 1 -
7
block/qcow2.c | 28 +---------------------------
13
blockdev.c | 75 +----------------------------------------------
8
1 file changed, 1 insertion(+), 27 deletions(-)
14
hw/block/block.c | 14 ---------
15
tests/hd-geo-test.c | 37 +++++------------------
16
hmp-commands.hx | 1 -
17
qemu-doc.texi | 5 ----
18
qemu-options.hx | 7 +----
19
7 files changed, 9 insertions(+), 131 deletions(-)
20
9
21
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
10
diff --git a/block/qcow2.c b/block/qcow2.c
22
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
23
--- a/include/sysemu/blockdev.h
12
--- a/block/qcow2.c
24
+++ b/include/sysemu/blockdev.h
13
+++ b/block/qcow2.c
25
@@ -XXX,XX +XXX,XX @@ struct DriveInfo {
14
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
26
int auto_del; /* see blockdev_mark_auto_del() */
15
goto out;
27
bool is_default; /* Added by default_drive() ? */
28
int media_cd;
29
- int cyls, heads, secs, trans;
30
QemuOpts *opts;
31
char *serial;
32
QTAILQ_ENTRY(DriveInfo) next;
33
diff --git a/blockdev.c b/blockdev.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/blockdev.c
36
+++ b/blockdev.c
37
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
38
.type = QEMU_OPT_STRING,
39
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
40
},{
41
- .name = "cyls",
42
- .type = QEMU_OPT_NUMBER,
43
- .help = "number of cylinders (ide disk geometry)",
44
- },{
45
- .name = "heads",
46
- .type = QEMU_OPT_NUMBER,
47
- .help = "number of heads (ide disk geometry)",
48
- },{
49
- .name = "secs",
50
- .type = QEMU_OPT_NUMBER,
51
- .help = "number of sectors (ide disk geometry)",
52
- },{
53
- .name = "trans",
54
- .type = QEMU_OPT_STRING,
55
- .help = "chs translation (auto, lba, none)",
56
- },{
57
.name = "addr",
58
.type = QEMU_OPT_STRING,
59
.help = "pci address (virtio only)",
60
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
61
QemuOpts *legacy_opts;
62
DriveMediaType media = MEDIA_DISK;
63
BlockInterfaceType type;
64
- int cyls, heads, secs, translation;
65
int max_devs, bus_id, unit_id, index;
66
const char *devaddr;
67
const char *werror, *rerror;
68
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
69
Error *local_err = NULL;
70
int i;
71
const char *deprecated[] = {
72
- "serial", "trans", "secs", "heads", "cyls", "addr"
73
+ "serial", "addr"
74
};
75
76
/* Change legacy command line options into QMP ones */
77
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
78
type = block_default_type;
79
}
16
}
80
17
81
- /* Geometry */
18
- if (qcow2_opts->preallocation == PREALLOC_MODE_FULL ||
82
- cyls = qemu_opt_get_number(legacy_opts, "cyls", 0);
19
- qcow2_opts->preallocation == PREALLOC_MODE_FALLOC)
83
- heads = qemu_opt_get_number(legacy_opts, "heads", 0);
20
- {
84
- secs = qemu_opt_get_number(legacy_opts, "secs", 0);
21
- int64_t prealloc_size =
22
- qcow2_calc_prealloc_size(qcow2_opts->size, cluster_size,
23
- refcount_order);
85
-
24
-
86
- if (cyls || heads || secs) {
25
- ret = blk_truncate(blk, prealloc_size, qcow2_opts->preallocation, errp);
87
- if (cyls < 1) {
26
- if (ret < 0) {
88
- error_report("invalid physical cyls number");
27
- goto out;
89
- goto fail;
90
- }
91
- if (heads < 1) {
92
- error_report("invalid physical heads number");
93
- goto fail;
94
- }
95
- if (secs < 1) {
96
- error_report("invalid physical secs number");
97
- goto fail;
98
- }
28
- }
99
- }
29
- }
100
-
30
-
101
- translation = BIOS_ATA_TRANSLATION_AUTO;
31
/* Write the header */
102
- value = qemu_opt_get(legacy_opts, "trans");
32
QEMU_BUILD_BUG_ON((1 << MIN_CLUSTER_BITS) < sizeof(*header));
103
- if (value != NULL) {
33
header = g_malloc0(cluster_size);
104
- if (!cyls) {
34
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
105
- error_report("'%s' trans must be used with cyls, heads and secs",
35
}
106
- value);
36
107
- goto fail;
37
/* Okay, now that we have a valid image, let's give it the right size */
108
- }
38
- ret = blk_truncate(blk, qcow2_opts->size, PREALLOC_MODE_OFF, errp);
109
- if (!strcmp(value, "none")) {
39
+ ret = blk_truncate(blk, qcow2_opts->size, qcow2_opts->preallocation, errp);
110
- translation = BIOS_ATA_TRANSLATION_NONE;
40
if (ret < 0) {
111
- } else if (!strcmp(value, "lba")) {
41
error_prepend(errp, "Could not resize image: ");
112
- translation = BIOS_ATA_TRANSLATION_LBA;
42
goto out;
113
- } else if (!strcmp(value, "large")) {
43
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
114
- translation = BIOS_ATA_TRANSLATION_LARGE;
44
}
115
- } else if (!strcmp(value, "rechs")) {
45
}
116
- translation = BIOS_ATA_TRANSLATION_RECHS;
46
117
- } else if (!strcmp(value, "auto")) {
47
- /* And if we're supposed to preallocate metadata, do that now */
118
- translation = BIOS_ATA_TRANSLATION_AUTO;
48
- if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) {
119
- } else {
49
- BDRVQcow2State *s = blk_bs(blk)->opaque;
120
- error_report("'%s' invalid translation type", value);
50
- qemu_co_mutex_lock(&s->lock);
121
- goto fail;
51
- ret = preallocate_co(blk_bs(blk), 0, qcow2_opts->size);
52
- qemu_co_mutex_unlock(&s->lock);
53
-
54
- if (ret < 0) {
55
- error_setg_errno(errp, -ret, "Could not preallocate metadata");
56
- goto out;
122
- }
57
- }
123
- }
58
- }
124
-
59
-
125
- if (media == MEDIA_CDROM) {
60
blk_unref(blk);
126
- if (cyls || secs || heads) {
61
blk = NULL;
127
- error_report("CHS can't be set with media=cdrom");
62
128
- goto fail;
129
- }
130
- }
131
-
132
/* Device address specified by bus/unit or index.
133
* If none was specified, try to find the first free one. */
134
bus_id = qemu_opt_get_number(legacy_opts, "bus", 0);
135
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
136
dinfo = g_malloc0(sizeof(*dinfo));
137
dinfo->opts = all_opts;
138
139
- dinfo->cyls = cyls;
140
- dinfo->heads = heads;
141
- dinfo->secs = secs;
142
- dinfo->trans = translation;
143
-
144
dinfo->type = type;
145
dinfo->bus = bus_id;
146
dinfo->unit = unit_id;
147
diff --git a/hw/block/block.c b/hw/block/block.c
148
index XXXXXXX..XXXXXXX 100644
149
--- a/hw/block/block.c
150
+++ b/hw/block/block.c
151
@@ -XXX,XX +XXX,XX @@ bool blkconf_geometry(BlockConf *conf, int *ptrans,
152
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
153
Error **errp)
154
{
155
- DriveInfo *dinfo;
156
-
157
- if (!conf->cyls && !conf->heads && !conf->secs) {
158
- /* try to fall back to value set with legacy -drive cyls=... */
159
- dinfo = blk_legacy_dinfo(conf->blk);
160
- if (dinfo) {
161
- conf->cyls = dinfo->cyls;
162
- conf->heads = dinfo->heads;
163
- conf->secs = dinfo->secs;
164
- if (ptrans) {
165
- *ptrans = dinfo->trans;
166
- }
167
- }
168
- }
169
if (!conf->cyls && !conf->heads && !conf->secs) {
170
hd_geometry_guess(conf->blk,
171
&conf->cyls, &conf->heads, &conf->secs,
172
diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c
173
index XXXXXXX..XXXXXXX 100644
174
--- a/tests/hd-geo-test.c
175
+++ b/tests/hd-geo-test.c
176
@@ -XXX,XX +XXX,XX @@ static void setup_mbr(int img_idx, MBRcontents mbr)
177
178
static int setup_ide(int argc, char *argv[], int argv_sz,
179
int ide_idx, const char *dev, int img_idx,
180
- MBRcontents mbr, const char *opts)
181
+ MBRcontents mbr)
182
{
183
char *s1, *s2, *s3;
184
185
@@ -XXX,XX +XXX,XX @@ static int setup_ide(int argc, char *argv[], int argv_sz,
186
s3 = g_strdup(",media=cdrom");
187
}
188
argc = append_arg(argc, argv, argv_sz,
189
- g_strdup_printf("%s%s%s%s", s1, s2, s3, opts));
190
+ g_strdup_printf("%s%s%s", s1, s2, s3));
191
g_free(s1);
192
g_free(s2);
193
g_free(s3);
194
@@ -XXX,XX +XXX,XX @@ static void test_ide_mbr(bool use_device, MBRcontents mbr)
195
for (i = 0; i < backend_last; i++) {
196
cur_ide[i] = &hd_chst[i][mbr];
197
dev = use_device ? (is_hd(cur_ide[i]) ? "ide-hd" : "ide-cd") : NULL;
198
- argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr, "");
199
+ argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr);
200
}
201
args = g_strjoinv(" ", argv);
202
qtest_start(args);
203
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_user(const char *dev, bool trans)
204
const CHST expected_chst = { secs / (4 * 32) , 4, 32, trans };
205
206
argc = setup_common(argv, ARGV_SIZE);
207
- opts = g_strdup_printf("%s,%s%scyls=%d,heads=%d,secs=%d",
208
- dev ?: "",
209
- trans && dev ? "bios-chs-" : "",
210
- trans ? "trans=lba," : "",
211
+ opts = g_strdup_printf("%s,%scyls=%d,heads=%d,secs=%d",
212
+ dev, trans ? "bios-chs-trans=lba," : "",
213
expected_chst.cyls, expected_chst.heads,
214
expected_chst.secs);
215
cur_ide[0] = &expected_chst;
216
- argc = setup_ide(argc, argv, ARGV_SIZE,
217
- 0, dev ? opts : NULL, backend_small, mbr_chs,
218
- dev ? "" : opts);
219
+ argc = setup_ide(argc, argv, ARGV_SIZE, 0, opts, backend_small, mbr_chs);
220
g_free(opts);
221
args = g_strjoinv(" ", argv);
222
qtest_start(args);
223
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_user(const char *dev, bool trans)
224
}
225
226
/*
227
- * Test case: IDE device (if=ide) with explicit CHS
228
- */
229
-static void test_ide_drive_user_chs(void)
230
-{
231
- test_ide_drive_user(NULL, false);
232
-}
233
-
234
-/*
235
- * Test case: IDE device (if=ide) with explicit CHS and translation
236
- */
237
-static void test_ide_drive_user_chst(void)
238
-{
239
- test_ide_drive_user(NULL, true);
240
-}
241
-
242
-/*
243
* Test case: IDE device (if=none) with explicit CHS
244
*/
245
static void test_ide_device_user_chs(void)
246
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_cd_0(void)
247
for (i = 0; i <= backend_empty; i++) {
248
ide_idx = backend_empty - i;
249
cur_ide[ide_idx] = &hd_chst[i][mbr_blank];
250
- argc = setup_ide(argc, argv, ARGV_SIZE,
251
- ide_idx, NULL, i, mbr_blank, "");
252
+ argc = setup_ide(argc, argv, ARGV_SIZE, ide_idx, NULL, i, mbr_blank);
253
}
254
args = g_strjoinv(" ", argv);
255
qtest_start(args);
256
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
257
qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
258
qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
259
qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
260
- qtest_add_func("hd-geo/ide/drive/user/chs", test_ide_drive_user_chs);
261
- qtest_add_func("hd-geo/ide/drive/user/chst", test_ide_drive_user_chst);
262
qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
263
qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
264
qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
265
diff --git a/hmp-commands.hx b/hmp-commands.hx
266
index XXXXXXX..XXXXXXX 100644
267
--- a/hmp-commands.hx
268
+++ b/hmp-commands.hx
269
@@ -XXX,XX +XXX,XX @@ ETEXI
270
.params = "[-n] [[<domain>:]<bus>:]<slot>\n"
271
"[file=file][,if=type][,bus=n]\n"
272
"[,unit=m][,media=d][,index=i]\n"
273
- "[,cyls=c,heads=h,secs=s[,trans=t]]\n"
274
"[,snapshot=on|off][,cache=on|off]\n"
275
"[,readonly=on|off][,copy-on-read=on|off]",
276
.help = "add drive to PCI storage controller",
277
diff --git a/qemu-doc.texi b/qemu-doc.texi
278
index XXXXXXX..XXXXXXX 100644
279
--- a/qemu-doc.texi
280
+++ b/qemu-doc.texi
281
@@ -XXX,XX +XXX,XX @@ with ``-device ...,netdev=x''), or ``-nic user,smb=/some/dir''
282
(for embedded NICs). The new syntax allows different settings to be
283
provided per NIC.
284
285
-@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0)
286
-
287
-The drive geometry arguments are replaced by the the geometry arguments
288
-that can be specified with the ``-device'' parameter.
289
-
290
@subsection -drive serial=... (since 2.10.0)
291
292
The drive serial argument is replaced by the the serial argument
293
diff --git a/qemu-options.hx b/qemu-options.hx
294
index XXXXXXX..XXXXXXX 100644
295
--- a/qemu-options.hx
296
+++ b/qemu-options.hx
297
@@ -XXX,XX +XXX,XX @@ ETEXI
298
299
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
300
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
301
- " [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
302
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
303
- " [,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
304
+ " [,snapshot=on|off][,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
305
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
306
" [,readonly=on|off][,copy-on-read=on|off]\n"
307
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
308
@@ -XXX,XX +XXX,XX @@ This option defines where is connected the drive by using an index in the list
309
of available connectors of a given interface type.
310
@item media=@var{media}
311
This option defines the type of the media: disk or cdrom.
312
-@item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}]
313
-Force disk physical geometry and the optional BIOS translation (trans=none or
314
-lba). These parameters are deprecated, use the corresponding parameters
315
-of @code{-device} instead.
316
@item snapshot=@var{snapshot}
317
@var{snapshot} is "on" or "off" and controls snapshot mode for the given drive
318
(see @option{-snapshot}).
319
--
63
--
320
2.13.6
64
2.20.1
321
65
322
66
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
This adds external data file to the qcow2 spec as a new incompatible
2
feature.
2
3
3
When you mix scalar and non-scalar keys, whether you get an "already
4
set as scalar" or an "already set as dict" error depends on qdict
5
iteration order. Neither message makes much sense. Replace by
6
""Cannot mix scalar and non-scalar keys". This is similar to the
7
message we get for mixing list and non-list keys.
8
9
I find qdict_crumple()'s first loop hard to understand. Rearrange it
10
and add a comment.
11
12
Signed-off-by: Markus Armbruster <armbru@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
5
---
15
qobject/block-qdict.c | 32 ++++++++++++++++----------------
6
docs/interop/qcow2.txt | 42 ++++++++++++++++++++++++++++++++++++++----
16
1 file changed, 16 insertions(+), 16 deletions(-)
7
1 file changed, 38 insertions(+), 4 deletions(-)
17
8
18
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
9
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
19
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
20
--- a/qobject/block-qdict.c
11
--- a/docs/interop/qcow2.txt
21
+++ b/qobject/block-qdict.c
12
+++ b/docs/interop/qcow2.txt
22
@@ -XXX,XX +XXX,XX @@ static int qdict_is_list(QDict *maybe_list, Error **errp)
13
@@ -XXX,XX +XXX,XX @@ in the description of a field.
23
QObject *qdict_crumple(const QDict *src, Error **errp)
14
be written to (unless for regaining
24
{
15
consistency).
25
const QDictEntry *ent;
16
26
- QDict *two_level, *multi_level = NULL;
17
- Bits 2-63: Reserved (set to 0)
27
+ QDict *two_level, *multi_level = NULL, *child_dict;
18
+ Bit 2: External data file bit. If this bit is set, an
28
QObject *dst = NULL, *child;
19
+ external data file is used. Guest clusters are
29
size_t i;
20
+ then stored in the external data file. For such
30
char *prefix = NULL;
21
+ images, clusters in the external data file are
31
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
22
+ not refcounted. The offset field in the
32
}
23
+ Standard Cluster Descriptor must match the
33
24
+ guest offset and neither compressed clusters
34
qdict_split_flat_key(ent->key, &prefix, &suffix);
25
+ nor internal snapshots are supported.
35
-
36
child = qdict_get(two_level, prefix);
37
+ child_dict = qobject_to(QDict, child);
38
+
26
+
39
+ if (child) {
27
+ An External Data File Name header extension may
40
+ /*
28
+ be present if this bit is set.
41
+ * If @child_dict, then all previous keys with this prefix
42
+ * had a suffix. If @suffix, this one has one as well,
43
+ * and we're good, else there's a clash.
44
+ */
45
+ if (!child_dict || !suffix) {
46
+ error_setg(errp, "Cannot mix scalar and non-scalar keys");
47
+ goto error;
48
+ }
49
+ }
50
+
29
+
51
if (suffix) {
30
+ Bits 3-63: Reserved (set to 0)
52
- QDict *child_dict = qobject_to(QDict, child);
31
53
if (!child_dict) {
32
80 - 87: compatible_features
54
- if (child) {
33
Bitmask of compatible features. An implementation can
55
- error_setg(errp, "Key %s prefix is already set as a scalar",
34
@@ -XXX,XX +XXX,XX @@ in the description of a field.
56
- prefix);
35
bit is unset, the bitmaps extension data must be
57
- goto error;
36
considered inconsistent.
58
- }
37
59
-
38
- Bits 1-63: Reserved (set to 0)
60
child_dict = qdict_new();
39
+ Bit 1: If this bit is set, the external data file can
61
- qdict_put_obj(two_level, prefix, QOBJECT(child_dict));
40
+ be read as a consistent standalone raw image
62
+ qdict_put(two_level, prefix, child_dict);
41
+ without looking at the qcow2 metadata.
63
}
42
+
64
-
43
+ Setting this bit has a performance impact for
65
qdict_put_obj(child_dict, suffix, qobject_ref(ent->value));
44
+ some operations on the image (e.g. writing
66
} else {
45
+ zeros requires writing to the data file instead
67
- if (child) {
46
+ of only setting the zero flag in the L2 table
68
- error_setg(errp, "Key %s prefix is already set as a dict",
47
+ entry) and conflicts with backing files.
69
- prefix);
48
+
70
- goto error;
49
+ This bit may only be set if the External Data
71
- }
50
+ File bit (incompatible feature bit 1) is also
72
qdict_put_obj(two_level, prefix, qobject_ref(ent->value));
51
+ set.
73
}
52
+
53
+ Bits 2-63: Reserved (set to 0)
54
55
96 - 99: refcount_order
56
Describes the width of a reference count block entry (width
57
@@ -XXX,XX +XXX,XX @@ be stored. Each extension has a structure like the following:
58
0x6803f857 - Feature name table
59
0x23852875 - Bitmaps extension
60
0x0537be77 - Full disk encryption header pointer
61
+ 0x44415441 - External data file name
62
other - Unknown header extension, can be safely
63
ignored
64
65
@@ -XXX,XX +XXX,XX @@ L2 table entry:
66
This information is only accurate in L2 tables
67
that are reachable from the active L1 table.
68
69
+ With external data files, all guest clusters have an
70
+ implicit refcount of 1 (because of the fixed host = guest
71
+ mapping for guest cluster offsets), so this bit should be 1
72
+ for all allocated clusters.
73
+
74
Standard Cluster Descriptor:
75
76
Bit 0: If set to 1, the cluster reads as all zeros. The host
77
@@ -XXX,XX +XXX,XX @@ Standard Cluster Descriptor:
78
1 - 8: Reserved (set to 0)
79
80
9 - 55: Bits 9-55 of host cluster offset. Must be aligned to a
81
- cluster boundary. If the offset is 0, the cluster is
82
- unallocated.
83
+ cluster boundary. If the offset is 0 and bit 63 is clear,
84
+ the cluster is unallocated. The offset may only be 0 with
85
+ bit 63 set (indicating a host cluster offset of 0) when an
86
+ external data file is used.
87
88
56 - 61: Reserved (set to 0)
74
89
75
--
90
--
76
2.13.6
91
2.20.1
77
92
78
93
diff view generated by jsdifflib
1
The -drive option serial was deprecated in QEMU 2.10. It's time to
1
This adds basic constants, struct fields and helper function for
2
remove it.
2
external data file support to the implementation.
3
3
4
Tests need to be updated to set the serial number with -global instead
4
QCOW2_INCOMPAT_MASK and QCOW2_AUTOCLEAR_MASK are not updated yet so that
5
of using the -drive option.
5
opening images with an external data file still fails (we don't handle
6
them correctly yet).
6
7
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Markus Armbruster <armbru@redhat.com>
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
10
---
9
---
11
include/hw/block/block.h | 1 -
10
block/qcow2.h | 32 ++++++++++++++++++++++----------
12
include/sysemu/blockdev.h | 1 -
11
block/qcow2.c | 9 +++++++++
13
block/block-backend.c | 1 -
12
tests/qemu-iotests/031.out | 8 ++++----
14
blockdev.c | 10 ----------
13
tests/qemu-iotests/036.out | 4 ++--
15
hw/block/block.c | 13 -------------
14
tests/qemu-iotests/061.out | 14 +++++++-------
16
hw/block/nvme.c | 1 -
15
5 files changed, 44 insertions(+), 23 deletions(-)
17
hw/block/virtio-blk.c | 1 -
16
18
hw/ide/qdev.c | 1 -
17
diff --git a/block/qcow2.h b/block/qcow2.h
19
hw/scsi/scsi-disk.c | 1 -
18
index XXXXXXX..XXXXXXX 100644
20
hw/usb/dev-storage.c | 1 -
19
--- a/block/qcow2.h
21
tests/ahci-test.c | 6 +++---
20
+++ b/block/qcow2.h
22
tests/ide-test.c | 8 ++++----
21
@@ -XXX,XX +XXX,XX @@ enum {
23
qemu-doc.texi | 5 -----
22
24
qemu-options.hx | 6 +-----
23
/* Incompatible feature bits */
25
14 files changed, 8 insertions(+), 48 deletions(-)
24
enum {
26
25
- QCOW2_INCOMPAT_DIRTY_BITNR = 0,
27
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
26
- QCOW2_INCOMPAT_CORRUPT_BITNR = 1,
28
index XXXXXXX..XXXXXXX 100644
27
- QCOW2_INCOMPAT_DIRTY = 1 << QCOW2_INCOMPAT_DIRTY_BITNR,
29
--- a/include/hw/block/block.h
28
- QCOW2_INCOMPAT_CORRUPT = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR,
30
+++ b/include/hw/block/block.h
29
-
31
@@ -XXX,XX +XXX,XX @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
30
- QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY
32
31
- | QCOW2_INCOMPAT_CORRUPT,
33
/* Configuration helpers */
32
+ QCOW2_INCOMPAT_DIRTY_BITNR = 0,
34
33
+ QCOW2_INCOMPAT_CORRUPT_BITNR = 1,
35
-void blkconf_serial(BlockConf *conf, char **serial);
34
+ QCOW2_INCOMPAT_DATA_FILE_BITNR = 2,
36
bool blkconf_geometry(BlockConf *conf, int *trans,
35
+ QCOW2_INCOMPAT_DIRTY = 1 << QCOW2_INCOMPAT_DIRTY_BITNR,
37
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
36
+ QCOW2_INCOMPAT_CORRUPT = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR,
38
Error **errp);
37
+ QCOW2_INCOMPAT_DATA_FILE = 1 << QCOW2_INCOMPAT_DATA_FILE_BITNR,
39
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
38
+
40
index XXXXXXX..XXXXXXX 100644
39
+ QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY
41
--- a/include/sysemu/blockdev.h
40
+ | QCOW2_INCOMPAT_CORRUPT,
42
+++ b/include/sysemu/blockdev.h
43
@@ -XXX,XX +XXX,XX @@ struct DriveInfo {
44
bool is_default; /* Added by default_drive() ? */
45
int media_cd;
46
QemuOpts *opts;
47
- char *serial;
48
QTAILQ_ENTRY(DriveInfo) next;
49
};
41
};
50
42
51
diff --git a/block/block-backend.c b/block/block-backend.c
43
/* Compatible feature bits */
52
index XXXXXXX..XXXXXXX 100644
44
@@ -XXX,XX +XXX,XX @@ enum {
53
--- a/block/block-backend.c
45
54
+++ b/block/block-backend.c
46
/* Autoclear feature bits */
55
@@ -XXX,XX +XXX,XX @@ static void drive_info_del(DriveInfo *dinfo)
47
enum {
56
return;
48
- QCOW2_AUTOCLEAR_BITMAPS_BITNR = 0,
57
}
49
- QCOW2_AUTOCLEAR_BITMAPS = 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR,
58
qemu_opts_del(dinfo->opts);
50
+ QCOW2_AUTOCLEAR_BITMAPS_BITNR = 0,
59
- g_free(dinfo->serial);
51
+ QCOW2_AUTOCLEAR_DATA_FILE_RAW_BITNR = 1,
60
g_free(dinfo);
52
+ QCOW2_AUTOCLEAR_BITMAPS = 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR,
61
}
53
+ QCOW2_AUTOCLEAR_DATA_FILE_RAW = 1 << QCOW2_AUTOCLEAR_DATA_FILE_RAW_BITNR,
62
54
63
diff --git a/blockdev.c b/blockdev.c
55
- QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS,
64
index XXXXXXX..XXXXXXX 100644
56
+ QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS,
65
--- a/blockdev.c
57
};
66
+++ b/blockdev.c
58
67
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
59
enum qcow2_discard_type {
68
.type = QEMU_OPT_STRING,
60
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State {
69
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
61
70
},{
62
CoQueue compress_wait_queue;
71
- .name = "serial",
63
int nb_compress_threads;
72
- .type = QEMU_OPT_STRING,
64
+
73
- .help = "disk serial number",
65
+ BdrvChild *data_file;
74
- },{
66
} BDRVQcow2State;
75
.name = "file",
67
76
.type = QEMU_OPT_STRING,
68
typedef struct Qcow2COWRegion {
77
.help = "file name",
69
@@ -XXX,XX +XXX,XX @@ typedef enum QCow2MetadataOverlap {
78
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
70
79
const char *werror, *rerror;
71
#define REFT_OFFSET_MASK 0xfffffffffffffe00ULL
80
bool read_only = false;
72
81
bool copy_on_read;
73
+static inline bool has_data_file(BlockDriverState *bs)
82
- const char *serial;
74
+{
83
const char *filename;
75
+ BDRVQcow2State *s = bs->opaque;
84
Error *local_err = NULL;
76
+ return (s->data_file != bs->file);
85
int i;
77
+}
86
const char *deprecated[] = {
78
+
87
- "serial"
79
static inline int64_t start_of_cluster(BDRVQcow2State *s, int64_t offset)
88
};
80
{
89
81
return offset & ~(s->cluster_size - 1);
90
/* Change legacy command line options into QMP ones */
82
diff --git a/block/qcow2.c b/block/qcow2.c
91
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
83
index XXXXXXX..XXXXXXX 100644
84
--- a/block/qcow2.c
85
+++ b/block/qcow2.c
86
@@ -XXX,XX +XXX,XX @@ typedef struct {
87
#define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857
88
#define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77
89
#define QCOW2_EXT_MAGIC_BITMAPS 0x23852875
90
+#define QCOW2_EXT_MAGIC_DATA_FILE 0x44415441
91
92
static int coroutine_fn
93
qcow2_co_preadv_compressed(BlockDriverState *bs,
94
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
92
goto fail;
95
goto fail;
93
}
96
}
94
97
95
- /* Serial number */
98
+ /* TODO Open external data file */
96
- serial = qemu_opt_get(legacy_opts, "serial");
99
+ s->data_file = bs->file;
97
-
100
+
98
/* no id supplied -> create one */
101
/* qcow2_read_extension may have set up the crypto context
99
if (qemu_opts_id(all_opts) == NULL) {
102
* if the crypt method needs a header region, some methods
100
char *new_id;
103
* don't need header extensions, so must check here
101
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
104
@@ -XXX,XX +XXX,XX @@ int qcow2_update_header(BlockDriverState *bs)
102
dinfo->type = type;
105
.bit = QCOW2_INCOMPAT_CORRUPT_BITNR,
103
dinfo->bus = bus_id;
106
.name = "corrupt bit",
104
dinfo->unit = unit_id;
107
},
105
- dinfo->serial = g_strdup(serial);
108
+ {
106
109
+ .type = QCOW2_FEAT_TYPE_INCOMPATIBLE,
107
blk_set_legacy_dinfo(blk, dinfo);
110
+ .bit = QCOW2_INCOMPAT_DATA_FILE_BITNR,
108
111
+ .name = "external data file",
109
diff --git a/hw/block/block.c b/hw/block/block.c
112
+ },
110
index XXXXXXX..XXXXXXX 100644
113
{
111
--- a/hw/block/block.c
114
.type = QCOW2_FEAT_TYPE_COMPATIBLE,
112
+++ b/hw/block/block.c
115
.bit = QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR,
113
@@ -XXX,XX +XXX,XX @@
116
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
114
#include "qapi/qapi-types-block.h"
117
index XXXXXXX..XXXXXXX 100644
115
#include "qemu/error-report.h"
118
--- a/tests/qemu-iotests/031.out
116
119
+++ b/tests/qemu-iotests/031.out
117
-void blkconf_serial(BlockConf *conf, char **serial)
120
@@ -XXX,XX +XXX,XX @@ header_length 104
118
-{
121
119
- DriveInfo *dinfo;
122
Header extension:
120
-
123
magic 0x6803f857
121
- if (!*serial) {
124
-length 144
122
- /* try to fall back to value set with legacy -drive serial=... */
125
+length 192
123
- dinfo = blk_legacy_dinfo(conf->blk);
126
data <binary>
124
- if (dinfo) {
127
125
- *serial = g_strdup(dinfo->serial);
128
Header extension:
126
- }
129
@@ -XXX,XX +XXX,XX @@ header_length 104
127
- }
130
128
-}
131
Header extension:
129
-
132
magic 0x6803f857
130
void blkconf_blocksizes(BlockConf *conf)
133
-length 144
131
{
134
+length 192
132
BlockBackend *blk = conf->blk;
135
data <binary>
133
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
136
134
index XXXXXXX..XXXXXXX 100644
137
Header extension:
135
--- a/hw/block/nvme.c
138
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
136
+++ b/hw/block/nvme.c
139
137
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
140
magic 0x514649fb
138
return;
141
version 3
139
}
142
-backing_file_offset 0x148
140
143
+backing_file_offset 0x178
141
- blkconf_serial(&n->conf, &n->serial);
144
backing_file_size 0x17
142
if (!n->serial) {
145
cluster_bits 16
143
error_setg(errp, "serial property not set");
146
size 67108864
144
return;
147
@@ -XXX,XX +XXX,XX @@ data 'host_device'
145
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
148
146
index XXXXXXX..XXXXXXX 100644
149
Header extension:
147
--- a/hw/block/virtio-blk.c
150
magic 0x6803f857
148
+++ b/hw/block/virtio-blk.c
151
-length 144
149
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
152
+length 192
150
return;
153
data <binary>
151
}
154
152
155
Header extension:
153
- blkconf_serial(&conf->conf, &conf->serial);
156
diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out
154
if (!blkconf_apply_backend_options(&conf->conf,
157
index XXXXXXX..XXXXXXX 100644
155
blk_is_read_only(conf->conf.blk), true,
158
--- a/tests/qemu-iotests/036.out
156
errp)) {
159
+++ b/tests/qemu-iotests/036.out
157
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
160
@@ -XXX,XX +XXX,XX @@ header_length 104
158
index XXXXXXX..XXXXXXX 100644
161
159
--- a/hw/ide/qdev.c
162
Header extension:
160
+++ b/hw/ide/qdev.c
163
magic 0x6803f857
161
@@ -XXX,XX +XXX,XX @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
164
-length 144
162
return;
165
+length 192
163
}
166
data <binary>
164
167
165
- blkconf_serial(&dev->conf, &dev->serial);
168
166
if (kind != IDE_CD) {
169
@@ -XXX,XX +XXX,XX @@ header_length 104
167
if (!blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255,
170
168
errp)) {
171
Header extension:
169
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
172
magic 0x6803f857
170
index XXXXXXX..XXXXXXX 100644
173
-length 144
171
--- a/hw/scsi/scsi-disk.c
174
+length 192
172
+++ b/hw/scsi/scsi-disk.c
175
data <binary>
173
@@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
176
174
return;
177
*** done
175
}
178
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
176
179
index XXXXXXX..XXXXXXX 100644
177
- blkconf_serial(&s->qdev.conf, &s->serial);
180
--- a/tests/qemu-iotests/061.out
178
blkconf_blocksizes(&s->qdev.conf);
181
+++ b/tests/qemu-iotests/061.out
179
182
@@ -XXX,XX +XXX,XX @@ header_length 104
180
if (s->qdev.conf.logical_block_size >
183
181
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
184
Header extension:
182
index XXXXXXX..XXXXXXX 100644
185
magic 0x6803f857
183
--- a/hw/usb/dev-storage.c
186
-length 144
184
+++ b/hw/usb/dev-storage.c
187
+length 192
185
@@ -XXX,XX +XXX,XX @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
188
data <binary>
186
return;
189
187
}
190
magic 0x514649fb
188
191
@@ -XXX,XX +XXX,XX @@ header_length 104
189
- blkconf_serial(&s->conf, &dev->serial);
192
190
blkconf_blocksizes(&s->conf);
193
Header extension:
191
if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true,
194
magic 0x6803f857
192
errp)) {
195
-length 144
193
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
196
+length 192
194
index XXXXXXX..XXXXXXX 100644
197
data <binary>
195
--- a/tests/ahci-test.c
198
196
+++ b/tests/ahci-test.c
199
magic 0x514649fb
197
@@ -XXX,XX +XXX,XX @@ static AHCIQState *ahci_boot(const char *cli, ...)
200
@@ -XXX,XX +XXX,XX @@ header_length 104
198
s = ahci_vboot(cli, ap);
201
199
va_end(ap);
202
Header extension:
200
} else {
203
magic 0x6803f857
201
- cli = "-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s"
204
-length 144
202
- ",format=%s"
205
+length 192
203
+ cli = "-drive if=none,id=drive0,file=%s,cache=writeback,format=%s"
206
data <binary>
204
" -M q35 "
207
205
"-device ide-hd,drive=drive0 "
208
ERROR cluster 5 refcount=0 reference=1
206
+ "-global ide-hd.serial=%s "
209
@@ -XXX,XX +XXX,XX @@ header_length 104
207
"-global ide-hd.ver=%s";
210
208
- s = ahci_boot(cli, tmp_path, "testdisk", imgfmt, "version");
211
Header extension:
209
+ s = ahci_boot(cli, tmp_path, imgfmt, "testdisk", "version");
212
magic 0x6803f857
210
}
213
-length 144
211
214
+length 192
212
return s;
215
data <binary>
213
diff --git a/tests/ide-test.c b/tests/ide-test.c
216
214
index XXXXXXX..XXXXXXX 100644
217
magic 0x514649fb
215
--- a/tests/ide-test.c
218
@@ -XXX,XX +XXX,XX @@ header_length 104
216
+++ b/tests/ide-test.c
219
217
@@ -XXX,XX +XXX,XX @@ static void test_bmdma_no_busmaster(void)
220
Header extension:
218
static void test_bmdma_setup(void)
221
magic 0x6803f857
219
{
222
-length 144
220
ide_test_start(
223
+length 192
221
- "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw "
224
data <binary>
222
- "-global ide-hd.ver=%s",
225
223
+ "-drive file=%s,if=ide,cache=writeback,format=raw "
226
read 65536/65536 bytes at offset 44040192
224
+ "-global ide-hd.serial=%s -global ide-hd.ver=%s",
227
@@ -XXX,XX +XXX,XX @@ header_length 104
225
tmp_path, "testdisk", "version");
228
226
qtest_irq_intercept_in(global_qtest, "ioapic");
229
Header extension:
227
}
230
magic 0x6803f857
228
@@ -XXX,XX +XXX,XX @@ static void test_identify(void)
231
-length 144
229
int ret;
232
+length 192
230
233
data <binary>
231
ide_test_start(
234
232
- "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw "
235
ERROR cluster 5 refcount=0 reference=1
233
- "-global ide-hd.ver=%s",
236
@@ -XXX,XX +XXX,XX @@ header_length 104
234
+ "-drive file=%s,if=ide,cache=writeback,format=raw "
237
235
+ "-global ide-hd.serial=%s -global ide-hd.ver=%s",
238
Header extension:
236
tmp_path, "testdisk", "version");
239
magic 0x6803f857
237
240
-length 144
238
dev = get_pci_device(&bmdma_bar, &ide_bar);
241
+length 192
239
diff --git a/qemu-doc.texi b/qemu-doc.texi
242
data <binary>
240
index XXXXXXX..XXXXXXX 100644
243
241
--- a/qemu-doc.texi
244
read 131072/131072 bytes at offset 0
242
+++ b/qemu-doc.texi
243
@@ -XXX,XX +XXX,XX @@ with ``-device ...,netdev=x''), or ``-nic user,smb=/some/dir''
244
(for embedded NICs). The new syntax allows different settings to be
245
provided per NIC.
246
247
-@subsection -drive serial=... (since 2.10.0)
248
-
249
-The drive serial argument is replaced by the the serial argument
250
-that can be specified with the ``-device'' parameter.
251
-
252
@subsection -usbdevice (since 2.10.0)
253
254
The ``-usbdevice DEV'' argument is now a synonym for setting
255
diff --git a/qemu-options.hx b/qemu-options.hx
256
index XXXXXXX..XXXXXXX 100644
257
--- a/qemu-options.hx
258
+++ b/qemu-options.hx
259
@@ -XXX,XX +XXX,XX @@ ETEXI
260
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
261
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
262
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
263
- " [,snapshot=on|off][,serial=s][,rerror=ignore|stop|report]\n"
264
+ " [,snapshot=on|off][,rerror=ignore|stop|report]\n"
265
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
266
" [,readonly=on|off][,copy-on-read=on|off]\n"
267
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
268
@@ -XXX,XX +XXX,XX @@ The default mode is @option{cache=writeback}.
269
Specify which disk @var{format} will be used rather than detecting
270
the format. Can be used to specify format=raw to avoid interpreting
271
an untrusted format header.
272
-@item serial=@var{serial}
273
-This option specifies the serial number to assign to the device. This
274
-parameter is deprecated, use the corresponding parameter of @code{-device}
275
-instead.
276
@item werror=@var{action},rerror=@var{action}
277
Specify which @var{action} to take on write and read errors. Valid actions are:
278
"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
279
--
245
--
280
2.13.6
246
2.20.1
281
247
282
248
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
2
3
The previous commit fixed -blockdev breakage due to misuse of the
4
qobject input visitor's keyval flavor in bdrv_file_open(). The commit
5
message explain why using the plain flavor would be just as wrong; it
6
would break -drive. Turns out we break it in three places:
7
nbd_open(), sd_open() and ssh_file_open(). They are even marked
8
FIXME. Example breakage:
9
10
$ qemu-system-x86 -drive node-name=n1,driver=nbd,server.type=inet,server.host=localhost,server.port=1234,server.numeric=off
11
qemu-system-x86: -drive node-name=n1,driver=nbd,server.type=inet,server.host=localhost,server.port=1234,server.numeric=off: Invalid parameter type for 'numeric', expected: boolean
12
13
Fix it the same way: replace qdict_crumple() by
14
qdict_crumple_for_keyval_qiv(), and switch from plain to the keyval
15
flavor.
16
17
Signed-off-by: Markus Armbruster <armbru@redhat.com>
18
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
---
2
---
21
block/nbd.c | 12 ++----------
3
block/qcow2.h | 3 ++-
22
block/sheepdog.c | 12 ++----------
4
block/qcow2-cluster.c | 37 +++++++++++++++++++------------------
23
block/ssh.c | 12 ++----------
5
block/qcow2-refcount.c | 10 +++++-----
24
3 files changed, 6 insertions(+), 30 deletions(-)
6
3 files changed, 26 insertions(+), 24 deletions(-)
25
7
26
diff --git a/block/nbd.c b/block/nbd.c
8
diff --git a/block/qcow2.h b/block/qcow2.h
27
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
28
--- a/block/nbd.c
10
--- a/block/qcow2.h
29
+++ b/block/nbd.c
11
+++ b/block/qcow2.h
30
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
12
@@ -XXX,XX +XXX,XX @@ static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s)
31
goto done;
13
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
14
}
15
16
-static inline QCow2ClusterType qcow2_get_cluster_type(uint64_t l2_entry)
17
+static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs,
18
+ uint64_t l2_entry)
19
{
20
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
21
return QCOW2_CLUSTER_COMPRESSED;
22
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2-cluster.c
25
+++ b/block/qcow2-cluster.c
26
@@ -XXX,XX +XXX,XX @@ fail:
27
* as contiguous. (This allows it, for example, to stop at the first compressed
28
* cluster which may require a different handling)
29
*/
30
-static int count_contiguous_clusters(int nb_clusters, int cluster_size,
31
- uint64_t *l2_slice, uint64_t stop_flags)
32
+static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters,
33
+ int cluster_size, uint64_t *l2_slice, uint64_t stop_flags)
34
{
35
int i;
36
QCow2ClusterType first_cluster_type;
37
@@ -XXX,XX +XXX,XX @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size,
32
}
38
}
33
39
34
- crumpled_addr = qdict_crumple(addr, errp);
40
/* must be allocated */
35
+ crumpled_addr = qdict_crumple_for_keyval_qiv(addr, errp);
41
- first_cluster_type = qcow2_get_cluster_type(first_entry);
36
if (!crumpled_addr) {
42
+ first_cluster_type = qcow2_get_cluster_type(bs, first_entry);
37
goto done;
43
assert(first_cluster_type == QCOW2_CLUSTER_NORMAL ||
44
first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC);
45
46
@@ -XXX,XX +XXX,XX @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size,
47
* Checks how many consecutive unallocated clusters in a given L2
48
* slice have the same cluster type.
49
*/
50
-static int count_contiguous_clusters_unallocated(int nb_clusters,
51
+static int count_contiguous_clusters_unallocated(BlockDriverState *bs,
52
+ int nb_clusters,
53
uint64_t *l2_slice,
54
QCow2ClusterType wanted_type)
55
{
56
@@ -XXX,XX +XXX,XX @@ static int count_contiguous_clusters_unallocated(int nb_clusters,
57
wanted_type == QCOW2_CLUSTER_UNALLOCATED);
58
for (i = 0; i < nb_clusters; i++) {
59
uint64_t entry = be64_to_cpu(l2_slice[i]);
60
- QCow2ClusterType type = qcow2_get_cluster_type(entry);
61
+ QCow2ClusterType type = qcow2_get_cluster_type(bs, entry);
62
63
if (type != wanted_type) {
64
break;
65
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
66
* true */
67
assert(nb_clusters <= INT_MAX);
68
69
- type = qcow2_get_cluster_type(*cluster_offset);
70
+ type = qcow2_get_cluster_type(bs, *cluster_offset);
71
if (s->qcow_version < 3 && (type == QCOW2_CLUSTER_ZERO_PLAIN ||
72
type == QCOW2_CLUSTER_ZERO_ALLOC)) {
73
qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found"
74
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
75
case QCOW2_CLUSTER_ZERO_PLAIN:
76
case QCOW2_CLUSTER_UNALLOCATED:
77
/* how many empty clusters ? */
78
- c = count_contiguous_clusters_unallocated(nb_clusters,
79
+ c = count_contiguous_clusters_unallocated(bs, nb_clusters,
80
&l2_slice[l2_index], type);
81
*cluster_offset = 0;
82
break;
83
case QCOW2_CLUSTER_ZERO_ALLOC:
84
case QCOW2_CLUSTER_NORMAL:
85
/* how many allocated clusters ? */
86
- c = count_contiguous_clusters(nb_clusters, s->cluster_size,
87
+ c = count_contiguous_clusters(bs, nb_clusters, s->cluster_size,
88
&l2_slice[l2_index], QCOW_OFLAG_ZERO);
89
*cluster_offset &= L2E_OFFSET_MASK;
90
if (offset_into_cluster(s, *cluster_offset)) {
91
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
92
* write, but require COW to be performed (this includes yet unallocated space,
93
* which must copy from the backing file)
94
*/
95
-static int count_cow_clusters(BDRVQcow2State *s, int nb_clusters,
96
+static int count_cow_clusters(BlockDriverState *bs, int nb_clusters,
97
uint64_t *l2_slice, int l2_index)
98
{
99
int i;
100
101
for (i = 0; i < nb_clusters; i++) {
102
uint64_t l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
103
- QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry);
104
+ QCow2ClusterType cluster_type = qcow2_get_cluster_type(bs, l2_entry);
105
106
switch(cluster_type) {
107
case QCOW2_CLUSTER_NORMAL:
108
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
109
cluster_offset = be64_to_cpu(l2_slice[l2_index]);
110
111
/* Check how many clusters are already allocated and don't need COW */
112
- if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL
113
+ if (qcow2_get_cluster_type(bs, cluster_offset) == QCOW2_CLUSTER_NORMAL
114
&& (cluster_offset & QCOW_OFLAG_COPIED))
115
{
116
/* If a specific host_offset is required, check it */
117
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
118
119
/* We keep all QCOW_OFLAG_COPIED clusters */
120
keep_clusters =
121
- count_contiguous_clusters(nb_clusters, s->cluster_size,
122
+ count_contiguous_clusters(bs, nb_clusters, s->cluster_size,
123
&l2_slice[l2_index],
124
QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
125
assert(keep_clusters <= nb_clusters);
126
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
127
if (entry & QCOW_OFLAG_COMPRESSED) {
128
nb_clusters = 1;
129
} else {
130
- nb_clusters = count_cow_clusters(s, nb_clusters, l2_slice, l2_index);
131
+ nb_clusters = count_cow_clusters(bs, nb_clusters, l2_slice, l2_index);
38
}
132
}
39
133
40
- /*
134
/* This function is only called when there were no non-COW clusters, so if
41
- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive
135
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
42
- * server.type=inet. .to doesn't matter, it's ignored anyway.
136
* wrong with our code. */
43
- * That's because when @options come from -blockdev or
137
assert(nb_clusters > 0);
44
- * blockdev_add, members are typed according to the QAPI schema,
138
45
- * but when they come from -drive, they're all QString. The
139
- if (qcow2_get_cluster_type(entry) == QCOW2_CLUSTER_ZERO_ALLOC &&
46
- * visitor expects the former.
140
+ if (qcow2_get_cluster_type(bs, entry) == QCOW2_CLUSTER_ZERO_ALLOC &&
47
- */
141
(entry & QCOW_OFLAG_COPIED) &&
48
- iv = qobject_input_visitor_new(crumpled_addr);
142
(!*host_offset ||
49
+ iv = qobject_input_visitor_new_keyval(crumpled_addr);
143
start_of_cluster(s, *host_offset) == (entry & L2E_OFFSET_MASK)))
50
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
144
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
51
if (local_err) {
145
* would be fine, too, but count_cow_clusters() above has limited
52
error_propagate(errp, local_err);
146
* nb_clusters already to a range of COW clusters */
53
diff --git a/block/sheepdog.c b/block/sheepdog.c
147
preallocated_nb_clusters =
148
- count_contiguous_clusters(nb_clusters, s->cluster_size,
149
+ count_contiguous_clusters(bs, nb_clusters, s->cluster_size,
150
&l2_slice[l2_index], QCOW_OFLAG_COPIED);
151
assert(preallocated_nb_clusters > 0);
152
153
@@ -XXX,XX +XXX,XX @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
154
* If full_discard is true, the sector should not read back as zeroes,
155
* but rather fall through to the backing file.
156
*/
157
- switch (qcow2_get_cluster_type(old_l2_entry)) {
158
+ switch (qcow2_get_cluster_type(bs, old_l2_entry)) {
159
case QCOW2_CLUSTER_UNALLOCATED:
160
if (full_discard || !bs->backing) {
161
continue;
162
@@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
163
* Minimize L2 changes if the cluster already reads back as
164
* zeroes with correct allocation.
165
*/
166
- cluster_type = qcow2_get_cluster_type(old_offset);
167
+ cluster_type = qcow2_get_cluster_type(bs, old_offset);
168
if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN ||
169
(cluster_type == QCOW2_CLUSTER_ZERO_ALLOC && !unmap)) {
170
continue;
171
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
172
uint64_t l2_entry = be64_to_cpu(l2_slice[j]);
173
int64_t offset = l2_entry & L2E_OFFSET_MASK;
174
QCow2ClusterType cluster_type =
175
- qcow2_get_cluster_type(l2_entry);
176
+ qcow2_get_cluster_type(bs, l2_entry);
177
178
if (cluster_type != QCOW2_CLUSTER_ZERO_PLAIN &&
179
cluster_type != QCOW2_CLUSTER_ZERO_ALLOC) {
180
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
54
index XXXXXXX..XXXXXXX 100644
181
index XXXXXXX..XXXXXXX 100644
55
--- a/block/sheepdog.c
182
--- a/block/qcow2-refcount.c
56
+++ b/block/sheepdog.c
183
+++ b/block/qcow2-refcount.c
57
@@ -XXX,XX +XXX,XX @@ static SocketAddress *sd_server_config(QDict *options, Error **errp)
184
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
58
185
{
59
qdict_extract_subqdict(options, &server, "server.");
186
BDRVQcow2State *s = bs->opaque;
60
187
61
- crumpled_server = qdict_crumple(server, errp);
188
- switch (qcow2_get_cluster_type(l2_entry)) {
62
+ crumpled_server = qdict_crumple_for_keyval_qiv(server, errp);
189
+ switch (qcow2_get_cluster_type(bs, l2_entry)) {
63
if (!crumpled_server) {
190
case QCOW2_CLUSTER_COMPRESSED:
64
goto done;
191
{
65
}
192
int nb_csectors;
66
193
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
67
- /*
194
entry &= ~QCOW_OFLAG_COPIED;
68
- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive
195
offset = entry & L2E_OFFSET_MASK;
69
- * server.type=inet. .to doesn't matter, it's ignored anyway.
196
70
- * That's because when @options come from -blockdev or
197
- switch (qcow2_get_cluster_type(entry)) {
71
- * blockdev_add, members are typed according to the QAPI schema,
198
+ switch (qcow2_get_cluster_type(bs, entry)) {
72
- * but when they come from -drive, they're all QString. The
199
case QCOW2_CLUSTER_COMPRESSED:
73
- * visitor expects the former.
200
nb_csectors = ((entry >> s->csize_shift) &
74
- */
201
s->csize_mask) + 1;
75
- iv = qobject_input_visitor_new(crumpled_server);
202
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
76
+ iv = qobject_input_visitor_new_keyval(crumpled_server);
203
for(i = 0; i < s->l2_size; i++) {
77
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
204
l2_entry = be64_to_cpu(l2_table[i]);
78
if (local_err) {
205
79
error_propagate(errp, local_err);
206
- switch (qcow2_get_cluster_type(l2_entry)) {
80
diff --git a/block/ssh.c b/block/ssh.c
207
+ switch (qcow2_get_cluster_type(bs, l2_entry)) {
81
index XXXXXXX..XXXXXXX 100644
208
case QCOW2_CLUSTER_COMPRESSED:
82
--- a/block/ssh.c
209
/* Compressed clusters don't have QCOW_OFLAG_COPIED */
83
+++ b/block/ssh.c
210
if (l2_entry & QCOW_OFLAG_COPIED) {
84
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
211
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
85
}
212
86
213
/* Correct offsets are cluster aligned */
87
/* Create the QAPI object */
214
if (offset_into_cluster(s, offset)) {
88
- crumpled = qdict_crumple(options, errp);
215
- if (qcow2_get_cluster_type(l2_entry) ==
89
+ crumpled = qdict_crumple_for_keyval_qiv(options, errp);
216
+ if (qcow2_get_cluster_type(bs, l2_entry) ==
90
if (crumpled == NULL) {
217
QCOW2_CLUSTER_ZERO_ALLOC)
91
goto fail;
218
{
92
}
219
fprintf(stderr, "%s offset=%" PRIx64 ": Preallocated zero "
93
220
@@ -XXX,XX +XXX,XX @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
94
- /*
221
for (j = 0; j < s->l2_size; j++) {
95
- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive.
222
uint64_t l2_entry = be64_to_cpu(l2_table[j]);
96
- * .to doesn't matter, it's ignored anyway.
223
uint64_t data_offset = l2_entry & L2E_OFFSET_MASK;
97
- * That's because when @options come from -blockdev or
224
- QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry);
98
- * blockdev_add, members are typed according to the QAPI schema,
225
+ QCow2ClusterType cluster_type = qcow2_get_cluster_type(bs, l2_entry);
99
- * but when they come from -drive, they're all QString. The
226
100
- * visitor expects the former.
227
if (cluster_type == QCOW2_CLUSTER_NORMAL ||
101
- */
228
cluster_type == QCOW2_CLUSTER_ZERO_ALLOC) {
102
- v = qobject_input_visitor_new(crumpled);
103
+ v = qobject_input_visitor_new_keyval(crumpled);
104
visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err);
105
visit_free(v);
106
qobject_unref(crumpled);
107
--
229
--
108
2.13.6
230
2.20.1
109
231
110
232
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
2
3
qdict_flatten_qdict() skips copying scalars from @qdict to @target
4
when the two are the same. Fair enough, but it uses a non-obvious
5
test for "same". Replace it by the obvious one. While there, improve
6
comments.
7
8
Signed-off-by: Markus Armbruster <armbru@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
2
---
12
qobject/block-qdict.c | 14 +++++++++-----
3
block/qcow2.h | 10 +++++++++-
13
1 file changed, 9 insertions(+), 5 deletions(-)
4
1 file changed, 9 insertions(+), 1 deletion(-)
14
5
15
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
6
diff --git a/block/qcow2.h b/block/qcow2.h
16
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
17
--- a/qobject/block-qdict.c
8
--- a/block/qcow2.h
18
+++ b/qobject/block-qdict.c
9
+++ b/block/qcow2.h
19
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
10
@@ -XXX,XX +XXX,XX @@ static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs,
20
value = qlist_entry_obj(entry);
21
new_key = g_strdup_printf("%s.%i", prefix, i);
22
23
+ /*
24
+ * Flatten non-empty QDict and QList recursively into @target,
25
+ * copy other objects to @target
26
+ */
27
if (qobject_type(value) == QTYPE_QDICT) {
28
qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
29
} else if (qobject_type(value) == QTYPE_QLIST) {
30
qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
31
} else {
32
- /* All other types are moved to the target unchanged. */
33
qdict_put_obj(target, new_key, qobject_ref(value));
34
}
11
}
35
12
return QCOW2_CLUSTER_ZERO_PLAIN;
36
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
13
} else if (!(l2_entry & L2E_OFFSET_MASK)) {
37
new_key = g_strdup_printf("%s.%s", prefix, entry->key);
14
- return QCOW2_CLUSTER_UNALLOCATED;
38
}
15
+ /* Offset 0 generally means unallocated, but it is ambiguous with
39
16
+ * external data files because 0 is a valid offset there. However, all
40
+ /*
17
+ * clusters in external data files always have refcount 1, so we can
41
+ * Flatten non-empty QDict and QList recursively into @target,
18
+ * rely on QCOW_OFLAG_COPIED to disambiguate. */
42
+ * copy other objects to @target
19
+ if (has_data_file(bs) && (l2_entry & QCOW_OFLAG_COPIED)) {
43
+ */
20
+ return QCOW2_CLUSTER_NORMAL;
44
if (qobject_type(value) == QTYPE_QDICT) {
21
+ } else {
45
- /* Entries of QDicts are processed recursively, the QDict object
22
+ return QCOW2_CLUSTER_UNALLOCATED;
46
- * itself disappears. */
23
+ }
47
qdict_flatten_qdict(qobject_to(QDict, value), target,
24
} else {
48
new_key ? new_key : entry->key);
25
return QCOW2_CLUSTER_NORMAL;
49
qdict_del(qdict, entry->key);
26
}
50
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
51
qdict_flatten_qlist(qobject_to(QList, value), target,
52
new_key ? new_key : entry->key);
53
qdict_del(qdict, entry->key);
54
- } else if (prefix) {
55
- /* All other objects are moved to the target unchanged. */
56
+ } else if (target != qdict) {
57
qdict_put_obj(target, new_key, qobject_ref(value));
58
qdict_del(qdict, entry->key);
59
}
60
--
27
--
61
2.13.6
28
2.20.1
62
29
63
30
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
Offset 0 can be valid for normal (allocated) clusters now, so use
2
qcow2_get_cluster_type() instead.
2
3
3
Remaining uses of qobject_input_visitor_new_keyval() in the block
4
subsystem:
5
6
* block_crypto_open_opts_init()
7
Currently doesn't visit any non-string scalars, thus safe. It's
8
called from
9
- block_crypto_open_luks()
10
Creates the QDict with qemu_opts_to_qdict_filtered(), which
11
creates only string scalars, but has a TODO asking for other types.
12
- qcow_open()
13
- qcow2_open(), qcow2_co_invalidate_cache(), qcow2_reopen_prepare()
14
15
* block_crypto_create_opts_init(), called from
16
- block_crypto_co_create_opts_luks()
17
Also creates the QDict with qemu_opts_to_qdict_filtered().
18
19
* vdi_co_create_opts()
20
Also creates the QDict with qemu_opts_to_qdict_filtered().
21
22
Replace these uses by qobject_input_visitor_new_flat_confused() for
23
robustness. This adds crumpling. Right now, that's a no-op, but if
24
we ever extend these things in non-flat ways, crumpling will be
25
needed.
26
27
Signed-off-by: Markus Armbruster <armbru@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29
---
5
---
30
block/crypto.c | 12 +++++++++---
6
block/qcow2-cluster.c | 4 ++--
31
block/vdi.c | 8 ++++++--
7
1 file changed, 2 insertions(+), 2 deletions(-)
32
2 files changed, 15 insertions(+), 5 deletions(-)
33
8
34
diff --git a/block/crypto.c b/block/crypto.c
9
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
35
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
36
--- a/block/crypto.c
11
--- a/block/qcow2-cluster.c
37
+++ b/block/crypto.c
12
+++ b/block/qcow2-cluster.c
38
@@ -XXX,XX +XXX,XX @@
13
@@ -XXX,XX +XXX,XX @@ static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters,
39
#include "qemu/osdep.h"
14
uint64_t first_entry = be64_to_cpu(l2_slice[0]);
40
15
uint64_t offset = first_entry & mask;
41
#include "block/block_int.h"
16
42
+#include "block/qdict.h"
17
- if (!offset) {
43
#include "sysemu/block-backend.h"
18
+ first_cluster_type = qcow2_get_cluster_type(bs, first_entry);
44
#include "crypto/block.h"
19
+ if (first_cluster_type == QCOW2_CLUSTER_UNALLOCATED) {
45
#include "qapi/opts-visitor.h"
20
return 0;
46
#include "qapi/qapi-visit-crypto.h"
47
-#include "qapi/qmp/qdict.h"
48
#include "qapi/qobject-input-visitor.h"
49
#include "qapi/error.h"
50
#include "qemu/option.h"
51
@@ -XXX,XX +XXX,XX @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
52
ret = g_new0(QCryptoBlockOpenOptions, 1);
53
ret->format = format;
54
55
- v = qobject_input_visitor_new_keyval(QOBJECT(opts));
56
+ v = qobject_input_visitor_new_flat_confused(opts, &local_err);
57
+ if (local_err) {
58
+ goto out;
59
+ }
60
61
visit_start_struct(v, NULL, NULL, 0, &local_err);
62
if (local_err) {
63
@@ -XXX,XX +XXX,XX @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
64
ret = g_new0(QCryptoBlockCreateOptions, 1);
65
ret->format = format;
66
67
- v = qobject_input_visitor_new_keyval(QOBJECT(opts));
68
+ v = qobject_input_visitor_new_flat_confused(opts, &local_err);
69
+ if (local_err) {
70
+ goto out;
71
+ }
72
73
visit_start_struct(v, NULL, NULL, 0, &local_err);
74
if (local_err) {
75
diff --git a/block/vdi.c b/block/vdi.c
76
index XXXXXXX..XXXXXXX 100644
77
--- a/block/vdi.c
78
+++ b/block/vdi.c
79
@@ -XXX,XX +XXX,XX @@
80
81
#include "qemu/osdep.h"
82
#include "qapi/error.h"
83
-#include "qapi/qmp/qdict.h"
84
#include "qapi/qobject-input-visitor.h"
85
#include "qapi/qapi-visit-block-core.h"
86
#include "block/block_int.h"
87
+#include "block/qdict.h"
88
#include "sysemu/block-backend.h"
89
#include "qemu/module.h"
90
#include "qemu/option.h"
91
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
92
}
21
}
93
22
94
/* Get the QAPI object */
23
/* must be allocated */
95
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
24
- first_cluster_type = qcow2_get_cluster_type(bs, first_entry);
96
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
25
assert(first_cluster_type == QCOW2_CLUSTER_NORMAL ||
97
+ if (!v) {
26
first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC);
98
+ ret = -EINVAL;
99
+ goto done;
100
+ }
101
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
102
visit_free(v);
103
27
104
--
28
--
105
2.13.6
29
2.20.1
106
30
107
31
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
The cluster allocation code uses 0 as an invalid offset that is used in
2
case of errors or as "offset not yet determined". With external data
3
files, a host cluster offset of 0 becomes valid, though.
2
4
3
There's no need to restart the loop. We don't elsewhere, e.g. in
5
Define a constant INV_OFFSET (which is not cluster aligned and will
4
qdict_extract_subqdict(), qdict_join() and qemu_opts_absorb_qdict().
6
therefore never be a valid offset) that can be used for such purposes.
5
Simplify accordingly.
6
7
7
Signed-off-by: Markus Armbruster <armbru@redhat.com>
8
This removes the additional host_offset == 0 check that commit
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
ff52aab2df5 introduced; the confusion between an invalid offset and
10
(erroneous) allocation at offset 0 is removed with this change.
11
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
13
---
11
qobject/block-qdict.c | 18 +++---------------
14
block/qcow2.h | 2 ++
12
1 file changed, 3 insertions(+), 15 deletions(-)
15
block/qcow2-cluster.c | 59 ++++++++++++++++++++-----------------------
16
2 files changed, 29 insertions(+), 32 deletions(-)
13
17
14
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
18
diff --git a/block/qcow2.h b/block/qcow2.h
15
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
16
--- a/qobject/block-qdict.c
20
--- a/block/qcow2.h
17
+++ b/qobject/block-qdict.c
21
+++ b/block/qcow2.h
18
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
22
@@ -XXX,XX +XXX,XX @@ typedef enum QCow2MetadataOverlap {
19
QObject *value;
23
20
const QDictEntry *entry, *next;
24
#define REFT_OFFSET_MASK 0xfffffffffffffe00ULL
21
char *new_key;
25
22
- bool delete;
26
+#define INV_OFFSET (-1ULL)
23
27
+
24
entry = qdict_first(qdict);
28
static inline bool has_data_file(BlockDriverState *bs)
25
29
{
26
while (entry != NULL) {
30
BDRVQcow2State *s = bs->opaque;
27
-
31
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
28
next = qdict_next(qdict, entry);
32
index XXXXXXX..XXXXXXX 100644
29
value = qdict_entry_value(entry);
33
--- a/block/qcow2-cluster.c
30
new_key = NULL;
34
+++ b/block/qcow2-cluster.c
31
- delete = false;
35
@@ -XXX,XX +XXX,XX @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
32
36
33
if (prefix) {
37
/*
34
new_key = g_strdup_printf("%s.%s", prefix, entry->key);
38
* Checks how many already allocated clusters that don't require a copy on
35
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
39
- * write there are at the given guest_offset (up to *bytes). If
36
* itself disappears. */
40
- * *host_offset is not zero, only physically contiguous clusters beginning at
37
qdict_flatten_qdict(qobject_to(QDict, value), target,
41
- * this host offset are counted.
38
new_key ? new_key : entry->key);
42
+ * write there are at the given guest_offset (up to *bytes). If *host_offset is
39
- delete = true;
43
+ * not INV_OFFSET, only physically contiguous clusters beginning at this host
40
+ qdict_del(qdict, entry->key);
44
+ * offset are counted.
41
} else if (qobject_type(value) == QTYPE_QLIST) {
45
*
42
qdict_flatten_qlist(qobject_to(QList, value), target,
46
* Note that guest_offset may not be cluster aligned. In this case, the
43
new_key ? new_key : entry->key);
47
* returned *host_offset points to exact byte referenced by guest_offset and
44
- delete = true;
48
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
45
+ qdict_del(qdict, entry->key);
49
trace_qcow2_handle_copied(qemu_coroutine_self(), guest_offset, *host_offset,
46
} else if (prefix) {
50
*bytes);
47
/* All other objects are moved to the target unchanged. */
51
48
qdict_put_obj(target, new_key, qobject_ref(value));
52
- assert(*host_offset == 0 || offset_into_cluster(s, guest_offset)
49
- delete = true;
53
- == offset_into_cluster(s, *host_offset));
54
+ assert(*host_offset == INV_OFFSET || offset_into_cluster(s, guest_offset)
55
+ == offset_into_cluster(s, *host_offset));
56
57
/*
58
* Calculate the number of clusters to look for. We stop at L2 slice
59
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
60
goto out;
61
}
62
63
- if (*host_offset != 0 && !offset_matches) {
64
+ if (*host_offset != INV_OFFSET && !offset_matches) {
65
*bytes = 0;
66
ret = 0;
67
goto out;
68
@@ -XXX,XX +XXX,XX @@ out:
69
* contain the number of clusters that have been allocated and are contiguous
70
* in the image file.
71
*
72
- * If *host_offset is non-zero, it specifies the offset in the image file at
73
- * which the new clusters must start. *nb_clusters can be 0 on return in this
74
- * case if the cluster at host_offset is already in use. If *host_offset is
75
- * zero, the clusters can be allocated anywhere in the image file.
76
+ * If *host_offset is not INV_OFFSET, it specifies the offset in the image file
77
+ * at which the new clusters must start. *nb_clusters can be 0 on return in
78
+ * this case if the cluster at host_offset is already in use. If *host_offset
79
+ * is INV_OFFSET, the clusters can be allocated anywhere in the image file.
80
*
81
* *host_offset is updated to contain the offset into the image file at which
82
* the first allocated cluster starts.
83
@@ -XXX,XX +XXX,XX @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
84
85
/* Allocate new clusters */
86
trace_qcow2_cluster_alloc_phys(qemu_coroutine_self());
87
- if (*host_offset == 0) {
88
+ if (*host_offset == INV_OFFSET) {
89
int64_t cluster_offset =
90
qcow2_alloc_clusters(bs, *nb_clusters * s->cluster_size);
91
if (cluster_offset < 0) {
92
@@ -XXX,XX +XXX,XX @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
93
94
/*
95
* Allocates new clusters for an area that either is yet unallocated or needs a
96
- * copy on write. If *host_offset is non-zero, clusters are only allocated if
97
- * the new allocation can match the specified host offset.
98
+ * copy on write. If *host_offset is not INV_OFFSET, clusters are only
99
+ * allocated if the new allocation can match the specified host offset.
100
*
101
* Note that guest_offset may not be cluster aligned. In this case, the
102
* returned *host_offset points to exact byte referenced by guest_offset and
103
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
104
int ret;
105
bool keep_old_clusters = false;
106
107
- uint64_t alloc_cluster_offset = 0;
108
+ uint64_t alloc_cluster_offset = INV_OFFSET;
109
110
trace_qcow2_handle_alloc(qemu_coroutine_self(), guest_offset, *host_offset,
111
*bytes);
112
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
113
114
if (qcow2_get_cluster_type(bs, entry) == QCOW2_CLUSTER_ZERO_ALLOC &&
115
(entry & QCOW_OFLAG_COPIED) &&
116
- (!*host_offset ||
117
+ (*host_offset == INV_OFFSET ||
118
start_of_cluster(s, *host_offset) == (entry & L2E_OFFSET_MASK)))
119
{
120
int preallocated_nb_clusters;
121
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
122
123
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
124
125
- if (!alloc_cluster_offset) {
126
+ if (alloc_cluster_offset == INV_OFFSET) {
127
/* Allocate, if necessary at a given offset in the image file */
128
- alloc_cluster_offset = start_of_cluster(s, *host_offset);
129
+ alloc_cluster_offset = *host_offset == INV_OFFSET ? INV_OFFSET :
130
+ start_of_cluster(s, *host_offset);
131
ret = do_alloc_cluster_offset(bs, guest_offset, &alloc_cluster_offset,
132
&nb_clusters);
133
if (ret < 0) {
134
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
135
return 0;
136
}
137
138
- /* !*host_offset would overwrite the image header and is reserved for
139
- * "no host offset preferred". If 0 was a valid host offset, it'd
140
- * trigger the following overlap check; do that now to avoid having an
141
- * invalid value in *host_offset. */
142
- if (!alloc_cluster_offset) {
143
- ret = qcow2_pre_write_overlap_check(bs, 0, alloc_cluster_offset,
144
- nb_clusters * s->cluster_size);
145
- assert(ret < 0);
146
- goto fail;
50
- }
147
- }
51
-
148
+ assert(alloc_cluster_offset != INV_OFFSET);
52
- g_free(new_key);
149
}
53
-
150
54
- if (delete) {
151
/*
55
qdict_del(qdict, entry->key);
152
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
56
-
153
again:
57
- /* Restart loop after modifying the iterated QDict */
154
start = offset;
58
- entry = qdict_first(qdict);
155
remaining = *bytes;
59
- continue;
156
- cluster_offset = 0;
157
- *host_offset = 0;
158
+ cluster_offset = INV_OFFSET;
159
+ *host_offset = INV_OFFSET;
160
cur_bytes = 0;
161
*m = NULL;
162
163
while (true) {
164
165
- if (!*host_offset) {
166
+ if (*host_offset == INV_OFFSET && cluster_offset != INV_OFFSET) {
167
*host_offset = start_of_cluster(s, cluster_offset);
60
}
168
}
61
169
62
+ g_free(new_key);
170
@@ -XXX,XX +XXX,XX @@ again:
63
entry = next;
171
64
}
172
start += cur_bytes;
173
remaining -= cur_bytes;
174
- cluster_offset += cur_bytes;
175
+
176
+ if (cluster_offset != INV_OFFSET) {
177
+ cluster_offset += cur_bytes;
178
+ }
179
180
if (remaining == 0) {
181
break;
182
@@ -XXX,XX +XXX,XX @@ again:
183
184
*bytes -= remaining;
185
assert(*bytes > 0);
186
- assert(*host_offset != 0);
187
+ assert(*host_offset != INV_OFFSET);
188
189
return 0;
65
}
190
}
66
--
191
--
67
2.13.6
192
2.20.1
68
193
69
194
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
qcow2_alloc_compressed_cluster_offset() used to return the cluster
2
offset for success and 0 for error. This doesn't only conflict with 0 as
3
a valid host offset, but also loses the error code.
2
4
3
The following pattern occurs in the .bdrv_co_create_opts() methods of
5
Similar to the change made to qcow2_alloc_cluster_offset() for
4
parallels, qcow, qcow2, qed, vhdx and vpc:
6
uncompressed clusters in commit 148da7ea9d6, make the function return
7
0/-errno and return the allocated cluster offset in a by-reference
8
parameter.
5
9
6
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
7
qobject_unref(qdict);
8
qdict = qobject_to(QDict, qobj);
9
if (qdict == NULL) {
10
ret = -EINVAL;
11
goto done;
12
}
13
14
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
15
[...]
16
ret = 0;
17
done:
18
qobject_unref(qdict);
19
[...]
20
return ret;
21
22
If qobject_to() fails, we return failure without setting errp. That's
23
wrong. As far as I can tell, it cannot fail here. Clean it up
24
anyway, by removing the useless conversion.
25
26
Signed-off-by: Markus Armbruster <armbru@redhat.com>
27
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29
---
11
---
30
block/parallels.c | 9 ++++-----
12
block/qcow2.h | 7 ++++---
31
block/qcow.c | 9 ++++-----
13
block/qcow2-cluster.c | 28 +++++++++++++---------------
32
block/qcow2.c | 9 ++++-----
14
block/qcow2.c | 19 ++++++++-----------
33
block/qed.c | 9 ++++-----
15
tests/qemu-iotests/220.out | 2 +-
34
block/vhdx.c | 9 ++++-----
16
4 files changed, 26 insertions(+), 30 deletions(-)
35
block/vpc.c | 9 ++++-----
36
6 files changed, 24 insertions(+), 30 deletions(-)
37
17
38
diff --git a/block/parallels.c b/block/parallels.c
18
diff --git a/block/qcow2.h b/block/qcow2.h
39
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
40
--- a/block/parallels.c
20
--- a/block/qcow2.h
41
+++ b/block/parallels.c
21
+++ b/block/qcow2.h
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
22
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
43
BlockdevCreateOptions *create_options = NULL;
23
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
44
Error *local_err = NULL;
24
unsigned int *bytes, uint64_t *host_offset,
45
BlockDriverState *bs = NULL;
25
QCowL2Meta **m);
46
- QDict *qdict = NULL;
26
-uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
47
+ QDict *qdict;
27
- uint64_t offset,
48
QObject *qobj;
28
- int compressed_size);
49
Visitor *v;
29
+int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
50
int ret;
30
+ uint64_t offset,
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
31
+ int compressed_size,
52
qdict_put_str(qdict, "file", bs->node_name);
32
+ uint64_t *host_offset);
53
33
54
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
34
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
55
- qobject_unref(qdict);
35
void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
56
- qdict = qobject_to(QDict, qobj);
36
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
57
- if (qdict == NULL) {
37
index XXXXXXX..XXXXXXX 100644
58
+ if (!qobj) {
38
--- a/block/qcow2-cluster.c
59
ret = -EINVAL;
39
+++ b/block/qcow2-cluster.c
60
goto done;
40
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
41
/*
42
* alloc_compressed_cluster_offset
43
*
44
- * For a given offset of the disk image, return cluster offset in
45
- * qcow2 file.
46
- *
47
- * If the offset is not found, allocate a new compressed cluster.
48
- *
49
- * Return the cluster offset if successful,
50
- * Return 0, otherwise.
51
+ * For a given offset on the virtual disk, allocate a new compressed cluster
52
+ * and put the host offset of the cluster into *host_offset. If a cluster is
53
+ * already allocated at the offset, return an error.
54
*
55
+ * Return 0 on success and -errno in error cases
56
*/
57
-
58
-uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
59
- uint64_t offset,
60
- int compressed_size)
61
+int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
62
+ uint64_t offset,
63
+ int compressed_size,
64
+ uint64_t *host_offset)
65
{
66
BDRVQcow2State *s = bs->opaque;
67
int l2_index, ret;
68
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
69
70
ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
71
if (ret < 0) {
72
- return 0;
73
+ return ret;
61
}
74
}
62
75
63
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
76
/* Compression can't overwrite anything. Fail if the cluster was already
64
+ v = qobject_input_visitor_new_keyval(qobj);
77
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
65
+ qobject_unref(qobj);
78
cluster_offset = be64_to_cpu(l2_slice[l2_index]);
66
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
79
if (cluster_offset & L2E_OFFSET_MASK) {
67
visit_free(v);
80
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
68
81
- return 0;
69
diff --git a/block/qcow.c b/block/qcow.c
82
+ return -EIO;
70
index XXXXXXX..XXXXXXX 100644
71
--- a/block/qcow.c
72
+++ b/block/qcow.c
73
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
74
{
75
BlockdevCreateOptions *create_options = NULL;
76
BlockDriverState *bs = NULL;
77
- QDict *qdict = NULL;
78
+ QDict *qdict;
79
QObject *qobj;
80
Visitor *v;
81
const char *val;
82
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
83
qdict_put_str(qdict, "file", bs->node_name);
84
85
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
86
- qobject_unref(qdict);
87
- qdict = qobject_to(QDict, qobj);
88
- if (qdict == NULL) {
89
+ if (!qobj) {
90
ret = -EINVAL;
91
goto fail;
92
}
83
}
93
84
94
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
85
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
95
+ v = qobject_input_visitor_new_keyval(qobj);
86
if (cluster_offset < 0) {
96
+ qobject_unref(qobj);
87
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
97
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
88
- return 0;
98
visit_free(v);
89
+ return cluster_offset;
99
90
}
91
92
nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
93
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
94
l2_slice[l2_index] = cpu_to_be64(cluster_offset);
95
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
96
97
- return cluster_offset;
98
+ *host_offset = cluster_offset & s->cluster_offset_mask;
99
+ return 0;
100
}
101
102
static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
100
diff --git a/block/qcow2.c b/block/qcow2.c
103
diff --git a/block/qcow2.c b/block/qcow2.c
101
index XXXXXXX..XXXXXXX 100644
104
index XXXXXXX..XXXXXXX 100644
102
--- a/block/qcow2.c
105
--- a/block/qcow2.c
103
+++ b/block/qcow2.c
106
+++ b/block/qcow2.c
104
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
107
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
105
Error **errp)
108
int ret;
106
{
109
size_t out_len;
107
BlockdevCreateOptions *create_options = NULL;
110
uint8_t *buf, *out_buf;
108
- QDict *qdict = NULL;
111
- int64_t cluster_offset;
109
+ QDict *qdict;
112
+ uint64_t cluster_offset;
110
QObject *qobj;
113
111
Visitor *v;
114
if (bytes == 0) {
112
BlockDriverState *bs = NULL;
115
/* align end of file to a sector boundary to ease reading with
113
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
116
sector based I/Os */
114
117
- cluster_offset = bdrv_getlength(bs->file->bs);
115
/* Now get the QAPI type BlockdevCreateOptions */
118
- if (cluster_offset < 0) {
116
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
119
- return cluster_offset;
117
- qobject_unref(qdict);
120
+ int64_t len = bdrv_getlength(bs->file->bs);
118
- qdict = qobject_to(QDict, qobj);
121
+ if (len < 0) {
119
- if (qdict == NULL) {
122
+ return len;
120
+ if (!qobj) {
123
}
121
ret = -EINVAL;
124
- return bdrv_co_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF,
122
goto finish;
125
- NULL);
126
+ return bdrv_co_truncate(bs->file, len, PREALLOC_MODE_OFF, NULL);
123
}
127
}
124
128
125
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
129
if (offset_into_cluster(s, offset)) {
126
+ v = qobject_input_visitor_new_keyval(qobj);
130
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
127
+ qobject_unref(qobj);
131
}
128
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
132
129
visit_free(v);
133
qemu_co_mutex_lock(&s->lock);
130
134
- cluster_offset =
131
diff --git a/block/qed.c b/block/qed.c
135
- qcow2_alloc_compressed_cluster_offset(bs, offset, out_len);
132
index XXXXXXX..XXXXXXX 100644
136
- if (!cluster_offset) {
133
--- a/block/qed.c
137
+ ret = qcow2_alloc_compressed_cluster_offset(bs, offset, out_len,
134
+++ b/block/qed.c
138
+ &cluster_offset);
135
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
139
+ if (ret < 0) {
136
Error **errp)
140
qemu_co_mutex_unlock(&s->lock);
137
{
141
- ret = -EIO;
138
BlockdevCreateOptions *create_options = NULL;
139
- QDict *qdict = NULL;
140
+ QDict *qdict;
141
QObject *qobj;
142
Visitor *v;
143
BlockDriverState *bs = NULL;
144
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
145
qdict_put_str(qdict, "file", bs->node_name);
146
147
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
148
- qobject_unref(qdict);
149
- qdict = qobject_to(QDict, qobj);
150
- if (qdict == NULL) {
151
+ if (!qobj) {
152
ret = -EINVAL;
153
goto fail;
142
goto fail;
154
}
143
}
155
144
- cluster_offset &= s->cluster_offset_mask;
156
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
145
157
+ v = qobject_input_visitor_new_keyval(qobj);
146
ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len);
158
+ qobject_unref(qobj);
147
qemu_co_mutex_unlock(&s->lock);
159
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
148
diff --git a/tests/qemu-iotests/220.out b/tests/qemu-iotests/220.out
160
visit_free(v);
161
162
diff --git a/block/vhdx.c b/block/vhdx.c
163
index XXXXXXX..XXXXXXX 100644
149
index XXXXXXX..XXXXXXX 100644
164
--- a/block/vhdx.c
150
--- a/tests/qemu-iotests/220.out
165
+++ b/block/vhdx.c
151
+++ b/tests/qemu-iotests/220.out
166
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
152
@@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 37748736
167
Error **errp)
153
No errors were found on the image.
168
{
154
image size 39845888
169
BlockdevCreateOptions *create_options = NULL;
155
== Trying to write compressed cluster ==
170
- QDict *qdict = NULL;
156
-write failed: Input/output error
171
+ QDict *qdict;
157
+write failed: File too large
172
QObject *qobj;
158
image size 562949957615616
173
Visitor *v;
159
== Writing normal cluster ==
174
BlockDriverState *bs = NULL;
160
wrote 2097152/2097152 bytes at offset 0
175
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
176
qdict_put_str(qdict, "file", bs->node_name);
177
178
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
179
- qobject_unref(qdict);
180
- qdict = qobject_to(QDict, qobj);
181
- if (qdict == NULL) {
182
+ if (!qobj) {
183
ret = -EINVAL;
184
goto fail;
185
}
186
187
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
188
+ v = qobject_input_visitor_new_keyval(qobj);
189
+ qobject_unref(qobj);
190
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
191
visit_free(v);
192
193
diff --git a/block/vpc.c b/block/vpc.c
194
index XXXXXXX..XXXXXXX 100644
195
--- a/block/vpc.c
196
+++ b/block/vpc.c
197
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
198
QemuOpts *opts, Error **errp)
199
{
200
BlockdevCreateOptions *create_options = NULL;
201
- QDict *qdict = NULL;
202
+ QDict *qdict;
203
QObject *qobj;
204
Visitor *v;
205
BlockDriverState *bs = NULL;
206
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
207
qdict_put_str(qdict, "file", bs->node_name);
208
209
qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
210
- qobject_unref(qdict);
211
- qdict = qobject_to(QDict, qobj);
212
- if (qdict == NULL) {
213
+ if (!qobj) {
214
ret = -EINVAL;
215
goto fail;
216
}
217
218
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
219
+ v = qobject_input_visitor_new_keyval(qobj);
220
+ qobject_unref(qobj);
221
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
222
visit_free(v);
223
224
--
161
--
225
2.13.6
162
2.20.1
226
163
227
164
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
Offset 0 cannot be assumed to mean an unallocated cluster any more.
2
Instead, the cluster type needs to be checked.
2
3
3
Parameter "filename" is deprecated since commit 5c3ad1a6a8f, v2.10.0.
4
*file must refer to the data file instead of the image file if a valid
4
Time to get rid of it.
5
offset is returned from qcow2_co_block_status().
5
6
6
Signed-off-by: Markus Armbruster <armbru@redhat.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
8
---
10
block/iscsi.c | 23 ++---------------------
9
block/qcow2.c | 4 ++--
11
1 file changed, 2 insertions(+), 21 deletions(-)
10
1 file changed, 2 insertions(+), 2 deletions(-)
12
11
13
diff --git a/block/iscsi.c b/block/iscsi.c
12
diff --git a/block/qcow2.c b/block/qcow2.c
14
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
15
--- a/block/iscsi.c
14
--- a/block/qcow2.c
16
+++ b/block/iscsi.c
15
+++ b/block/qcow2.c
17
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
16
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
18
.name = "timeout",
17
19
.type = QEMU_OPT_NUMBER,
18
*pnum = bytes;
20
},
19
21
- {
20
- if (cluster_offset != 0 && ret != QCOW2_CLUSTER_COMPRESSED &&
22
- .name = "filename",
21
+ if ((ret == QCOW2_CLUSTER_NORMAL || ret == QCOW2_CLUSTER_ZERO_ALLOC) &&
23
- .type = QEMU_OPT_STRING,
22
!s->crypto) {
24
- },
23
index_in_cluster = offset & (s->cluster_size - 1);
25
{ /* end of list */ }
24
*map = cluster_offset | index_in_cluster;
26
},
25
- *file = bs->file->bs;
27
};
26
+ *file = s->data_file->bs;
28
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
27
status |= BDRV_BLOCK_OFFSET_VALID;
29
char *initiator_name = NULL;
30
QemuOpts *opts;
31
Error *local_err = NULL;
32
- const char *transport_name, *portal, *target, *filename;
33
+ const char *transport_name, *portal, *target;
34
#if LIBISCSI_API_VERSION >= (20160603)
35
enum iscsi_transport_type transport;
36
#endif
37
int i, ret = 0, timeout = 0, lun;
38
39
- /* If we are given a filename, parse the filename, with precedence given to
40
- * filename encoded options */
41
- filename = qdict_get_try_str(options, "filename");
42
- if (filename) {
43
- warn_report("'filename' option specified. "
44
- "This is an unsupported option, and may be deprecated "
45
- "in the future");
46
- iscsi_parse_filename(filename, options, &local_err);
47
- if (local_err) {
48
- ret = -EINVAL;
49
- error_propagate(errp, local_err);
50
- goto exit;
51
- }
52
- }
53
-
54
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
55
qemu_opts_absorb_qdict(opts, options, &local_err);
56
if (local_err) {
57
@@ -XXX,XX +XXX,XX @@ out:
58
}
59
memset(iscsilun, 0, sizeof(IscsiLun));
60
}
28
}
61
-exit:
29
if (ret == QCOW2_CLUSTER_ZERO_PLAIN || ret == QCOW2_CLUSTER_ZERO_ALLOC) {
62
+
63
return ret;
64
}
65
66
--
30
--
67
2.13.6
31
2.20.1
68
32
69
33
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
This changes the qcow2 implementation to direct all guest data I/O to
2
s->data_file rather than bs->file, while metadata I/O still uses
3
bs->file. At the moment, this is still always the same, but soon we'll
4
add options to set s->data_file to an external data file.
2
5
3
Configuration flows through the block subsystem in a rather peculiar
4
way. Configuration made with -drive enters it as QemuOpts.
5
Configuration made with -blockdev / blockdev-add enters it as QAPI
6
type BlockdevOptions. The block subsystem uses QDict, QemuOpts and
7
QAPI types internally. The precise flow is next to impossible to
8
explain (I tried for this commit message, but gave up after wasting
9
several hours). What I can explain is a flaw in the BlockDriver
10
interface that leads to this bug:
11
12
$ qemu-system-x86_64 -blockdev node-name=n1,driver=nfs,server.type=inet,server.host=localhost,path=/foo/bar,user=1234
13
qemu-system-x86_64: -blockdev node-name=n1,driver=nfs,server.type=inet,server.host=localhost,path=/foo/bar,user=1234: Internal error: parameter user invalid
14
15
QMP blockdev-add is broken the same way.
16
17
Here's what happens. The block layer passes configuration represented
18
as flat QDict (with dotted keys) to BlockDriver methods
19
.bdrv_file_open(). The QDict's members are typed according to the
20
QAPI schema.
21
22
nfs_file_open() converts it to QAPI type BlockdevOptionsNfs, with
23
qdict_crumple() and a qobject input visitor.
24
25
This visitor comes in two flavors. The plain flavor requires scalars
26
to be typed according to the QAPI schema. That's the case here. The
27
keyval flavor requires string scalars. That's not the case here.
28
nfs_file_open() uses the latter, and promptly falls apart for members
29
@user, @group, @tcp-syn-count, @readahead-size, @page-cache-size,
30
@debug.
31
32
Switching to the plain flavor would fix -blockdev, but break -drive,
33
because there the scalars arrive in nfs_file_open() as strings.
34
35
The proper fix would be to replace the QDict by QAPI type
36
BlockdevOptions in the BlockDriver interface. Sadly, that's beyond my
37
reach right now.
38
39
Next best would be to fix the block layer to always pass correctly
40
typed QDicts to the BlockDriver methods. Also beyond my reach.
41
42
What I can do is throw another hack onto the pile: have
43
nfs_file_open() convert all members to string, so use of the keyval
44
flavor actually works, by replacing qdict_crumple() by new function
45
qdict_crumple_for_keyval_qiv().
46
47
The pattern "pass result of qdict_crumple() to
48
qobject_input_visitor_new_keyval()" occurs several times more:
49
50
* qemu_rbd_open()
51
52
Same issue as nfs_file_open(), but since BlockdevOptionsRbd has only
53
string members, its only a latent bug. Fix it anyway.
54
55
* parallels_co_create_opts(), qcow_co_create_opts(),
56
qcow2_co_create_opts(), bdrv_qed_co_create_opts(),
57
sd_co_create_opts(), vhdx_co_create_opts(), vpc_co_create_opts()
58
59
These work, because they create the QDict with
60
qemu_opts_to_qdict_filtered(), which creates only string scalars.
61
The function sports a TODO comment asking for better typing; that's
62
going to be fun. Use qdict_crumple_for_keyval_qiv() to be safe.
63
64
Signed-off-by: Markus Armbruster <armbru@redhat.com>
65
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
66
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
67
---
7
---
68
include/block/qdict.h | 1 +
8
block/qcow2.h | 2 +-
69
block/nfs.c | 2 +-
9
block/qcow2-bitmap.c | 7 +++---
70
block/parallels.c | 2 +-
10
block/qcow2-cache.c | 6 ++---
71
block/qcow.c | 2 +-
11
block/qcow2-cluster.c | 46 +++++++++++++++++++++++++++++++------
72
block/qcow2.c | 2 +-
12
block/qcow2-refcount.c | 39 +++++++++++++++++++++++--------
73
block/qed.c | 2 +-
13
block/qcow2-snapshot.c | 7 +++---
74
block/rbd.c | 2 +-
14
block/qcow2.c | 52 +++++++++++++++++++++++++++++++++---------
75
block/sheepdog.c | 2 +-
15
7 files changed, 122 insertions(+), 37 deletions(-)
76
block/vhdx.c | 2 +-
77
block/vpc.c | 2 +-
78
qobject/block-qdict.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++
79
11 files changed, 67 insertions(+), 9 deletions(-)
80
16
81
diff --git a/include/block/qdict.h b/include/block/qdict.h
17
diff --git a/block/qcow2.h b/block/qcow2.h
82
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
83
--- a/include/block/qdict.h
19
--- a/block/qcow2.h
84
+++ b/include/block/qdict.h
20
+++ b/block/qcow2.h
85
@@ -XXX,XX +XXX,XX @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
21
@@ -XXX,XX +XXX,XX @@ void qcow2_process_discards(BlockDriverState *bs, int ret);
86
void qdict_array_split(QDict *src, QList **dst);
22
int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
87
int qdict_array_entries(QDict *src, const char *subqdict);
23
int64_t size);
88
QObject *qdict_crumple(const QDict *src, Error **errp);
24
int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
89
+QObject *qdict_crumple_for_keyval_qiv(QDict *qdict, Error **errp);
25
- int64_t size);
90
void qdict_flatten(QDict *qdict);
26
+ int64_t size, bool data_file);
91
27
int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
92
typedef struct QDictRenames {
28
void **refcount_table,
93
diff --git a/block/nfs.c b/block/nfs.c
29
int64_t *refcount_table_size,
94
index XXXXXXX..XXXXXXX 100644
30
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
95
--- a/block/nfs.c
31
index XXXXXXX..XXXXXXX 100644
96
+++ b/block/nfs.c
32
--- a/block/qcow2-bitmap.c
97
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
33
+++ b/block/qcow2-bitmap.c
98
const QDictEntry *e;
34
@@ -XXX,XX +XXX,XX @@ static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list,
99
Error *local_err = NULL;
35
* directory in-place (actually, turn-off the extension), which is checked
100
36
* in qcow2_check_metadata_overlap() */
101
- crumpled = qdict_crumple(options, errp);
37
ret = qcow2_pre_write_overlap_check(
102
+ crumpled = qdict_crumple_for_keyval_qiv(options, errp);
38
- bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_size);
103
if (crumpled == NULL) {
39
+ bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_size,
104
return NULL;
40
+ false);
105
}
41
if (ret < 0) {
106
diff --git a/block/parallels.c b/block/parallels.c
42
goto fail;
107
index XXXXXXX..XXXXXXX 100644
43
}
108
--- a/block/parallels.c
44
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
109
+++ b/block/parallels.c
45
memset(buf + write_size, 0, s->cluster_size - write_size);
110
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
46
}
111
qdict_put_str(qdict, "driver", "parallels");
47
112
qdict_put_str(qdict, "file", bs->node_name);
48
- ret = qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size);
113
49
+ ret = qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size, false);
114
- qobj = qdict_crumple(qdict, errp);
50
if (ret < 0) {
115
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
51
error_setg_errno(errp, -ret, "Qcow2 overlap check failed");
116
qobject_unref(qdict);
52
goto fail;
117
qdict = qobject_to(QDict, qobj);
53
@@ -XXX,XX +XXX,XX @@ static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp)
118
if (qdict == NULL) {
54
}
119
diff --git a/block/qcow.c b/block/qcow.c
55
120
index XXXXXXX..XXXXXXX 100644
56
ret = qcow2_pre_write_overlap_check(bs, 0, tb_offset,
121
--- a/block/qcow.c
57
- tb_size * sizeof(tb[0]));
122
+++ b/block/qcow.c
58
+ tb_size * sizeof(tb[0]), false);
123
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
59
if (ret < 0) {
124
qdict_put_str(qdict, "driver", "qcow");
60
error_setg_errno(errp, -ret, "Qcow2 overlap check failed");
125
qdict_put_str(qdict, "file", bs->node_name);
61
goto fail;
126
62
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
127
- qobj = qdict_crumple(qdict, errp);
63
index XXXXXXX..XXXXXXX 100644
128
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
64
--- a/block/qcow2-cache.c
129
qobject_unref(qdict);
65
+++ b/block/qcow2-cache.c
130
qdict = qobject_to(QDict, qobj);
66
@@ -XXX,XX +XXX,XX @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
131
if (qdict == NULL) {
67
68
if (c == s->refcount_block_cache) {
69
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_BLOCK,
70
- c->entries[i].offset, c->table_size);
71
+ c->entries[i].offset, c->table_size, false);
72
} else if (c == s->l2_table_cache) {
73
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
74
- c->entries[i].offset, c->table_size);
75
+ c->entries[i].offset, c->table_size, false);
76
} else {
77
ret = qcow2_pre_write_overlap_check(bs, 0,
78
- c->entries[i].offset, c->table_size);
79
+ c->entries[i].offset, c->table_size, false);
80
}
81
82
if (ret < 0) {
83
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
84
index XXXXXXX..XXXXXXX 100644
85
--- a/block/qcow2-cluster.c
86
+++ b/block/qcow2-cluster.c
87
@@ -XXX,XX +XXX,XX @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
88
/* the L1 position has not yet been updated, so these clusters must
89
* indeed be completely free */
90
ret = qcow2_pre_write_overlap_check(bs, 0, new_l1_table_offset,
91
- new_l1_size2);
92
+ new_l1_size2, false);
93
if (ret < 0) {
94
goto fail;
95
}
96
@@ -XXX,XX +XXX,XX @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
97
}
98
99
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1,
100
- s->l1_table_offset + 8 * l1_start_index, sizeof(buf));
101
+ s->l1_table_offset + 8 * l1_start_index, sizeof(buf), false);
102
if (ret < 0) {
103
return ret;
104
}
105
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
106
unsigned offset_in_cluster,
107
QEMUIOVector *qiov)
108
{
109
+ BDRVQcow2State *s = bs->opaque;
110
int ret;
111
112
if (qiov->size == 0) {
113
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
114
}
115
116
ret = qcow2_pre_write_overlap_check(bs, 0,
117
- cluster_offset + offset_in_cluster, qiov->size);
118
+ cluster_offset + offset_in_cluster, qiov->size, true);
119
if (ret < 0) {
120
return ret;
121
}
122
123
BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
124
- ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster,
125
+ ret = bdrv_co_pwritev(s->data_file, cluster_offset + offset_in_cluster,
126
qiov->size, qiov, 0);
127
if (ret < 0) {
128
return ret;
129
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
130
}
131
switch (type) {
132
case QCOW2_CLUSTER_COMPRESSED:
133
+ if (has_data_file(bs)) {
134
+ qcow2_signal_corruption(bs, true, -1, -1, "Compressed cluster "
135
+ "entry found in image with external data "
136
+ "file (L2 offset: %#" PRIx64 ", L2 index: "
137
+ "%#x)", l2_offset, l2_index);
138
+ ret = -EIO;
139
+ goto fail;
140
+ }
141
/* Compressed clusters can only be processed one by one */
142
c = 1;
143
*cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
144
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
145
ret = -EIO;
146
goto fail;
147
}
148
+ if (has_data_file(bs) && *cluster_offset != offset - offset_in_cluster)
149
+ {
150
+ qcow2_signal_corruption(bs, true, -1, -1,
151
+ "External data file host cluster offset %#"
152
+ PRIx64 " does not match guest cluster "
153
+ "offset: %#" PRIx64
154
+ ", L2 index: %#x)", *cluster_offset,
155
+ offset - offset_in_cluster, l2_index);
156
+ ret = -EIO;
157
+ goto fail;
158
+ }
159
break;
160
default:
161
abort();
162
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
163
int64_t cluster_offset;
164
int nb_csectors;
165
166
+ if (has_data_file(bs)) {
167
+ return 0;
168
+ }
169
+
170
ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
171
if (ret < 0) {
172
return ret;
173
@@ -XXX,XX +XXX,XX @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
174
trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offset,
175
*host_offset, *nb_clusters);
176
177
+ if (has_data_file(bs)) {
178
+ assert(*host_offset == INV_OFFSET ||
179
+ *host_offset == start_of_cluster(s, guest_offset));
180
+ *host_offset = start_of_cluster(s, guest_offset);
181
+ return 0;
182
+ }
183
+
184
/* Allocate new clusters */
185
trace_qcow2_cluster_alloc_phys(qemu_coroutine_self());
186
if (*host_offset == INV_OFFSET) {
187
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
188
}
189
190
ret = qcow2_pre_write_overlap_check(bs, 0, offset,
191
- s->cluster_size);
192
+ s->cluster_size, true);
193
if (ret < 0) {
194
if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
195
qcow2_free_clusters(bs, offset, s->cluster_size,
196
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
197
goto fail;
198
}
199
200
- ret = bdrv_pwrite_zeroes(bs->file, offset, s->cluster_size, 0);
201
+ ret = bdrv_pwrite_zeroes(s->data_file, offset,
202
+ s->cluster_size, 0);
203
if (ret < 0) {
204
if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
205
qcow2_free_clusters(bs, offset, s->cluster_size,
206
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
207
if (l2_dirty) {
208
ret = qcow2_pre_write_overlap_check(
209
bs, QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2,
210
- slice_offset, slice_size2);
211
+ slice_offset, slice_size2, false);
212
if (ret < 0) {
213
goto fail;
214
}
215
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
216
index XXXXXXX..XXXXXXX 100644
217
--- a/block/qcow2-refcount.c
218
+++ b/block/qcow2-refcount.c
219
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
220
int nb_clusters, enum qcow2_discard_type type)
221
{
222
BDRVQcow2State *s = bs->opaque;
223
+ QCow2ClusterType ctype = qcow2_get_cluster_type(bs, l2_entry);
224
225
- switch (qcow2_get_cluster_type(bs, l2_entry)) {
226
+ if (has_data_file(bs)) {
227
+ if (s->discard_passthrough[type] &&
228
+ (ctype == QCOW2_CLUSTER_NORMAL ||
229
+ ctype == QCOW2_CLUSTER_ZERO_ALLOC))
230
+ {
231
+ bdrv_pdiscard(s->data_file, l2_entry & L2E_OFFSET_MASK,
232
+ nb_clusters << s->cluster_bits);
233
+ }
234
+ return;
235
+ }
236
+
237
+ switch (ctype) {
238
case QCOW2_CLUSTER_COMPRESSED:
239
{
240
int nb_csectors;
241
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
242
l2_table[i] = cpu_to_be64(l2_entry);
243
ret = qcow2_pre_write_overlap_check(bs,
244
QCOW2_OL_ACTIVE_L2 | QCOW2_OL_INACTIVE_L2,
245
- l2e_offset, sizeof(uint64_t));
246
+ l2e_offset, sizeof(uint64_t), false);
247
if (ret < 0) {
248
fprintf(stderr, "ERROR: Overlap check failed\n");
249
res->check_errors++;
250
@@ -XXX,XX +XXX,XX @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
251
252
if (l2_dirty) {
253
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
254
- l2_offset, s->cluster_size);
255
+ l2_offset, s->cluster_size,
256
+ false);
257
if (ret < 0) {
258
fprintf(stderr, "ERROR: Could not write L2 table; metadata "
259
"overlap check failed: %s\n", strerror(-ret));
260
@@ -XXX,XX +XXX,XX @@ write_refblocks:
261
}
262
263
ret = qcow2_pre_write_overlap_check(bs, 0, refblock_offset,
264
- s->cluster_size);
265
+ s->cluster_size, false);
266
if (ret < 0) {
267
fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret));
268
goto fail;
269
@@ -XXX,XX +XXX,XX @@ write_refblocks:
270
}
271
272
ret = qcow2_pre_write_overlap_check(bs, 0, reftable_offset,
273
- reftable_size * sizeof(uint64_t));
274
+ reftable_size * sizeof(uint64_t),
275
+ false);
276
if (ret < 0) {
277
fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret));
278
goto fail;
279
@@ -XXX,XX +XXX,XX @@ QEMU_BUILD_BUG_ON(QCOW2_OL_MAX_BITNR != ARRAY_SIZE(metadata_ol_names));
280
* overlaps; or a negative value (-errno) on error.
281
*/
282
int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
283
- int64_t size)
284
+ int64_t size, bool data_file)
285
{
286
- int ret = qcow2_check_metadata_overlap(bs, ign, offset, size);
287
+ int ret;
288
+
289
+ if (data_file && has_data_file(bs)) {
290
+ return 0;
291
+ }
292
293
+ ret = qcow2_check_metadata_overlap(bs, ign, offset, size);
294
if (ret < 0) {
295
return ret;
296
} else if (ret > 0) {
297
@@ -XXX,XX +XXX,XX @@ static int flush_refblock(BlockDriverState *bs, uint64_t **reftable,
298
if (reftable_index < *reftable_size && (*reftable)[reftable_index]) {
299
offset = (*reftable)[reftable_index];
300
301
- ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size);
302
+ ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size,
303
+ false);
304
if (ret < 0) {
305
error_setg_errno(errp, -ret, "Overlap check failed");
306
return ret;
307
@@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
308
309
/* Write the new reftable */
310
ret = qcow2_pre_write_overlap_check(bs, 0, new_reftable_offset,
311
- new_reftable_size * sizeof(uint64_t));
312
+ new_reftable_size * sizeof(uint64_t),
313
+ false);
314
if (ret < 0) {
315
error_setg_errno(errp, -ret, "Overlap check failed");
316
goto done;
317
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
318
index XXXXXXX..XXXXXXX 100644
319
--- a/block/qcow2-snapshot.c
320
+++ b/block/qcow2-snapshot.c
321
@@ -XXX,XX +XXX,XX @@ static int qcow2_write_snapshots(BlockDriverState *bs)
322
323
/* The snapshot list position has not yet been updated, so these clusters
324
* must indeed be completely free */
325
- ret = qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size);
326
+ ret = qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size, false);
327
if (ret < 0) {
328
goto fail;
329
}
330
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
331
}
332
333
ret = qcow2_pre_write_overlap_check(bs, 0, sn->l1_table_offset,
334
- s->l1_size * sizeof(uint64_t));
335
+ s->l1_size * sizeof(uint64_t), false);
336
if (ret < 0) {
337
goto fail;
338
}
339
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
340
}
341
342
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1,
343
- s->l1_table_offset, cur_l1_bytes);
344
+ s->l1_table_offset, cur_l1_bytes,
345
+ false);
346
if (ret < 0) {
347
goto fail;
348
}
132
diff --git a/block/qcow2.c b/block/qcow2.c
349
diff --git a/block/qcow2.c b/block/qcow2.c
133
index XXXXXXX..XXXXXXX 100644
350
index XXXXXXX..XXXXXXX 100644
134
--- a/block/qcow2.c
351
--- a/block/qcow2.c
135
+++ b/block/qcow2.c
352
+++ b/block/qcow2.c
136
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
353
@@ -XXX,XX +XXX,XX @@ static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen,
137
qdict_put_str(qdict, "file", bs->node_name);
354
/* Zero fill remaining space in cluster so it has predictable
138
355
* content in case of future spec changes */
139
/* Now get the QAPI type BlockdevCreateOptions */
356
clusterlen = size_to_clusters(s, headerlen) * s->cluster_size;
140
- qobj = qdict_crumple(qdict, errp);
357
- assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen) == 0);
141
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
358
+ assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen, false) == 0);
142
qobject_unref(qdict);
359
ret = bdrv_pwrite_zeroes(bs->file,
143
qdict = qobject_to(QDict, qobj);
360
ret + headerlen,
144
if (qdict == NULL) {
361
clusterlen - headerlen, 0);
145
diff --git a/block/qed.c b/block/qed.c
362
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
146
index XXXXXXX..XXXXXXX 100644
363
*/
147
--- a/block/qed.c
364
if (!cluster_data) {
148
+++ b/block/qed.c
365
cluster_data =
149
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
366
- qemu_try_blockalign(bs->file->bs,
150
qdict_put_str(qdict, "driver", "qed");
367
+ qemu_try_blockalign(s->data_file->bs,
151
qdict_put_str(qdict, "file", bs->node_name);
368
QCOW_MAX_CRYPT_CLUSTERS
152
369
* s->cluster_size);
153
- qobj = qdict_crumple(qdict, errp);
370
if (cluster_data == NULL) {
154
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
371
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
155
qobject_unref(qdict);
372
156
qdict = qobject_to(QDict, qobj);
373
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
157
if (qdict == NULL) {
374
qemu_co_mutex_unlock(&s->lock);
158
diff --git a/block/rbd.c b/block/rbd.c
375
- ret = bdrv_co_preadv(bs->file,
159
index XXXXXXX..XXXXXXX 100644
376
+ ret = bdrv_co_preadv(s->data_file,
160
--- a/block/rbd.c
377
cluster_offset + offset_in_cluster,
161
+++ b/block/rbd.c
378
cur_bytes, &hd_qiov, 0);
162
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
379
qemu_co_mutex_lock(&s->lock);
163
}
380
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
164
381
}
165
/* Convert the remaining options into a QAPI object */
382
166
- crumpled = qdict_crumple(options, errp);
383
ret = qcow2_pre_write_overlap_check(bs, 0,
167
+ crumpled = qdict_crumple_for_keyval_qiv(options, errp);
384
- cluster_offset + offset_in_cluster, cur_bytes);
168
if (crumpled == NULL) {
385
+ cluster_offset + offset_in_cluster, cur_bytes, true);
169
r = -EINVAL;
386
if (ret < 0) {
170
goto out;
387
goto fail;
171
diff --git a/block/sheepdog.c b/block/sheepdog.c
388
}
172
index XXXXXXX..XXXXXXX 100644
389
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
173
--- a/block/sheepdog.c
390
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
174
+++ b/block/sheepdog.c
391
trace_qcow2_writev_data(qemu_coroutine_self(),
175
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
392
cluster_offset + offset_in_cluster);
176
}
393
- ret = bdrv_co_pwritev(bs->file,
177
394
+ ret = bdrv_co_pwritev(s->data_file,
178
/* Get the QAPI object */
395
cluster_offset + offset_in_cluster,
179
- crumpled = qdict_crumple(qdict, errp);
396
cur_bytes, &hd_qiov, 0);
180
+ crumpled = qdict_crumple_for_keyval_qiv(qdict, errp);
397
qemu_co_mutex_lock(&s->lock);
181
if (crumpled == NULL) {
398
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
182
ret = -EINVAL;
399
goto out;
183
goto fail;
400
184
diff --git a/block/vhdx.c b/block/vhdx.c
401
case QCOW2_CLUSTER_NORMAL:
185
index XXXXXXX..XXXXXXX 100644
402
- child = bs->file;
186
--- a/block/vhdx.c
403
+ child = s->data_file;
187
+++ b/block/vhdx.c
404
copy_offset += offset_into_cluster(s, src_offset);
188
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
405
if ((copy_offset & 511) != 0) {
189
qdict_put_str(qdict, "driver", "vhdx");
406
ret = -EIO;
190
qdict_put_str(qdict, "file", bs->node_name);
407
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs,
191
408
assert((cluster_offset & 511) == 0);
192
- qobj = qdict_crumple(qdict, errp);
409
193
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
410
ret = qcow2_pre_write_overlap_check(bs, 0,
194
qobject_unref(qdict);
411
- cluster_offset + offset_in_cluster, cur_bytes);
195
qdict = qobject_to(QDict, qobj);
412
+ cluster_offset + offset_in_cluster, cur_bytes, true);
196
if (qdict == NULL) {
413
if (ret < 0) {
197
diff --git a/block/vpc.c b/block/vpc.c
414
goto fail;
198
index XXXXXXX..XXXXXXX 100644
415
}
199
--- a/block/vpc.c
416
200
+++ b/block/vpc.c
417
qemu_co_mutex_unlock(&s->lock);
201
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
418
ret = bdrv_co_copy_range_to(src, src_offset,
202
qdict_put_str(qdict, "driver", "vpc");
419
- bs->file,
203
qdict_put_str(qdict, "file", bs->node_name);
420
+ s->data_file,
204
421
cluster_offset + offset_in_cluster,
205
- qobj = qdict_crumple(qdict, errp);
422
cur_bytes, read_flags, write_flags);
206
+ qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
423
qemu_co_mutex_lock(&s->lock);
207
qobject_unref(qdict);
424
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
208
qdict = qobject_to(QDict, qobj);
425
int64_t old_file_size, new_file_size;
209
if (qdict == NULL) {
426
uint64_t nb_new_data_clusters, nb_new_l2_tables;
210
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
427
211
index XXXXXXX..XXXXXXX 100644
428
+ /* With a data file, preallocation means just allocating the metadata
212
--- a/qobject/block-qdict.c
429
+ * and forwarding the truncate request to the data file */
213
+++ b/qobject/block-qdict.c
430
+ if (has_data_file(bs)) {
214
@@ -XXX,XX +XXX,XX @@
431
+ ret = preallocate_co(bs, old_length, offset);
215
432
+ if (ret < 0) {
216
#include "qemu/osdep.h"
433
+ error_setg_errno(errp, -ret, "Preallocation failed");
217
#include "block/qdict.h"
434
+ goto fail;
218
+#include "qapi/qmp/qbool.h"
435
+ }
219
#include "qapi/qmp/qlist.h"
220
+#include "qapi/qmp/qnum.h"
221
+#include "qapi/qmp/qstring.h"
222
#include "qemu/cutils.h"
223
#include "qapi/error.h"
224
225
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
226
}
227
228
/**
229
+ * qdict_crumple_for_keyval_qiv:
230
+ * @src: the flat dictionary (only scalar values) to crumple
231
+ * @errp: location to store error
232
+ *
233
+ * Like qdict_crumple(), but additionally transforms scalar values so
234
+ * the result can be passed to qobject_input_visitor_new_keyval().
235
+ *
236
+ * The block subsystem uses this function to prepare its flat QDict
237
+ * with possibly confused scalar types for a visit. It should not be
238
+ * used for anything else, and it should go away once the block
239
+ * subsystem has been cleaned up.
240
+ */
241
+QObject *qdict_crumple_for_keyval_qiv(QDict *src, Error **errp)
242
+{
243
+ QDict *tmp = NULL;
244
+ char *buf;
245
+ const char *s;
246
+ const QDictEntry *ent;
247
+ QObject *dst;
248
+
249
+ for (ent = qdict_first(src); ent; ent = qdict_next(src, ent)) {
250
+ buf = NULL;
251
+ switch (qobject_type(ent->value)) {
252
+ case QTYPE_QNULL:
253
+ case QTYPE_QSTRING:
254
+ continue;
255
+ case QTYPE_QNUM:
256
+ s = buf = qnum_to_string(qobject_to(QNum, ent->value));
257
+ break;
436
+ break;
258
+ case QTYPE_QDICT:
259
+ case QTYPE_QLIST:
260
+ /* @src isn't flat; qdict_crumple() will fail */
261
+ continue;
262
+ case QTYPE_QBOOL:
263
+ s = qbool_get_bool(qobject_to(QBool, ent->value))
264
+ ? "on" : "off";
265
+ break;
266
+ default:
267
+ abort();
268
+ }
437
+ }
269
+
438
+
270
+ if (!tmp) {
439
old_file_size = bdrv_getlength(bs->file->bs);
271
+ tmp = qdict_clone_shallow(src);
440
if (old_file_size < 0) {
441
error_setg_errno(errp, -old_file_size,
442
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
443
444
bs->total_sectors = offset / BDRV_SECTOR_SIZE;
445
446
+ if (has_data_file(bs)) {
447
+ if (prealloc == PREALLOC_MODE_METADATA) {
448
+ prealloc = PREALLOC_MODE_OFF;
272
+ }
449
+ }
273
+ qdict_put(tmp, ent->key, qstring_from_str(s));
450
+ ret = bdrv_co_truncate(s->data_file, offset, prealloc, errp);
274
+ g_free(buf);
451
+ if (ret < 0) {
275
+ }
452
+ goto fail;
276
+
453
+ }
277
+ dst = qdict_crumple(tmp ?: src, errp);
454
+ }
278
+ qobject_unref(tmp);
455
+
279
+ return dst;
456
/* write updated header.size */
280
+}
457
offset = cpu_to_be64(offset);
281
+
458
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
282
+/**
459
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
283
* qdict_array_entries(): Returns the number of direct array entries if the
460
uint8_t *buf, *out_buf;
284
* sub-QDict of src specified by the prefix in subqdict (or src itself for
461
uint64_t cluster_offset;
285
* prefix == "") is valid as an array, i.e. the length of the created list if
462
463
+ if (has_data_file(bs)) {
464
+ return -ENOTSUP;
465
+ }
466
+
467
if (bytes == 0) {
468
/* align end of file to a sector boundary to ease reading with
469
sector based I/Os */
470
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
471
goto fail;
472
}
473
474
- ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len);
475
+ ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len, true);
476
qemu_co_mutex_unlock(&s->lock);
477
if (ret < 0) {
478
goto fail;
479
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
480
481
qemu_iovec_init_buf(&hd_qiov, out_buf, out_len);
482
483
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
484
- ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0);
485
+ BLKDBG_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED);
486
+ ret = bdrv_co_pwritev(s->data_file, cluster_offset, out_len, &hd_qiov, 0);
487
if (ret < 0) {
488
goto fail;
489
}
490
@@ -XXX,XX +XXX,XX @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
491
return -ENOTSUP;
492
}
493
494
+ if (has_data_file(bs)) {
495
+ error_setg(errp, "Cannot downgrade an image with a data file");
496
+ return -ENOTSUP;
497
+ }
498
+
499
/* clear incompatible features */
500
if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) {
501
ret = qcow2_mark_clean(bs);
286
--
502
--
287
2.13.6
503
2.20.1
288
504
289
505
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
Internal snapshots and an external data file are incompatible because
2
snapshots require refcounting and non-linear mapping. Return an error
3
for all of the snapshot operations if an external data file is in use.
2
4
3
-blockdev and blockdev-add silently ignore empty objects and arrays in
4
their argument. That's because qmp_blockdev_add() converts the
5
argument to a flat QDict, and qdict_flatten() eats empty QDict and
6
QList members. For instance, we ignore an empty BlockdevOptions
7
member @cache. No real harm, as absent means the same as empty there.
8
9
Thus, the flaw puts an artificial restriction on the QAPI schema: we
10
can't have potentially empty objects and arrays within
11
BlockdevOptions, except when they're optional and "empty" has the same
12
meaning as "absent".
13
14
Our QAPI schema satisfies this restriction (I checked), but it's a
15
trap for the unwary, and a temptation to employ awkward workarounds
16
for the wary. Let's get rid of it.
17
18
Change qdict_flatten() and qdict_crumple() to treat empty dictionaries
19
and lists exactly like scalars.
20
21
Signed-off-by: Markus Armbruster <armbru@redhat.com>
22
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
---
6
---
25
qobject/block-qdict.c | 54 +++++++++++++++++++++++++++++------------------
7
block/qcow2-snapshot.c | 15 +++++++++++++++
26
tests/check-block-qdict.c | 38 ++++++++++++++++++++++++++-------
8
1 file changed, 15 insertions(+)
27
2 files changed, 63 insertions(+), 29 deletions(-)
28
9
29
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
10
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
30
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
31
--- a/qobject/block-qdict.c
12
--- a/block/qcow2-snapshot.c
32
+++ b/qobject/block-qdict.c
13
+++ b/block/qcow2-snapshot.c
33
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
14
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
34
{
15
return -EFBIG;
35
QObject *value;
16
}
36
const QListEntry *entry;
17
37
+ QDict *dict_val;
18
+ if (has_data_file(bs)) {
38
+ QList *list_val;
19
+ return -ENOTSUP;
39
char *new_key;
20
+ }
21
+
22
memset(sn, 0, sizeof(*sn));
23
24
/* Generate an ID */
25
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
26
int ret;
27
uint64_t *sn_l1_table = NULL;
28
29
+ if (has_data_file(bs)) {
30
+ return -ENOTSUP;
31
+ }
32
+
33
/* Search the snapshot */
34
snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
35
if (snapshot_index < 0) {
36
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_delete(BlockDriverState *bs,
37
QCowSnapshot sn;
38
int snapshot_index, ret;
39
40
+ if (has_data_file(bs)) {
41
+ return -ENOTSUP;
42
+ }
43
+
44
/* Search the snapshot */
45
snapshot_index = find_snapshot_by_id_and_name(bs, snapshot_id, name);
46
if (snapshot_index < 0) {
47
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
48
QCowSnapshot *sn;
40
int i;
49
int i;
41
50
42
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
51
+ if (has_data_file(bs)) {
43
52
+ return -ENOTSUP;
44
for (i = 0; entry; entry = qlist_next(entry), i++) {
53
+ }
45
value = qlist_entry_obj(entry);
54
if (!s->nb_snapshots) {
46
+ dict_val = qobject_to(QDict, value);
55
*psn_tab = NULL;
47
+ list_val = qobject_to(QList, value);
56
return s->nb_snapshots;
48
new_key = g_strdup_printf("%s.%i", prefix, i);
49
50
/*
51
* Flatten non-empty QDict and QList recursively into @target,
52
* copy other objects to @target
53
*/
54
- if (qobject_type(value) == QTYPE_QDICT) {
55
- qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
56
- } else if (qobject_type(value) == QTYPE_QLIST) {
57
- qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
58
+ if (dict_val && qdict_size(dict_val)) {
59
+ qdict_flatten_qdict(dict_val, target, new_key);
60
+ } else if (list_val && !qlist_empty(list_val)) {
61
+ qdict_flatten_qlist(list_val, target, new_key);
62
} else {
63
qdict_put_obj(target, new_key, qobject_ref(value));
64
}
65
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
66
{
67
QObject *value;
68
const QDictEntry *entry, *next;
69
+ QDict *dict_val;
70
+ QList *list_val;
71
char *new_key;
72
73
entry = qdict_first(qdict);
74
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
75
while (entry != NULL) {
76
next = qdict_next(qdict, entry);
77
value = qdict_entry_value(entry);
78
+ dict_val = qobject_to(QDict, value);
79
+ list_val = qobject_to(QList, value);
80
new_key = NULL;
81
82
if (prefix) {
83
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
84
* Flatten non-empty QDict and QList recursively into @target,
85
* copy other objects to @target
86
*/
87
- if (qobject_type(value) == QTYPE_QDICT) {
88
- qdict_flatten_qdict(qobject_to(QDict, value), target,
89
+ if (dict_val && qdict_size(dict_val)) {
90
+ qdict_flatten_qdict(dict_val, target,
91
new_key ? new_key : entry->key);
92
qdict_del(qdict, entry->key);
93
- } else if (qobject_type(value) == QTYPE_QLIST) {
94
- qdict_flatten_qlist(qobject_to(QList, value), target,
95
+ } else if (list_val && !qlist_empty(list_val)) {
96
+ qdict_flatten_qlist(list_val, target,
97
new_key ? new_key : entry->key);
98
qdict_del(qdict, entry->key);
99
} else if (target != qdict) {
100
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
101
}
102
103
/**
104
- * qdict_flatten(): For each nested QDict with key x, all fields with key y
105
- * are moved to this QDict and their key is renamed to "x.y". For each nested
106
- * QList with key x, the field at index y is moved to this QDict with the key
107
- * "x.y" (i.e., the reverse of what qdict_array_split() does).
108
+ * qdict_flatten(): For each nested non-empty QDict with key x, all
109
+ * fields with key y are moved to this QDict and their key is renamed
110
+ * to "x.y". For each nested non-empty QList with key x, the field at
111
+ * index y is moved to this QDict with the key "x.y" (i.e., the
112
+ * reverse of what qdict_array_split() does).
113
* This operation is applied recursively for nested QDicts and QLists.
114
*/
115
void qdict_flatten(QDict *qdict)
116
@@ -XXX,XX +XXX,XX @@ static int qdict_is_list(QDict *maybe_list, Error **errp)
117
* @src: the original flat dictionary (only scalar values) to crumple
118
*
119
* Takes a flat dictionary whose keys use '.' separator to indicate
120
- * nesting, and values are scalars, and crumples it into a nested
121
- * structure.
122
+ * nesting, and values are scalars, empty dictionaries or empty lists,
123
+ * and crumples it into a nested structure.
124
*
125
* To include a literal '.' in a key name, it must be escaped as '..'
126
*
127
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
128
{
129
const QDictEntry *ent;
130
QDict *two_level, *multi_level = NULL, *child_dict;
131
+ QDict *dict_val;
132
+ QList *list_val;
133
QObject *dst = NULL, *child;
134
size_t i;
135
char *prefix = NULL;
136
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
137
138
/* Step 1: split our totally flat dict into a two level dict */
139
for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) {
140
- if (qobject_type(ent->value) == QTYPE_QDICT ||
141
- qobject_type(ent->value) == QTYPE_QLIST) {
142
- error_setg(errp, "Value %s is not a scalar",
143
- ent->key);
144
+ dict_val = qobject_to(QDict, ent->value);
145
+ list_val = qobject_to(QList, ent->value);
146
+ if ((dict_val && qdict_size(dict_val))
147
+ || (list_val && !qlist_empty(list_val))) {
148
+ error_setg(errp, "Value %s is not flat", ent->key);
149
goto error;
150
}
151
152
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
153
multi_level = qdict_new();
154
for (ent = qdict_first(two_level); ent != NULL;
155
ent = qdict_next(two_level, ent)) {
156
- QDict *dict = qobject_to(QDict, ent->value);
157
- if (dict) {
158
- child = qdict_crumple(dict, errp);
159
+ dict_val = qobject_to(QDict, ent->value);
160
+ if (dict_val && qdict_size(dict_val)) {
161
+ child = qdict_crumple(dict_val, errp);
162
if (!child) {
163
goto error;
164
}
165
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/tests/check-block-qdict.c
168
+++ b/tests/check-block-qdict.c
169
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
170
* "e.1.2.b": 1,
171
* "f.c": 2,
172
* "f.d": 3,
173
- * "g": 4
174
+ * "g": 4,
175
+ * "y.0": {},
176
+ * "z.a": []
177
* }
178
- *
179
- * Note that "y" and "z" get eaten.
180
*/
181
182
qdict_put_int(e_1_2, "a", 0);
183
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_test(void)
184
g_assert(qdict_get_int(root, "f.c") == 2);
185
g_assert(qdict_get_int(root, "f.d") == 3);
186
g_assert(qdict_get_int(root, "g") == 4);
187
+ g_assert(!qdict_size(qdict_get_qdict(root, "y.0")));
188
+ g_assert(qlist_empty(qdict_get_qlist(root, "z.a")));
189
190
- g_assert(qdict_size(root) == 8);
191
+ g_assert(qdict_size(root) == 10);
192
193
qobject_unref(root);
194
}
195
@@ -XXX,XX +XXX,XX @@ static void qdict_join_test(void)
196
static void qdict_crumple_test_recursive(void)
197
{
198
QDict *src, *dst, *rule, *vnc, *acl, *listen;
199
- QList *rules;
200
+ QDict *empty, *empty_dict, *empty_list_0;
201
+ QList *rules, *empty_list, *empty_dict_a;
202
203
src = qdict_new();
204
qdict_put_str(src, "vnc.listen.addr", "127.0.0.1");
205
@@ -XXX,XX +XXX,XX @@ static void qdict_crumple_test_recursive(void)
206
qdict_put_str(src, "vnc.acl.default", "deny");
207
qdict_put_str(src, "vnc.acl..name", "acl0");
208
qdict_put_str(src, "vnc.acl.rule..name", "acl0");
209
+ qdict_put(src, "empty.dict.a", qlist_new());
210
+ qdict_put(src, "empty.list.0", qdict_new());
211
212
dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
213
g_assert(dst);
214
- g_assert_cmpint(qdict_size(dst), ==, 1);
215
+ g_assert_cmpint(qdict_size(dst), ==, 2);
216
217
vnc = qdict_get_qdict(dst, "vnc");
218
g_assert(vnc);
219
@@ -XXX,XX +XXX,XX @@ static void qdict_crumple_test_recursive(void)
220
g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name"));
221
g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name"));
222
223
+ empty = qdict_get_qdict(dst, "empty");
224
+ g_assert(empty);
225
+ g_assert_cmpint(qdict_size(empty), ==, 2);
226
+ empty_dict = qdict_get_qdict(empty, "dict");
227
+ g_assert(empty_dict);
228
+ g_assert_cmpint(qdict_size(empty_dict), ==, 1);
229
+ empty_dict_a = qdict_get_qlist(empty_dict, "a");
230
+ g_assert(empty_dict_a && qlist_empty(empty_dict_a));
231
+ empty_list = qdict_get_qlist(empty, "list");
232
+ g_assert(empty_list);
233
+ g_assert_cmpint(qlist_size(empty_list), ==, 1);
234
+ empty_list_0 = qobject_to(QDict, qlist_pop(empty_list));
235
+ g_assert(empty_list_0);
236
+ g_assert_cmpint(qdict_size(empty_list_0), ==, 0);
237
+
238
qobject_unref(src);
239
qobject_unref(dst);
240
}
241
@@ -XXX,XX +XXX,XX @@ static void qdict_rename_keys_test(void)
242
243
static void qdict_crumple_test_bad_inputs(void)
244
{
245
- QDict *src;
246
+ QDict *src, *nested;
247
Error *error = NULL;
248
249
src = qdict_new();
250
@@ -XXX,XX +XXX,XX @@ static void qdict_crumple_test_bad_inputs(void)
251
252
src = qdict_new();
253
/* The input should be flat, ie no dicts or lists */
254
- qdict_put(src, "rule.a", qdict_new());
255
+ nested = qdict_new();
256
+ qdict_put(nested, "x", qdict_new());
257
+ qdict_put(src, "rule.a", nested);
258
qdict_put_str(src, "rule.b", "allow");
259
260
g_assert(qdict_crumple(src, &error) == NULL);
261
--
57
--
262
2.13.6
58
2.20.1
263
59
264
60
diff view generated by jsdifflib
1
We removed all options from the 'deprecated' array, so the code is dead
1
For external data files, data clusters must be excluded from the
2
and can be removed as well.
2
refcount calculations. Instead, an implicit refcount of 1 is assumed for
3
the COPIED flag.
4
5
Compressed clusters and internal snapshots are incompatible with
6
external data files, so print an error if they are in use for images
7
with an external data file.
3
8
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Markus Armbruster <armbru@redhat.com>
6
---
10
---
7
blockdev.c | 12 ------------
11
block/qcow2-refcount.c | 41 ++++++++++++++++++++++++++++++-----------
8
1 file changed, 12 deletions(-)
12
1 file changed, 30 insertions(+), 11 deletions(-)
9
13
10
diff --git a/blockdev.c b/blockdev.c
14
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
11
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
12
--- a/blockdev.c
16
--- a/block/qcow2-refcount.c
13
+++ b/blockdev.c
17
+++ b/block/qcow2-refcount.c
14
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
18
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
15
const char *filename;
19
res->corruptions++;
16
Error *local_err = NULL;
20
}
17
int i;
21
18
- const char *deprecated[] = {
22
+ if (has_data_file(bs)) {
19
- };
23
+ fprintf(stderr, "ERROR compressed cluster %d with data file, "
20
24
+ "entry=0x%" PRIx64 "\n", i, l2_entry);
21
/* Change legacy command line options into QMP ones */
25
+ res->corruptions++;
22
static const struct {
26
+ break;
23
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
27
+ }
24
goto fail;
28
+
29
/* Mark cluster as used */
30
nb_csectors = ((l2_entry >> s->csize_shift) &
31
s->csize_mask) + 1;
32
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
33
}
34
35
/* Mark cluster as used */
36
- ret = qcow2_inc_refcounts_imrt(bs, res,
37
- refcount_table, refcount_table_size,
38
- offset, s->cluster_size);
39
- if (ret < 0) {
40
- goto fail;
41
+ if (!has_data_file(bs)) {
42
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table,
43
+ refcount_table_size,
44
+ offset, s->cluster_size);
45
+ if (ret < 0) {
46
+ goto fail;
47
+ }
48
}
49
break;
50
}
51
@@ -XXX,XX +XXX,XX @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
52
53
if (cluster_type == QCOW2_CLUSTER_NORMAL ||
54
cluster_type == QCOW2_CLUSTER_ZERO_ALLOC) {
55
- ret = qcow2_get_refcount(bs,
56
- data_offset >> s->cluster_bits,
57
- &refcount);
58
- if (ret < 0) {
59
- /* don't print message nor increment check_errors */
60
- continue;
61
+ if (has_data_file(bs)) {
62
+ refcount = 1;
63
+ } else {
64
+ ret = qcow2_get_refcount(bs,
65
+ data_offset >> s->cluster_bits,
66
+ &refcount);
67
+ if (ret < 0) {
68
+ /* don't print message nor increment check_errors */
69
+ continue;
70
+ }
71
}
72
if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) {
73
fprintf(stderr, "%s OFLAG_COPIED data cluster: "
74
@@ -XXX,XX +XXX,XX @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
25
}
75
}
26
76
27
- /* Other deprecated options */
77
/* snapshots */
28
- if (!qtest_enabled()) {
78
+ if (has_data_file(bs) && s->nb_snapshots) {
29
- for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
79
+ fprintf(stderr, "ERROR %d snapshots in image with data file\n",
30
- if (qemu_opt_get(legacy_opts, deprecated[i]) != NULL) {
80
+ s->nb_snapshots);
31
- error_report("'%s' is deprecated, please use the corresponding "
81
+ res->corruptions++;
32
- "option of '-device' instead", deprecated[i]);
82
+ }
33
- }
83
+
34
- }
84
for (i = 0; i < s->nb_snapshots; i++) {
35
- }
85
sn = s->snapshots + i;
36
-
86
if (offset_into_cluster(s, sn->l1_table_offset)) {
37
/* Media type */
38
value = qemu_opt_get(legacy_opts, "media");
39
if (value) {
40
--
87
--
41
2.13.6
88
2.20.1
42
89
43
90
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
This adds a .bdrv_open option to specify the external data file node.
2
2
3
Signed-off-by: Markus Armbruster <armbru@redhat.com>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
4
---
7
include/block/qdict.h | 3 ++-
5
qapi/block-core.json | 7 ++++++-
8
block/nbd.c | 7 ++-----
6
block/qcow2.h | 4 +++-
9
block/nfs.c | 7 ++-----
7
block/qcow2.c | 34 ++++++++++++++++++++++++++++++++--
10
block/parallels.c | 7 ++-----
8
3 files changed, 41 insertions(+), 4 deletions(-)
11
block/qcow.c | 7 ++-----
12
block/qcow2.c | 7 ++-----
13
block/qed.c | 7 ++-----
14
block/rbd.c | 7 ++-----
15
block/sheepdog.c | 14 ++++----------
16
block/ssh.c | 7 ++-----
17
block/vhdx.c | 7 ++-----
18
block/vpc.c | 7 ++-----
19
qobject/block-qdict.c | 28 +++++++++++++++++++++++++++-
20
13 files changed, 53 insertions(+), 62 deletions(-)
21
9
22
diff --git a/include/block/qdict.h b/include/block/qdict.h
10
diff --git a/qapi/block-core.json b/qapi/block-core.json
23
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
24
--- a/include/block/qdict.h
12
--- a/qapi/block-core.json
25
+++ b/include/block/qdict.h
13
+++ b/qapi/block-core.json
26
@@ -XXX,XX +XXX,XX @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
14
@@ -XXX,XX +XXX,XX @@
27
void qdict_array_split(QDict *src, QList **dst);
15
# encrypted images, except when doing a metadata-only
28
int qdict_array_entries(QDict *src, const char *subqdict);
16
# probe of the image. (since 2.10)
29
QObject *qdict_crumple(const QDict *src, Error **errp);
17
#
30
-QObject *qdict_crumple_for_keyval_qiv(QDict *qdict, Error **errp);
18
+# @data-file: reference to or definition of the external data file.
31
void qdict_flatten(QDict *qdict);
19
+# This may only be specified for images that require an
32
20
+# external data file. (since 4.0)
33
typedef struct QDictRenames {
21
+#
34
@@ -XXX,XX +XXX,XX @@ typedef struct QDictRenames {
22
# Since: 2.9
35
} QDictRenames;
23
##
36
bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
24
{ 'struct': 'BlockdevOptionsQcow2',
37
25
@@ -XXX,XX +XXX,XX @@
38
+Visitor *qobject_input_visitor_new_flat_confused(QDict *qdict,
26
'*l2-cache-entry-size': 'int',
39
+ Error **errp);
27
'*refcount-cache-size': 'int',
40
#endif
28
'*cache-clean-interval': 'int',
41
diff --git a/block/nbd.c b/block/nbd.c
29
- '*encrypt': 'BlockdevQcow2Encryption' } }
30
+ '*encrypt': 'BlockdevQcow2Encryption',
31
+ '*data-file': 'BlockdevRef' } }
32
33
##
34
# @SshHostKeyCheckMode:
35
diff --git a/block/qcow2.h b/block/qcow2.h
42
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
43
--- a/block/nbd.c
37
--- a/block/qcow2.h
44
+++ b/block/nbd.c
38
+++ b/block/qcow2.h
45
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
39
@@ -XXX,XX +XXX,XX @@
46
{
40
47
SocketAddress *saddr = NULL;
41
#define DEFAULT_CLUSTER_SIZE 65536
48
QDict *addr = NULL;
42
49
- QObject *crumpled_addr = NULL;
43
+#define QCOW2_OPT_DATA_FILE "data-file"
50
Visitor *iv = NULL;
44
#define QCOW2_OPT_LAZY_REFCOUNTS "lazy-refcounts"
51
Error *local_err = NULL;
45
#define QCOW2_OPT_DISCARD_REQUEST "pass-discard-request"
52
46
#define QCOW2_OPT_DISCARD_SNAPSHOT "pass-discard-snapshot"
53
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
47
@@ -XXX,XX +XXX,XX @@ enum {
54
goto done;
48
QCOW2_INCOMPAT_DATA_FILE = 1 << QCOW2_INCOMPAT_DATA_FILE_BITNR,
55
}
49
56
50
QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY
57
- crumpled_addr = qdict_crumple_for_keyval_qiv(addr, errp);
51
- | QCOW2_INCOMPAT_CORRUPT,
58
- if (!crumpled_addr) {
52
+ | QCOW2_INCOMPAT_CORRUPT
59
+ iv = qobject_input_visitor_new_flat_confused(addr, errp);
53
+ | QCOW2_INCOMPAT_DATA_FILE,
60
+ if (!iv) {
54
};
61
goto done;
55
62
}
56
/* Compatible feature bits */
63
64
- iv = qobject_input_visitor_new_keyval(crumpled_addr);
65
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
66
if (local_err) {
67
error_propagate(errp, local_err);
68
@@ -XXX,XX +XXX,XX @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
69
70
done:
71
qobject_unref(addr);
72
- qobject_unref(crumpled_addr);
73
visit_free(iv);
74
return saddr;
75
}
76
diff --git a/block/nfs.c b/block/nfs.c
77
index XXXXXXX..XXXXXXX 100644
78
--- a/block/nfs.c
79
+++ b/block/nfs.c
80
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
81
Error **errp)
82
{
83
BlockdevOptionsNfs *opts = NULL;
84
- QObject *crumpled = NULL;
85
Visitor *v;
86
const QDictEntry *e;
87
Error *local_err = NULL;
88
89
- crumpled = qdict_crumple_for_keyval_qiv(options, errp);
90
- if (crumpled == NULL) {
91
+ v = qobject_input_visitor_new_flat_confused(options, errp);
92
+ if (!v) {
93
return NULL;
94
}
95
96
- v = qobject_input_visitor_new_keyval(crumpled);
97
visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
98
visit_free(v);
99
- qobject_unref(crumpled);
100
101
if (local_err) {
102
error_propagate(errp, local_err);
103
diff --git a/block/parallels.c b/block/parallels.c
104
index XXXXXXX..XXXXXXX 100644
105
--- a/block/parallels.c
106
+++ b/block/parallels.c
107
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
108
Error *local_err = NULL;
109
BlockDriverState *bs = NULL;
110
QDict *qdict;
111
- QObject *qobj;
112
Visitor *v;
113
int ret;
114
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
116
qdict_put_str(qdict, "driver", "parallels");
117
qdict_put_str(qdict, "file", bs->node_name);
118
119
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
120
- if (!qobj) {
121
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
122
+ if (!v) {
123
ret = -EINVAL;
124
goto done;
125
}
126
127
- v = qobject_input_visitor_new_keyval(qobj);
128
- qobject_unref(qobj);
129
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
130
visit_free(v);
131
132
diff --git a/block/qcow.c b/block/qcow.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/block/qcow.c
135
+++ b/block/qcow.c
136
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
137
BlockdevCreateOptions *create_options = NULL;
138
BlockDriverState *bs = NULL;
139
QDict *qdict;
140
- QObject *qobj;
141
Visitor *v;
142
const char *val;
143
Error *local_err = NULL;
144
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename,
145
qdict_put_str(qdict, "driver", "qcow");
146
qdict_put_str(qdict, "file", bs->node_name);
147
148
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
149
- if (!qobj) {
150
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
151
+ if (!v) {
152
ret = -EINVAL;
153
goto fail;
154
}
155
156
- v = qobject_input_visitor_new_keyval(qobj);
157
- qobject_unref(qobj);
158
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
159
visit_free(v);
160
161
diff --git a/block/qcow2.c b/block/qcow2.c
57
diff --git a/block/qcow2.c b/block/qcow2.c
162
index XXXXXXX..XXXXXXX 100644
58
index XXXXXXX..XXXXXXX 100644
163
--- a/block/qcow2.c
59
--- a/block/qcow2.c
164
+++ b/block/qcow2.c
60
+++ b/block/qcow2.c
165
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
61
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
166
{
167
BlockdevCreateOptions *create_options = NULL;
168
QDict *qdict;
169
- QObject *qobj;
170
Visitor *v;
171
BlockDriverState *bs = NULL;
172
Error *local_err = NULL;
173
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
174
qdict_put_str(qdict, "file", bs->node_name);
175
176
/* Now get the QAPI type BlockdevCreateOptions */
177
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
178
- if (!qobj) {
179
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
180
+ if (!v) {
181
ret = -EINVAL;
182
goto finish;
183
}
184
185
- v = qobject_input_visitor_new_keyval(qobj);
186
- qobject_unref(qobj);
187
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
188
visit_free(v);
189
190
diff --git a/block/qed.c b/block/qed.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/block/qed.c
193
+++ b/block/qed.c
194
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
195
{
196
BlockdevCreateOptions *create_options = NULL;
197
QDict *qdict;
198
- QObject *qobj;
199
Visitor *v;
200
BlockDriverState *bs = NULL;
201
Error *local_err = NULL;
202
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
203
qdict_put_str(qdict, "driver", "qed");
204
qdict_put_str(qdict, "file", bs->node_name);
205
206
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
207
- if (!qobj) {
208
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
209
+ if (!v) {
210
ret = -EINVAL;
211
goto fail;
62
goto fail;
212
}
63
}
213
64
214
- v = qobject_input_visitor_new_keyval(qobj);
65
- /* TODO Open external data file */
215
- qobject_unref(qobj);
66
- s->data_file = bs->file;
216
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
67
+ /* Open external data file */
217
visit_free(v);
68
+ s->data_file = bdrv_open_child(NULL, options, "data-file", bs, &child_file,
218
69
+ true, &local_err);
219
diff --git a/block/rbd.c b/block/rbd.c
70
+ if (local_err) {
220
index XXXXXXX..XXXXXXX 100644
71
+ error_propagate(errp, local_err);
221
--- a/block/rbd.c
72
+ ret = -EINVAL;
222
+++ b/block/rbd.c
73
+ goto fail;
223
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
224
BDRVRBDState *s = bs->opaque;
225
BlockdevOptionsRbd *opts = NULL;
226
Visitor *v;
227
- QObject *crumpled = NULL;
228
const QDictEntry *e;
229
Error *local_err = NULL;
230
char *keypairs, *secretid;
231
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
232
}
233
234
/* Convert the remaining options into a QAPI object */
235
- crumpled = qdict_crumple_for_keyval_qiv(options, errp);
236
- if (crumpled == NULL) {
237
+ v = qobject_input_visitor_new_flat_confused(options, errp);
238
+ if (!v) {
239
r = -EINVAL;
240
goto out;
241
}
242
243
- v = qobject_input_visitor_new_keyval(crumpled);
244
visit_type_BlockdevOptionsRbd(v, NULL, &opts, &local_err);
245
visit_free(v);
246
- qobject_unref(crumpled);
247
248
if (local_err) {
249
error_propagate(errp, local_err);
250
diff --git a/block/sheepdog.c b/block/sheepdog.c
251
index XXXXXXX..XXXXXXX 100644
252
--- a/block/sheepdog.c
253
+++ b/block/sheepdog.c
254
@@ -XXX,XX +XXX,XX @@ static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s,
255
static SocketAddress *sd_server_config(QDict *options, Error **errp)
256
{
257
QDict *server = NULL;
258
- QObject *crumpled_server = NULL;
259
Visitor *iv = NULL;
260
SocketAddress *saddr = NULL;
261
Error *local_err = NULL;
262
263
qdict_extract_subqdict(options, &server, "server.");
264
265
- crumpled_server = qdict_crumple_for_keyval_qiv(server, errp);
266
- if (!crumpled_server) {
267
+ iv = qobject_input_visitor_new_flat_confused(server, errp);
268
+ if (!iv) {
269
goto done;
270
}
271
272
- iv = qobject_input_visitor_new_keyval(crumpled_server);
273
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
274
if (local_err) {
275
error_propagate(errp, local_err);
276
@@ -XXX,XX +XXX,XX @@ static SocketAddress *sd_server_config(QDict *options, Error **errp)
277
278
done:
279
visit_free(iv);
280
- qobject_unref(crumpled_server);
281
qobject_unref(server);
282
return saddr;
283
}
284
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
285
{
286
BlockdevCreateOptions *create_options = NULL;
287
QDict *qdict, *location_qdict;
288
- QObject *crumpled;
289
Visitor *v;
290
char *redundancy;
291
Error *local_err = NULL;
292
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
293
}
294
295
/* Get the QAPI object */
296
- crumpled = qdict_crumple_for_keyval_qiv(qdict, errp);
297
- if (crumpled == NULL) {
298
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
299
+ if (!v) {
300
ret = -EINVAL;
301
goto fail;
302
}
303
304
- v = qobject_input_visitor_new_keyval(crumpled);
305
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
306
visit_free(v);
307
- qobject_unref(crumpled);
308
309
if (local_err) {
310
error_propagate(errp, local_err);
311
diff --git a/block/ssh.c b/block/ssh.c
312
index XXXXXXX..XXXXXXX 100644
313
--- a/block/ssh.c
314
+++ b/block/ssh.c
315
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
316
BlockdevOptionsSsh *result = NULL;
317
QemuOpts *opts = NULL;
318
Error *local_err = NULL;
319
- QObject *crumpled;
320
const QDictEntry *e;
321
Visitor *v;
322
323
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
324
}
325
326
/* Create the QAPI object */
327
- crumpled = qdict_crumple_for_keyval_qiv(options, errp);
328
- if (crumpled == NULL) {
329
+ v = qobject_input_visitor_new_flat_confused(options, errp);
330
+ if (!v) {
331
goto fail;
332
}
333
334
- v = qobject_input_visitor_new_keyval(crumpled);
335
visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err);
336
visit_free(v);
337
- qobject_unref(crumpled);
338
339
if (local_err) {
340
error_propagate(errp, local_err);
341
diff --git a/block/vhdx.c b/block/vhdx.c
342
index XXXXXXX..XXXXXXX 100644
343
--- a/block/vhdx.c
344
+++ b/block/vhdx.c
345
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
346
{
347
BlockdevCreateOptions *create_options = NULL;
348
QDict *qdict;
349
- QObject *qobj;
350
Visitor *v;
351
BlockDriverState *bs = NULL;
352
Error *local_err = NULL;
353
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename,
354
qdict_put_str(qdict, "driver", "vhdx");
355
qdict_put_str(qdict, "file", bs->node_name);
356
357
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
358
- if (!qobj) {
359
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
360
+ if (!v) {
361
ret = -EINVAL;
362
goto fail;
363
}
364
365
- v = qobject_input_visitor_new_keyval(qobj);
366
- qobject_unref(qobj);
367
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
368
visit_free(v);
369
370
diff --git a/block/vpc.c b/block/vpc.c
371
index XXXXXXX..XXXXXXX 100644
372
--- a/block/vpc.c
373
+++ b/block/vpc.c
374
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
375
{
376
BlockdevCreateOptions *create_options = NULL;
377
QDict *qdict;
378
- QObject *qobj;
379
Visitor *v;
380
BlockDriverState *bs = NULL;
381
Error *local_err = NULL;
382
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
383
qdict_put_str(qdict, "driver", "vpc");
384
qdict_put_str(qdict, "file", bs->node_name);
385
386
- qobj = qdict_crumple_for_keyval_qiv(qdict, errp);
387
- if (!qobj) {
388
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
389
+ if (!v) {
390
ret = -EINVAL;
391
goto fail;
392
}
393
394
- v = qobject_input_visitor_new_keyval(qobj);
395
- qobject_unref(qobj);
396
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
397
visit_free(v);
398
399
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
400
index XXXXXXX..XXXXXXX 100644
401
--- a/qobject/block-qdict.c
402
+++ b/qobject/block-qdict.c
403
@@ -XXX,XX +XXX,XX @@
404
#include "qapi/qmp/qlist.h"
405
#include "qapi/qmp/qnum.h"
406
#include "qapi/qmp/qstring.h"
407
+#include "qapi/qobject-input-visitor.h"
408
#include "qemu/cutils.h"
409
#include "qapi/error.h"
410
411
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp)
412
* used for anything else, and it should go away once the block
413
* subsystem has been cleaned up.
414
*/
415
-QObject *qdict_crumple_for_keyval_qiv(QDict *src, Error **errp)
416
+static QObject *qdict_crumple_for_keyval_qiv(QDict *src, Error **errp)
417
{
418
QDict *tmp = NULL;
419
char *buf;
420
@@ -XXX,XX +XXX,XX @@ bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
421
}
422
return true;
423
}
424
+
425
+/*
426
+ * Create a QObject input visitor for flat @qdict with possibly
427
+ * confused scalar types.
428
+ *
429
+ * The block subsystem uses this function to visit its flat QDict with
430
+ * possibly confused scalar types. It should not be used for anything
431
+ * else, and it should go away once the block subsystem has been
432
+ * cleaned up.
433
+ */
434
+Visitor *qobject_input_visitor_new_flat_confused(QDict *qdict,
435
+ Error **errp)
436
+{
437
+ QObject *crumpled;
438
+ Visitor *v;
439
+
440
+ crumpled = qdict_crumple_for_keyval_qiv(qdict, errp);
441
+ if (!crumpled) {
442
+ return NULL;
443
+ }
74
+ }
444
+
75
+
445
+ v = qobject_input_visitor_new_keyval(crumpled);
76
+ if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
446
+ qobject_unref(crumpled);
77
+ if (!s->data_file) {
447
+ return v;
78
+ error_setg(errp, "'data-file' is required for this image");
448
+}
79
+ ret = -EINVAL;
80
+ goto fail;
81
+ }
82
+ } else {
83
+ if (s->data_file) {
84
+ error_setg(errp, "'data-file' can only be set for images with an "
85
+ "external data file");
86
+ ret = -EINVAL;
87
+ goto fail;
88
+ } else {
89
+ s->data_file = bs->file;
90
+ }
91
+ }
92
93
/* qcow2_read_extension may have set up the crypto context
94
* if the crypt method needs a header region, some methods
95
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
96
return ret;
97
98
fail:
99
+ if (has_data_file(bs)) {
100
+ bdrv_unref_child(bs, s->data_file);
101
+ }
102
g_free(s->unknown_header_fields);
103
cleanup_unknown_header_ext(bs);
104
qcow2_free_snapshots(bs);
105
@@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs)
106
g_free(s->image_backing_file);
107
g_free(s->image_backing_format);
108
109
+ if (has_data_file(bs)) {
110
+ bdrv_unref_child(bs, s->data_file);
111
+ }
112
+
113
qcow2_refcount_close(bs);
114
qcow2_free_snapshots(bs);
115
}
449
--
116
--
450
2.13.6
117
2.20.1
451
118
452
119
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
This adds a .bdrv_create option to use an external data file.
2
2
3
Parameter auth-client-required lets you configure authentication
4
methods. We tried to provide that in v2.9.0, but backed out due to
5
interface design doubts (commit 464444fcc16).
6
7
This commit is similar to what we backed out, but simpler: we use a
8
list of enumeration values instead of a list of objects with a member
9
of enumeration type.
10
11
Let's review our reasons for backing out the first try, as stated in
12
the commit message:
13
14
* The implementation uses deprecated rados_conf_set() key
15
"auth_supported". No biggie.
16
17
Fixed: we use "auth-client-required".
18
19
* The implementation makes -drive silently ignore invalid parameters
20
"auth" and "auth-supported.*.X" where X isn't "auth". Fixable (in
21
fact I'm going to fix similar bugs around parameter server), so
22
again no biggie.
23
24
That fix is commit 2836284db60. This commit doesn't bring the bugs
25
back.
26
27
* BlockdevOptionsRbd member @password-secret applies only to
28
authentication method cephx. Should it be a variant member of
29
RbdAuthMethod?
30
31
We've had time to ponder, and we decided to stick to the way Ceph
32
configuration works: the key configured separately, and silently
33
ignored if the authentication method doesn't use it.
34
35
* BlockdevOptionsRbd member @user could apply to both methods cephx
36
and none, but I'm not sure it's actually used with none. If it
37
isn't, should it be a variant member of RbdAuthMethod?
38
39
Likewise.
40
41
* The client offers a *set* of authentication methods, not a list.
42
Should the methods be optional members of BlockdevOptionsRbd instead
43
of members of list @auth-supported? The latter begs the question
44
what multiple entries for the same method mean. Trivial question
45
now that RbdAuthMethod contains nothing but @type, but less so when
46
RbdAuthMethod acquires other members, such the ones discussed above.
47
48
Again, we decided to stick to the way Ceph configuration works, except
49
we make auth-client-required a list of enumeration values instead of a
50
string containing keywords separated by delimiters.
51
52
* How BlockdevOptionsRbd member @auth-supported interacts with
53
settings from a configuration file specified with @conf is
54
undocumented. I suspect it's untested, too.
55
56
Not actually true, the documentation for @conf says "Values in the
57
configuration file will be overridden by options specified via QAPI",
58
and we've tested this.
59
60
Signed-off-by: Markus Armbruster <armbru@redhat.com>
61
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
62
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
63
---
4
---
64
qapi/block-core.json | 13 +++++++++++++
5
qapi/block-core.json | 4 ++++
65
block/rbd.c | 42 ++++++++++++++++++++++++++++++++----------
6
include/block/block_int.h | 1 +
66
2 files changed, 45 insertions(+), 10 deletions(-)
7
block/qcow2.c | 26 ++++++++++++++++++++++++++
8
3 files changed, 31 insertions(+)
67
9
68
diff --git a/qapi/block-core.json b/qapi/block-core.json
10
diff --git a/qapi/block-core.json b/qapi/block-core.json
69
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
70
--- a/qapi/block-core.json
12
--- a/qapi/block-core.json
71
+++ b/qapi/block-core.json
13
+++ b/qapi/block-core.json
72
@@ -XXX,XX +XXX,XX @@
14
@@ -XXX,XX +XXX,XX @@
73
15
# Driver specific image creation options for qcow2.
74
16
#
17
# @file Node to create the image format on
18
+# @data-file Node to use as an external data file in which all guest
19
+# data is stored so that only metadata remains in the qcow2
20
+# file (since: 4.0)
21
# @size Size of the virtual disk in bytes
22
# @version Compatibility level (default: v3)
23
# @backing-file File name of the backing file if a backing file
24
@@ -XXX,XX +XXX,XX @@
75
##
25
##
76
+# @RbdAuthMode:
26
{ 'struct': 'BlockdevCreateOptionsQcow2',
77
+#
27
'data': { 'file': 'BlockdevRef',
78
+# Since: 3.0
28
+ '*data-file': 'BlockdevRef',
79
+##
29
'size': 'size',
80
+{ 'enum': 'RbdAuthMode',
30
'*version': 'BlockdevQcow2Version',
81
+ 'data': [ 'cephx', 'none' ] }
31
'*backing-file': 'str',
82
+
32
diff --git a/include/block/block_int.h b/include/block/block_int.h
83
+##
33
index XXXXXXX..XXXXXXX 100644
84
# @BlockdevOptionsRbd:
34
--- a/include/block/block_int.h
85
#
35
+++ b/include/block/block_int.h
86
# @pool: Ceph pool name.
87
@@ -XXX,XX +XXX,XX @@
36
@@ -XXX,XX +XXX,XX @@
88
#
37
#define BLOCK_OPT_NOCOW "nocow"
89
# @user: Ceph id name.
38
#define BLOCK_OPT_OBJECT_SIZE "object_size"
90
#
39
#define BLOCK_OPT_REFCOUNT_BITS "refcount_bits"
91
+# @auth-client-required: Acceptable authentication modes.
40
+#define BLOCK_OPT_DATA_FILE "data_file"
92
+# This maps to Ceph configuration option
41
93
+# "auth_client_required". (Since 3.0)
42
#define BLOCK_PROBE_BUF_SIZE 512
94
+#
43
95
# @server: Monitor host address and port. This maps
44
diff --git a/block/qcow2.c b/block/qcow2.c
96
# to the "mon_host" Ceph option.
97
#
98
@@ -XXX,XX +XXX,XX @@
99
'*conf': 'str',
100
'*snapshot': 'str',
101
'*user': 'str',
102
+ '*auth-client-required': ['RbdAuthMode'],
103
'*server': ['InetSocketAddressBase'] } }
104
105
##
106
diff --git a/block/rbd.c b/block/rbd.c
107
index XXXXXXX..XXXXXXX 100644
45
index XXXXXXX..XXXXXXX 100644
108
--- a/block/rbd.c
46
--- a/block/qcow2.c
109
+++ b/block/rbd.c
47
+++ b/block/qcow2.c
110
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_refresh_limits(BlockDriverState *bs, Error **errp)
48
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
111
49
*/
112
50
BlockBackend *blk = NULL;
113
static int qemu_rbd_set_auth(rados_t cluster, const char *secretid,
51
BlockDriverState *bs = NULL;
114
+ BlockdevOptionsRbd *opts,
52
+ BlockDriverState *data_bs = NULL;
115
Error **errp)
53
QCowHeader *header;
116
{
54
size_t cluster_size;
117
- if (secretid == 0) {
55
int version;
118
- return 0;
56
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
119
- }
57
}
120
+ char *acr;
58
refcount_order = ctz32(qcow2_opts->refcount_bits);
121
+ int r;
59
122
+ GString *accu;
60
+ if (qcow2_opts->data_file) {
123
+ RbdAuthModeList *auth;
61
+ if (version < 3) {
124
+
62
+ error_setg(errp, "External data files are only supported with "
125
+ if (secretid) {
63
+ "compatibility level 1.1 and above (use version=v3 or "
126
+ gchar *secret = qcrypto_secret_lookup_as_base64(secretid,
64
+ "greater)");
127
+ errp);
65
+ ret = -EINVAL;
128
+ if (!secret) {
66
+ goto out;
129
+ return -1;
130
+ }
67
+ }
131
68
+ data_bs = bdrv_open_blockdev_ref(qcow2_opts->data_file, errp);
132
- gchar *secret = qcrypto_secret_lookup_as_base64(secretid,
69
+ if (bs == NULL) {
133
- errp);
70
+ ret = -EIO;
134
- if (!secret) {
71
+ goto out;
135
- return -1;
136
+ rados_conf_set(cluster, "key", secret);
137
+ g_free(secret);
138
}
139
140
- rados_conf_set(cluster, "key", secret);
141
- g_free(secret);
142
+ if (opts->has_auth_client_required) {
143
+ accu = g_string_new("");
144
+ for (auth = opts->auth_client_required; auth; auth = auth->next) {
145
+ if (accu->str[0]) {
146
+ g_string_append_c(accu, ';');
147
+ }
148
+ g_string_append(accu, RbdAuthMode_str(auth->value));
149
+ }
150
+ acr = g_string_free(accu, FALSE);
151
+ r = rados_conf_set(cluster, "auth_client_required", acr);
152
+ g_free(acr);
153
+ if (r < 0) {
154
+ error_setg_errno(errp, -r,
155
+ "Could not set 'auth_client_required'");
156
+ return r;
157
+ }
72
+ }
158
+ }
73
+ }
159
74
160
return 0;
75
/* Create BlockBackend to write to the image */
76
blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
77
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
78
header->compatible_features |=
79
cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS);
80
}
81
+ if (data_bs) {
82
+ header->incompatible_features |=
83
+ cpu_to_be64(QCOW2_INCOMPAT_DATA_FILE);
84
+ }
85
86
ret = blk_pwrite(blk, 0, header, cluster_size, 0);
87
g_free(header);
88
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
89
options = qdict_new();
90
qdict_put_str(options, "driver", "qcow2");
91
qdict_put_str(options, "file", bs->node_name);
92
+ if (data_bs) {
93
+ qdict_put_str(options, "data-file", data_bs->node_name);
94
+ }
95
blk = blk_new_open(NULL, NULL, options,
96
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH,
97
&local_err);
98
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
99
options = qdict_new();
100
qdict_put_str(options, "driver", "qcow2");
101
qdict_put_str(options, "file", bs->node_name);
102
+ if (data_bs) {
103
+ qdict_put_str(options, "data-file", data_bs->node_name);
104
+ }
105
blk = blk_new_open(NULL, NULL, options,
106
BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO,
107
&local_err);
108
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
109
out:
110
blk_unref(blk);
111
bdrv_unref(bs);
112
+ bdrv_unref(data_bs);
113
return ret;
161
}
114
}
162
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
115
163
}
164
}
165
166
- if (qemu_rbd_set_auth(*cluster, secretid, errp) < 0) {
167
+ if (qemu_rbd_set_auth(*cluster, secretid, opts, errp) < 0) {
168
r = -EIO;
169
goto failed_shutdown;
170
}
171
--
116
--
172
2.13.6
117
2.20.1
173
118
174
119
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
Rather than requiring that the external data file node is passed
2
explicitly when creating the qcow2 node, store the filename in the
3
designated header extension during .bdrv_create and read it from there
4
as a default during .bdrv_open.
2
5
3
Pure code motion, except for two brace placements and a comment
4
tweaked to appease checkpatch.
5
6
Signed-off-by: Markus Armbruster <armbru@redhat.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
7
---
10
qobject/block-qdict.c | 640 ++++++++++++++++++++++++++++++++++++++++++++
8
qapi/block-core.json | 8 +++-
11
qobject/qdict.c | 629 --------------------------------------------
9
block/qcow2.h | 1 +
12
tests/check-block-qdict.c | 655 ++++++++++++++++++++++++++++++++++++++++++++++
10
block/qcow2.c | 94 +++++++++++++++++++++++++++++++++++++-
13
tests/check-qdict.c | 642 ---------------------------------------------
11
tests/qemu-iotests/082.out | 27 +++++++++++
14
MAINTAINERS | 2 +
12
4 files changed, 128 insertions(+), 2 deletions(-)
15
qobject/Makefile.objs | 1 +
16
tests/Makefile.include | 4 +
17
7 files changed, 1302 insertions(+), 1271 deletions(-)
18
create mode 100644 qobject/block-qdict.c
19
create mode 100644 tests/check-block-qdict.c
20
13
21
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
14
diff --git a/qapi/block-core.json b/qapi/block-core.json
22
new file mode 100644
15
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX
16
--- a/qapi/block-core.json
24
--- /dev/null
17
+++ b/qapi/block-core.json
25
+++ b/qobject/block-qdict.c
26
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@
27
+/*
19
#
28
+ * Special QDict functions used by the block layer
20
# @compat: compatibility level
29
+ *
21
#
30
+ * Copyright (c) 2013-2018 Red Hat, Inc.
22
+# @data-file: the filename of the external data file that is stored in the
31
+ *
23
+# image and used as a default for opening the image (since: 4.0)
32
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
24
+#
33
+ * See the COPYING.LIB file in the top-level directory.
25
# @lazy-refcounts: on or off; only valid for compat >= 1.1
34
+ */
26
#
35
+
27
# @corrupt: true if the image has been marked corrupt; only valid for
36
+#include "qemu/osdep.h"
28
@@ -XXX,XX +XXX,XX @@
37
+#include "block/qdict.h"
29
{ 'struct': 'ImageInfoSpecificQCow2',
38
+#include "qapi/qmp/qlist.h"
30
'data': {
39
+#include "qemu/cutils.h"
31
'compat': 'str',
40
+#include "qapi/error.h"
32
+ '*data-file': 'str',
41
+
33
'*lazy-refcounts': 'bool',
42
+/**
34
'*corrupt': 'bool',
43
+ * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the
35
'refcount-bits': 'int',
44
+ * value of 'key' in 'src' is copied there (and the refcount increased
36
@@ -XXX,XX +XXX,XX @@
45
+ * accordingly).
37
#
46
+ */
38
# @data-file: reference to or definition of the external data file.
47
+void qdict_copy_default(QDict *dst, QDict *src, const char *key)
39
# This may only be specified for images that require an
48
+{
40
-# external data file. (since 4.0)
49
+ QObject *val;
41
+# external data file. If it is not specified for such
50
+
42
+# an image, the data file name is loaded from the image
51
+ if (qdict_haskey(dst, key)) {
43
+# file. (since 4.0)
52
+ return;
44
#
53
+ }
45
# Since: 2.9
54
+
46
##
55
+ val = qdict_get(src, key);
47
diff --git a/block/qcow2.h b/block/qcow2.h
56
+ if (val) {
48
index XXXXXXX..XXXXXXX 100644
57
+ qdict_put_obj(dst, key, qobject_ref(val));
49
--- a/block/qcow2.h
58
+ }
50
+++ b/block/qcow2.h
59
+}
51
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State {
60
+
52
* override) */
61
+/**
53
char *image_backing_file;
62
+ * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a
54
char *image_backing_format;
63
+ * new QString initialised by 'val' is put there.
55
+ char *image_data_file;
64
+ */
56
65
+void qdict_set_default_str(QDict *dst, const char *key, const char *val)
57
CoQueue compress_wait_queue;
66
+{
58
int nb_compress_threads;
67
+ if (qdict_haskey(dst, key)) {
59
diff --git a/block/qcow2.c b/block/qcow2.c
68
+ return;
60
index XXXXXXX..XXXXXXX 100644
69
+ }
61
--- a/block/qcow2.c
70
+
62
+++ b/block/qcow2.c
71
+ qdict_put_str(dst, key, val);
63
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
72
+}
64
#endif
73
+
65
break;
74
+static void qdict_flatten_qdict(QDict *qdict, QDict *target,
66
75
+ const char *prefix);
67
+ case QCOW2_EXT_MAGIC_DATA_FILE:
76
+
68
+ {
77
+static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
69
+ s->image_data_file = g_malloc0(ext.len + 1);
78
+{
70
+ ret = bdrv_pread(bs->file, offset, s->image_data_file, ext.len);
79
+ QObject *value;
71
+ if (ret < 0) {
80
+ const QListEntry *entry;
72
+ error_setg_errno(errp, -ret,
81
+ char *new_key;
73
+ "ERROR: Could not read data file name");
82
+ int i;
74
+ return ret;
83
+
84
+ /* This function is never called with prefix == NULL, i.e., it is always
85
+ * called from within qdict_flatten_q(list|dict)(). Therefore, it does not
86
+ * need to remove list entries during the iteration (the whole list will be
87
+ * deleted eventually anyway from qdict_flatten_qdict()). */
88
+ assert(prefix);
89
+
90
+ entry = qlist_first(qlist);
91
+
92
+ for (i = 0; entry; entry = qlist_next(entry), i++) {
93
+ value = qlist_entry_obj(entry);
94
+ new_key = g_strdup_printf("%s.%i", prefix, i);
95
+
96
+ if (qobject_type(value) == QTYPE_QDICT) {
97
+ qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
98
+ } else if (qobject_type(value) == QTYPE_QLIST) {
99
+ qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
100
+ } else {
101
+ /* All other types are moved to the target unchanged. */
102
+ qdict_put_obj(target, new_key, qobject_ref(value));
103
+ }
104
+
105
+ g_free(new_key);
106
+ }
107
+}
108
+
109
+static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
110
+{
111
+ QObject *value;
112
+ const QDictEntry *entry, *next;
113
+ char *new_key;
114
+ bool delete;
115
+
116
+ entry = qdict_first(qdict);
117
+
118
+ while (entry != NULL) {
119
+
120
+ next = qdict_next(qdict, entry);
121
+ value = qdict_entry_value(entry);
122
+ new_key = NULL;
123
+ delete = false;
124
+
125
+ if (prefix) {
126
+ new_key = g_strdup_printf("%s.%s", prefix, entry->key);
127
+ }
128
+
129
+ if (qobject_type(value) == QTYPE_QDICT) {
130
+ /* Entries of QDicts are processed recursively, the QDict object
131
+ * itself disappears. */
132
+ qdict_flatten_qdict(qobject_to(QDict, value), target,
133
+ new_key ? new_key : entry->key);
134
+ delete = true;
135
+ } else if (qobject_type(value) == QTYPE_QLIST) {
136
+ qdict_flatten_qlist(qobject_to(QList, value), target,
137
+ new_key ? new_key : entry->key);
138
+ delete = true;
139
+ } else if (prefix) {
140
+ /* All other objects are moved to the target unchanged. */
141
+ qdict_put_obj(target, new_key, qobject_ref(value));
142
+ delete = true;
143
+ }
144
+
145
+ g_free(new_key);
146
+
147
+ if (delete) {
148
+ qdict_del(qdict, entry->key);
149
+
150
+ /* Restart loop after modifying the iterated QDict */
151
+ entry = qdict_first(qdict);
152
+ continue;
153
+ }
154
+
155
+ entry = next;
156
+ }
157
+}
158
+
159
+/**
160
+ * qdict_flatten(): For each nested QDict with key x, all fields with key y
161
+ * are moved to this QDict and their key is renamed to "x.y". For each nested
162
+ * QList with key x, the field at index y is moved to this QDict with the key
163
+ * "x.y" (i.e., the reverse of what qdict_array_split() does).
164
+ * This operation is applied recursively for nested QDicts and QLists.
165
+ */
166
+void qdict_flatten(QDict *qdict)
167
+{
168
+ qdict_flatten_qdict(qdict, qdict, NULL);
169
+}
170
+
171
+/* extract all the src QDict entries starting by start into dst */
172
+void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start)
173
+
174
+{
175
+ const QDictEntry *entry, *next;
176
+ const char *p;
177
+
178
+ *dst = qdict_new();
179
+ entry = qdict_first(src);
180
+
181
+ while (entry != NULL) {
182
+ next = qdict_next(src, entry);
183
+ if (strstart(entry->key, start, &p)) {
184
+ qdict_put_obj(*dst, p, qobject_ref(entry->value));
185
+ qdict_del(src, entry->key);
186
+ }
187
+ entry = next;
188
+ }
189
+}
190
+
191
+static int qdict_count_prefixed_entries(const QDict *src, const char *start)
192
+{
193
+ const QDictEntry *entry;
194
+ int count = 0;
195
+
196
+ for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
197
+ if (strstart(entry->key, start, NULL)) {
198
+ if (count == INT_MAX) {
199
+ return -ERANGE;
200
+ }
75
+ }
201
+ count++;
76
+#ifdef DEBUG_EXT
202
+ }
77
+ printf("Qcow2: Got external data file %s\n", s->image_data_file);
203
+ }
78
+#endif
204
+
205
+ return count;
206
+}
207
+
208
+/**
209
+ * qdict_array_split(): This function moves array-like elements of a QDict into
210
+ * a new QList. Every entry in the original QDict with a key "%u" or one
211
+ * prefixed "%u.", where %u designates an unsigned integer starting at 0 and
212
+ * incrementally counting up, will be moved to a new QDict at index %u in the
213
+ * output QList with the key prefix removed, if that prefix is "%u.". If the
214
+ * whole key is just "%u", the whole QObject will be moved unchanged without
215
+ * creating a new QDict. The function terminates when there is no entry in the
216
+ * QDict with a prefix directly (incrementally) following the last one; it also
217
+ * returns if there are both entries with "%u" and "%u." for the same index %u.
218
+ * Example: {"0.a": 42, "0.b": 23, "1.x": 0, "4.y": 1, "o.o": 7, "2": 66}
219
+ * (or {"1.x": 0, "4.y": 1, "0.a": 42, "o.o": 7, "0.b": 23, "2": 66})
220
+ * => [{"a": 42, "b": 23}, {"x": 0}, 66]
221
+ * and {"4.y": 1, "o.o": 7} (remainder of the old QDict)
222
+ */
223
+void qdict_array_split(QDict *src, QList **dst)
224
+{
225
+ unsigned i;
226
+
227
+ *dst = qlist_new();
228
+
229
+ for (i = 0; i < UINT_MAX; i++) {
230
+ QObject *subqobj;
231
+ bool is_subqdict;
232
+ QDict *subqdict;
233
+ char indexstr[32], prefix[32];
234
+ size_t snprintf_ret;
235
+
236
+ snprintf_ret = snprintf(indexstr, 32, "%u", i);
237
+ assert(snprintf_ret < 32);
238
+
239
+ subqobj = qdict_get(src, indexstr);
240
+
241
+ snprintf_ret = snprintf(prefix, 32, "%u.", i);
242
+ assert(snprintf_ret < 32);
243
+
244
+ /* Overflow is the same as positive non-zero results */
245
+ is_subqdict = qdict_count_prefixed_entries(src, prefix);
246
+
247
+ /*
248
+ * There may be either a single subordinate object (named
249
+ * "%u") or multiple objects (each with a key prefixed "%u."),
250
+ * but not both.
251
+ */
252
+ if (!subqobj == !is_subqdict) {
253
+ break;
79
+ break;
254
+ }
80
+ }
255
+
81
+
256
+ if (is_subqdict) {
82
default:
257
+ qdict_extract_subqdict(src, &subqdict, prefix);
83
/* unknown magic - save it in case we need to rewrite the header */
258
+ assert(qdict_size(subqdict) > 0);
84
/* If you add a new feature, make sure to also update the fast
259
+ } else {
85
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
260
+ qobject_ref(subqobj);
86
}
261
+ qdict_del(src, indexstr);
87
262
+ }
88
if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
263
+
89
+ if (!s->data_file && s->image_data_file) {
264
+ qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict));
90
+ s->data_file = bdrv_open_child(s->image_data_file, options,
265
+ }
91
+ "data-file", bs, &child_file,
266
+}
92
+ false, errp);
267
+
93
+ if (!s->data_file) {
268
+/**
94
+ ret = -EINVAL;
269
+ * qdict_split_flat_key:
95
+ goto fail;
270
+ * @key: the key string to split
271
+ * @prefix: non-NULL pointer to hold extracted prefix
272
+ * @suffix: non-NULL pointer to remaining suffix
273
+ *
274
+ * Given a flattened key such as 'foo.0.bar', split it into two parts
275
+ * at the first '.' separator. Allows double dot ('..') to escape the
276
+ * normal separator.
277
+ *
278
+ * e.g.
279
+ * 'foo.0.bar' -> prefix='foo' and suffix='0.bar'
280
+ * 'foo..0.bar' -> prefix='foo.0' and suffix='bar'
281
+ *
282
+ * The '..' sequence will be unescaped in the returned 'prefix'
283
+ * string. The 'suffix' string will be left in escaped format, so it
284
+ * can be fed back into the qdict_split_flat_key() key as the input
285
+ * later.
286
+ *
287
+ * The caller is responsible for freeing the string returned in @prefix
288
+ * using g_free().
289
+ */
290
+static void qdict_split_flat_key(const char *key, char **prefix,
291
+ const char **suffix)
292
+{
293
+ const char *separator;
294
+ size_t i, j;
295
+
296
+ /* Find first '.' separator, but if there is a pair '..'
297
+ * that acts as an escape, so skip over '..' */
298
+ separator = NULL;
299
+ do {
300
+ if (separator) {
301
+ separator += 2;
302
+ } else {
303
+ separator = key;
304
+ }
305
+ separator = strchr(separator, '.');
306
+ } while (separator && separator[1] == '.');
307
+
308
+ if (separator) {
309
+ *prefix = g_strndup(key, separator - key);
310
+ *suffix = separator + 1;
311
+ } else {
312
+ *prefix = g_strdup(key);
313
+ *suffix = NULL;
314
+ }
315
+
316
+ /* Unescape the '..' sequence into '.' */
317
+ for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) {
318
+ if ((*prefix)[i] == '.') {
319
+ assert((*prefix)[i + 1] == '.');
320
+ i++;
321
+ }
322
+ (*prefix)[j] = (*prefix)[i];
323
+ }
324
+ (*prefix)[j] = '\0';
325
+}
326
+
327
+/**
328
+ * qdict_is_list:
329
+ * @maybe_list: dict to check if keys represent list elements.
330
+ *
331
+ * Determine whether all keys in @maybe_list are valid list elements.
332
+ * If @maybe_list is non-zero in length and all the keys look like
333
+ * valid list indexes, this will return 1. If @maybe_list is zero
334
+ * length or all keys are non-numeric then it will return 0 to indicate
335
+ * it is a normal qdict. If there is a mix of numeric and non-numeric
336
+ * keys, or the list indexes are non-contiguous, an error is reported.
337
+ *
338
+ * Returns: 1 if a valid list, 0 if a dict, -1 on error
339
+ */
340
+static int qdict_is_list(QDict *maybe_list, Error **errp)
341
+{
342
+ const QDictEntry *ent;
343
+ ssize_t len = 0;
344
+ ssize_t max = -1;
345
+ int is_list = -1;
346
+ int64_t val;
347
+
348
+ for (ent = qdict_first(maybe_list); ent != NULL;
349
+ ent = qdict_next(maybe_list, ent)) {
350
+
351
+ if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) {
352
+ if (is_list == -1) {
353
+ is_list = 1;
354
+ } else if (!is_list) {
355
+ error_setg(errp,
356
+ "Cannot mix list and non-list keys");
357
+ return -1;
358
+ }
359
+ len++;
360
+ if (val > max) {
361
+ max = val;
362
+ }
363
+ } else {
364
+ if (is_list == -1) {
365
+ is_list = 0;
366
+ } else if (is_list) {
367
+ error_setg(errp,
368
+ "Cannot mix list and non-list keys");
369
+ return -1;
370
+ }
96
+ }
371
+ }
97
+ }
98
if (!s->data_file) {
99
error_setg(errp, "'data-file' is required for this image");
100
ret = -EINVAL;
101
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
102
return ret;
103
104
fail:
105
+ g_free(s->image_data_file);
106
if (has_data_file(bs)) {
107
bdrv_unref_child(bs, s->data_file);
108
}
109
@@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs)
110
g_free(s->unknown_header_fields);
111
cleanup_unknown_header_ext(bs);
112
113
+ g_free(s->image_data_file);
114
g_free(s->image_backing_file);
115
g_free(s->image_backing_format);
116
117
@@ -XXX,XX +XXX,XX @@ int qcow2_update_header(BlockDriverState *bs)
118
buflen -= ret;
119
}
120
121
+ /* External data file header extension */
122
+ if (has_data_file(bs) && s->image_data_file) {
123
+ ret = header_ext_add(buf, QCOW2_EXT_MAGIC_DATA_FILE,
124
+ s->image_data_file, strlen(s->image_data_file),
125
+ buflen);
126
+ if (ret < 0) {
127
+ goto fail;
128
+ }
129
+
130
+ buf += ret;
131
+ buflen -= ret;
372
+ }
132
+ }
373
+
133
+
374
+ if (is_list == -1) {
134
/* Full disk encryption header pointer extension */
375
+ assert(!qdict_size(maybe_list));
135
if (s->crypto_header.offset != 0) {
376
+ is_list = 0;
136
s->crypto_header.offset = cpu_to_be64(s->crypto_header.offset);
137
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
138
abort();
139
}
140
141
+ /* Set the external data file if necessary */
142
+ if (data_bs) {
143
+ BDRVQcow2State *s = blk_bs(blk)->opaque;
144
+ s->image_data_file = g_strdup(data_bs->filename);
377
+ }
145
+ }
378
+
146
+
379
+ /* NB this isn't a perfect check - e.g. it won't catch
147
/* Create a full header (including things like feature table) */
380
+ * a list containing '1', '+1', '01', '3', but that
148
ret = qcow2_update_header(blk_bs(blk));
381
+ * does not matter - we've still proved that the
149
if (ret < 0) {
382
+ * input is a list. It is up the caller to do a
150
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
383
+ * stricter check if desired */
151
QDict *qdict;
384
+ if (len != (max + 1)) {
152
Visitor *v;
385
+ error_setg(errp, "List indices are not contiguous, "
153
BlockDriverState *bs = NULL;
386
+ "saw %zd elements but %zd largest index",
154
+ BlockDriverState *data_bs = NULL;
387
+ len, max);
155
Error *local_err = NULL;
388
+ return -1;
156
const char *val;
157
int ret;
158
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
159
goto finish;
160
}
161
162
+ /* Create and open an external data file (protocol layer) */
163
+ val = qdict_get_try_str(qdict, BLOCK_OPT_DATA_FILE);
164
+ if (val) {
165
+ ret = bdrv_create_file(val, opts, errp);
166
+ if (ret < 0) {
167
+ goto finish;
168
+ }
169
+
170
+ data_bs = bdrv_open(val, NULL, NULL,
171
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
172
+ errp);
173
+ if (data_bs == NULL) {
174
+ ret = -EIO;
175
+ goto finish;
176
+ }
177
+
178
+ qdict_del(qdict, BLOCK_OPT_DATA_FILE);
179
+ qdict_put_str(qdict, "data-file", data_bs->node_name);
389
+ }
180
+ }
390
+
181
+
391
+ return is_list;
182
/* Set 'driver' and 'node' options */
392
+}
183
qdict_put_str(qdict, "driver", "qcow2");
393
+
184
qdict_put_str(qdict, "file", bs->node_name);
394
+/**
185
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
395
+ * qdict_crumple:
186
finish:
396
+ * @src: the original flat dictionary (only scalar values) to crumple
187
qobject_unref(qdict);
397
+ *
188
bdrv_unref(bs);
398
+ * Takes a flat dictionary whose keys use '.' separator to indicate
189
+ bdrv_unref(data_bs);
399
+ * nesting, and values are scalars, and crumples it into a nested
190
qapi_free_BlockdevCreateOptions(create_options);
400
+ * structure.
191
return ret;
401
+ *
192
}
402
+ * To include a literal '.' in a key name, it must be escaped as '..'
193
@@ -XXX,XX +XXX,XX @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs,
403
+ *
194
.refcount_bits = s->refcount_bits,
404
+ * For example, an input of:
195
.has_bitmaps = !!bitmaps,
405
+ *
196
.bitmaps = bitmaps,
406
+ * { 'foo.0.bar': 'one', 'foo.0.wizz': '1',
197
+ .has_data_file = !!s->image_data_file,
407
+ * 'foo.1.bar': 'two', 'foo.1.wizz': '2' }
198
+ .data_file = g_strdup(s->image_data_file),
408
+ *
199
};
409
+ * will result in an output of:
200
} else {
410
+ *
201
/* if this assertion fails, this probably means a new version was
411
+ * {
202
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
412
+ * 'foo': [
203
BDRVQcow2State *s = bs->opaque;
413
+ * { 'bar': 'one', 'wizz': '1' },
204
int old_version = s->qcow_version, new_version = old_version;
414
+ * { 'bar': 'two', 'wizz': '2' }
205
uint64_t new_size = 0;
415
+ * ],
206
- const char *backing_file = NULL, *backing_format = NULL;
416
+ * }
207
+ const char *backing_file = NULL, *backing_format = NULL, *data_file = NULL;
417
+ *
208
bool lazy_refcounts = s->use_lazy_refcounts;
418
+ * The following scenarios in the input dict will result in an
209
const char *compat = NULL;
419
+ * error being returned:
210
uint64_t cluster_size = s->cluster_size;
420
+ *
211
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
421
+ * - Any values in @src are non-scalar types
212
"may not exceed 64 bits");
422
+ * - If keys in @src imply that a particular level is both a
213
return -EINVAL;
423
+ * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar".
214
}
424
+ * - If keys in @src imply that a particular level is a list,
215
+ } else if (!strcmp(desc->name, BLOCK_OPT_DATA_FILE)) {
425
+ * but the indices are non-contiguous. e.g. "foo.0.bar" and
216
+ data_file = qemu_opt_get(opts, BLOCK_OPT_DATA_FILE);
426
+ * "foo.2.bar" without any "foo.1.bar" present.
217
+ if (data_file && !has_data_file(bs)) {
427
+ * - If keys in @src represent list indexes, but are not in
218
+ error_setg(errp, "data-file can only be set for images that "
428
+ * the "%zu" format. e.g. "foo.+0.bar"
219
+ "use an external data file");
429
+ *
220
+ return -EINVAL;
430
+ * Returns: either a QDict or QList for the nested data structure, or NULL
431
+ * on error
432
+ */
433
+QObject *qdict_crumple(const QDict *src, Error **errp)
434
+{
435
+ const QDictEntry *ent;
436
+ QDict *two_level, *multi_level = NULL;
437
+ QObject *dst = NULL, *child;
438
+ size_t i;
439
+ char *prefix = NULL;
440
+ const char *suffix = NULL;
441
+ int is_list;
442
+
443
+ two_level = qdict_new();
444
+
445
+ /* Step 1: split our totally flat dict into a two level dict */
446
+ for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) {
447
+ if (qobject_type(ent->value) == QTYPE_QDICT ||
448
+ qobject_type(ent->value) == QTYPE_QLIST) {
449
+ error_setg(errp, "Value %s is not a scalar",
450
+ ent->key);
451
+ goto error;
452
+ }
453
+
454
+ qdict_split_flat_key(ent->key, &prefix, &suffix);
455
+
456
+ child = qdict_get(two_level, prefix);
457
+ if (suffix) {
458
+ QDict *child_dict = qobject_to(QDict, child);
459
+ if (!child_dict) {
460
+ if (child) {
461
+ error_setg(errp, "Key %s prefix is already set as a scalar",
462
+ prefix);
463
+ goto error;
464
+ }
465
+
466
+ child_dict = qdict_new();
467
+ qdict_put_obj(two_level, prefix, QOBJECT(child_dict));
468
+ }
221
+ }
469
+
222
} else {
470
+ qdict_put_obj(child_dict, suffix, qobject_ref(ent->value));
223
/* if this point is reached, this probably means a new option was
471
+ } else {
224
* added without having it covered here */
472
+ if (child) {
225
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
473
+ error_setg(errp, "Key %s prefix is already set as a dict",
226
}
474
+ prefix);
227
}
475
+ goto error;
228
476
+ }
229
+ if (data_file) {
477
+ qdict_put_obj(two_level, prefix, qobject_ref(ent->value));
230
+ g_free(s->image_data_file);
478
+ }
231
+ s->image_data_file = *data_file ? g_strdup(data_file) : NULL;
479
+
480
+ g_free(prefix);
481
+ prefix = NULL;
482
+ }
232
+ }
483
+
233
+
484
+ /* Step 2: optionally process the two level dict recursively
234
+ ret = qcow2_update_header(bs);
485
+ * into a multi-level dict */
235
+ if (ret < 0) {
486
+ multi_level = qdict_new();
236
+ error_setg_errno(errp, -ret, "Failed to update the image header");
487
+ for (ent = qdict_first(two_level); ent != NULL;
237
+ return ret;
488
+ ent = qdict_next(two_level, ent)) {
489
+ QDict *dict = qobject_to(QDict, ent->value);
490
+ if (dict) {
491
+ child = qdict_crumple(dict, errp);
492
+ if (!child) {
493
+ goto error;
494
+ }
495
+
496
+ qdict_put_obj(multi_level, ent->key, child);
497
+ } else {
498
+ qdict_put_obj(multi_level, ent->key, qobject_ref(ent->value));
499
+ }
500
+ }
238
+ }
501
+ qobject_unref(two_level);
239
+
502
+ two_level = NULL;
240
if (backing_file || backing_format) {
503
+
241
ret = qcow2_change_backing_file(bs,
504
+ /* Step 3: detect if we need to turn our dict into list */
242
backing_file ?: s->image_backing_file,
505
+ is_list = qdict_is_list(multi_level, errp);
243
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_create_opts = {
506
+ if (is_list < 0) {
244
.type = QEMU_OPT_STRING,
507
+ goto error;
245
.help = "Image format of the base image"
508
+ }
246
},
509
+
247
+ {
510
+ if (is_list) {
248
+ .name = BLOCK_OPT_DATA_FILE,
511
+ dst = QOBJECT(qlist_new());
249
+ .type = QEMU_OPT_STRING,
512
+
250
+ .help = "File name of an external data file"
513
+ for (i = 0; i < qdict_size(multi_level); i++) {
251
+ },
514
+ char *key = g_strdup_printf("%zu", i);
252
{
515
+
253
.name = BLOCK_OPT_ENCRYPT,
516
+ child = qdict_get(multi_level, key);
254
.type = QEMU_OPT_BOOL,
517
+ g_free(key);
255
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
518
+
519
+ if (!child) {
520
+ error_setg(errp, "Missing list index %zu", i);
521
+ goto error;
522
+ }
523
+
524
+ qlist_append_obj(qobject_to(QList, dst), qobject_ref(child));
525
+ }
526
+ qobject_unref(multi_level);
527
+ multi_level = NULL;
528
+ } else {
529
+ dst = QOBJECT(multi_level);
530
+ }
531
+
532
+ return dst;
533
+
534
+ error:
535
+ g_free(prefix);
536
+ qobject_unref(multi_level);
537
+ qobject_unref(two_level);
538
+ qobject_unref(dst);
539
+ return NULL;
540
+}
541
+
542
+/**
543
+ * qdict_array_entries(): Returns the number of direct array entries if the
544
+ * sub-QDict of src specified by the prefix in subqdict (or src itself for
545
+ * prefix == "") is valid as an array, i.e. the length of the created list if
546
+ * the sub-QDict would become empty after calling qdict_array_split() on it. If
547
+ * the array is not valid, -EINVAL is returned.
548
+ */
549
+int qdict_array_entries(QDict *src, const char *subqdict)
550
+{
551
+ const QDictEntry *entry;
552
+ unsigned i;
553
+ unsigned entries = 0;
554
+ size_t subqdict_len = strlen(subqdict);
555
+
556
+ assert(!subqdict_len || subqdict[subqdict_len - 1] == '.');
557
+
558
+ /* qdict_array_split() loops until UINT_MAX, but as we want to return
559
+ * negative errors, we only have a signed return value here. Any additional
560
+ * entries will lead to -EINVAL. */
561
+ for (i = 0; i < INT_MAX; i++) {
562
+ QObject *subqobj;
563
+ int subqdict_entries;
564
+ char *prefix = g_strdup_printf("%s%u.", subqdict, i);
565
+
566
+ subqdict_entries = qdict_count_prefixed_entries(src, prefix);
567
+
568
+ /* Remove ending "." */
569
+ prefix[strlen(prefix) - 1] = 0;
570
+ subqobj = qdict_get(src, prefix);
571
+
572
+ g_free(prefix);
573
+
574
+ if (subqdict_entries < 0) {
575
+ return subqdict_entries;
576
+ }
577
+
578
+ /* There may be either a single subordinate object (named "%u") or
579
+ * multiple objects (each with a key prefixed "%u."), but not both. */
580
+ if (subqobj && subqdict_entries) {
581
+ return -EINVAL;
582
+ } else if (!subqobj && !subqdict_entries) {
583
+ break;
584
+ }
585
+
586
+ entries += subqdict_entries ? subqdict_entries : 1;
587
+ }
588
+
589
+ /* Consider everything handled that isn't part of the given sub-QDict */
590
+ for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
591
+ if (!strstart(qdict_entry_key(entry), subqdict, NULL)) {
592
+ entries++;
593
+ }
594
+ }
595
+
596
+ /* Anything left in the sub-QDict that wasn't handled? */
597
+ if (qdict_size(src) != entries) {
598
+ return -EINVAL;
599
+ }
600
+
601
+ return i;
602
+}
603
+
604
+/**
605
+ * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
606
+ * elements from src to dest.
607
+ *
608
+ * If an element from src has a key already present in dest, it will not be
609
+ * moved unless overwrite is true.
610
+ *
611
+ * If overwrite is true, the conflicting values in dest will be discarded and
612
+ * replaced by the corresponding values from src.
613
+ *
614
+ * Therefore, with overwrite being true, the src QDict will always be empty when
615
+ * this function returns. If overwrite is false, the src QDict will be empty
616
+ * iff there were no conflicts.
617
+ */
618
+void qdict_join(QDict *dest, QDict *src, bool overwrite)
619
+{
620
+ const QDictEntry *entry, *next;
621
+
622
+ entry = qdict_first(src);
623
+ while (entry) {
624
+ next = qdict_next(src, entry);
625
+
626
+ if (overwrite || !qdict_haskey(dest, entry->key)) {
627
+ qdict_put_obj(dest, entry->key, qobject_ref(entry->value));
628
+ qdict_del(src, entry->key);
629
+ }
630
+
631
+ entry = next;
632
+ }
633
+}
634
+
635
+/**
636
+ * qdict_rename_keys(): Rename keys in qdict according to the replacements
637
+ * specified in the array renames. The array must be terminated by an entry
638
+ * with from = NULL.
639
+ *
640
+ * The renames are performed individually in the order of the array, so entries
641
+ * may be renamed multiple times and may or may not conflict depending on the
642
+ * order of the renames array.
643
+ *
644
+ * Returns true for success, false in error cases.
645
+ */
646
+bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
647
+{
648
+ QObject *qobj;
649
+
650
+ while (renames->from) {
651
+ if (qdict_haskey(qdict, renames->from)) {
652
+ if (qdict_haskey(qdict, renames->to)) {
653
+ error_setg(errp, "'%s' and its alias '%s' can't be used at the "
654
+ "same time", renames->to, renames->from);
655
+ return false;
656
+ }
657
+
658
+ qobj = qdict_get(qdict, renames->from);
659
+ qdict_put_obj(qdict, renames->to, qobject_ref(qobj));
660
+ qdict_del(qdict, renames->from);
661
+ }
662
+
663
+ renames++;
664
+ }
665
+ return true;
666
+}
667
diff --git a/qobject/qdict.c b/qobject/qdict.c
668
index XXXXXXX..XXXXXXX 100644
256
index XXXXXXX..XXXXXXX 100644
669
--- a/qobject/qdict.c
257
--- a/tests/qemu-iotests/082.out
670
+++ b/qobject/qdict.c
258
+++ b/tests/qemu-iotests/082.out
671
@@ -XXX,XX +XXX,XX @@
259
@@ -XXX,XX +XXX,XX @@ Supported options:
672
*/
260
backing_fmt=<str> - Image format of the base image
673
261
cluster_size=<size> - qcow2 cluster size
674
#include "qemu/osdep.h"
262
compat=<str> - Compatibility level (0.10 or 1.1)
675
-#include "block/qdict.h"
263
+ data_file=<str> - File name of an external data file
676
#include "qapi/qmp/qnum.h"
264
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
677
#include "qapi/qmp/qdict.h"
265
encrypt.cipher-mode=<str> - Name of encryption cipher mode
678
#include "qapi/qmp/qbool.h"
266
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
679
-#include "qapi/qmp/qlist.h"
267
@@ -XXX,XX +XXX,XX @@ Supported options:
680
#include "qapi/qmp/qnull.h"
268
backing_fmt=<str> - Image format of the base image
681
#include "qapi/qmp/qstring.h"
269
cluster_size=<size> - qcow2 cluster size
682
-#include "qapi/error.h"
270
compat=<str> - Compatibility level (0.10 or 1.1)
683
-#include "qemu/queue.h"
271
+ data_file=<str> - File name of an external data file
684
-#include "qemu-common.h"
272
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
685
-#include "qemu/cutils.h"
273
encrypt.cipher-mode=<str> - Name of encryption cipher mode
686
274
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
687
/**
275
@@ -XXX,XX +XXX,XX @@ Supported options:
688
* qdict_new(): Create a new QDict
276
backing_fmt=<str> - Image format of the base image
689
@@ -XXX,XX +XXX,XX @@ void qdict_destroy_obj(QObject *obj)
277
cluster_size=<size> - qcow2 cluster size
690
278
compat=<str> - Compatibility level (0.10 or 1.1)
691
g_free(qdict);
279
+ data_file=<str> - File name of an external data file
692
}
280
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
693
-
281
encrypt.cipher-mode=<str> - Name of encryption cipher mode
694
-/**
282
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
695
- * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the
283
@@ -XXX,XX +XXX,XX @@ Supported options:
696
- * value of 'key' in 'src' is copied there (and the refcount increased
284
backing_fmt=<str> - Image format of the base image
697
- * accordingly).
285
cluster_size=<size> - qcow2 cluster size
698
- */
286
compat=<str> - Compatibility level (0.10 or 1.1)
699
-void qdict_copy_default(QDict *dst, QDict *src, const char *key)
287
+ data_file=<str> - File name of an external data file
700
-{
288
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
701
- QObject *val;
289
encrypt.cipher-mode=<str> - Name of encryption cipher mode
702
-
290
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
703
- if (qdict_haskey(dst, key)) {
291
@@ -XXX,XX +XXX,XX @@ Supported options:
704
- return;
292
backing_fmt=<str> - Image format of the base image
705
- }
293
cluster_size=<size> - qcow2 cluster size
706
-
294
compat=<str> - Compatibility level (0.10 or 1.1)
707
- val = qdict_get(src, key);
295
+ data_file=<str> - File name of an external data file
708
- if (val) {
296
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
709
- qdict_put_obj(dst, key, qobject_ref(val));
297
encrypt.cipher-mode=<str> - Name of encryption cipher mode
710
- }
298
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
711
-}
299
@@ -XXX,XX +XXX,XX @@ Supported options:
712
-
300
backing_fmt=<str> - Image format of the base image
713
-/**
301
cluster_size=<size> - qcow2 cluster size
714
- * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a
302
compat=<str> - Compatibility level (0.10 or 1.1)
715
- * new QString initialised by 'val' is put there.
303
+ data_file=<str> - File name of an external data file
716
- */
304
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
717
-void qdict_set_default_str(QDict *dst, const char *key, const char *val)
305
encrypt.cipher-mode=<str> - Name of encryption cipher mode
718
-{
306
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
719
- if (qdict_haskey(dst, key)) {
307
@@ -XXX,XX +XXX,XX @@ Supported options:
720
- return;
308
backing_fmt=<str> - Image format of the base image
721
- }
309
cluster_size=<size> - qcow2 cluster size
722
-
310
compat=<str> - Compatibility level (0.10 or 1.1)
723
- qdict_put_str(dst, key, val);
311
+ data_file=<str> - File name of an external data file
724
-}
312
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
725
-
313
encrypt.cipher-mode=<str> - Name of encryption cipher mode
726
-static void qdict_flatten_qdict(QDict *qdict, QDict *target,
314
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
727
- const char *prefix);
315
@@ -XXX,XX +XXX,XX @@ Supported options:
728
-
316
backing_fmt=<str> - Image format of the base image
729
-static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
317
cluster_size=<size> - qcow2 cluster size
730
-{
318
compat=<str> - Compatibility level (0.10 or 1.1)
731
- QObject *value;
319
+ data_file=<str> - File name of an external data file
732
- const QListEntry *entry;
320
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
733
- char *new_key;
321
encrypt.cipher-mode=<str> - Name of encryption cipher mode
734
- int i;
322
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
735
-
323
@@ -XXX,XX +XXX,XX @@ Supported options:
736
- /* This function is never called with prefix == NULL, i.e., it is always
324
backing_fmt=<str> - Image format of the base image
737
- * called from within qdict_flatten_q(list|dict)(). Therefore, it does not
325
cluster_size=<size> - qcow2 cluster size
738
- * need to remove list entries during the iteration (the whole list will be
326
compat=<str> - Compatibility level (0.10 or 1.1)
739
- * deleted eventually anyway from qdict_flatten_qdict()). */
327
+ data_file=<str> - File name of an external data file
740
- assert(prefix);
328
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
741
-
329
encrypt.cipher-mode=<str> - Name of encryption cipher mode
742
- entry = qlist_first(qlist);
330
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
743
-
331
@@ -XXX,XX +XXX,XX @@ Supported options:
744
- for (i = 0; entry; entry = qlist_next(entry), i++) {
332
backing_fmt=<str> - Image format of the base image
745
- value = qlist_entry_obj(entry);
333
cluster_size=<size> - qcow2 cluster size
746
- new_key = g_strdup_printf("%s.%i", prefix, i);
334
compat=<str> - Compatibility level (0.10 or 1.1)
747
-
335
+ data_file=<str> - File name of an external data file
748
- if (qobject_type(value) == QTYPE_QDICT) {
336
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
749
- qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
337
encrypt.cipher-mode=<str> - Name of encryption cipher mode
750
- } else if (qobject_type(value) == QTYPE_QLIST) {
338
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
751
- qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
339
@@ -XXX,XX +XXX,XX @@ Supported options:
752
- } else {
340
backing_fmt=<str> - Image format of the base image
753
- /* All other types are moved to the target unchanged. */
341
cluster_size=<size> - qcow2 cluster size
754
- qdict_put_obj(target, new_key, qobject_ref(value));
342
compat=<str> - Compatibility level (0.10 or 1.1)
755
- }
343
+ data_file=<str> - File name of an external data file
756
-
344
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
757
- g_free(new_key);
345
encrypt.cipher-mode=<str> - Name of encryption cipher mode
758
- }
346
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
759
-}
347
@@ -XXX,XX +XXX,XX @@ Supported options:
760
-
348
backing_fmt=<str> - Image format of the base image
761
-static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
349
cluster_size=<size> - qcow2 cluster size
762
-{
350
compat=<str> - Compatibility level (0.10 or 1.1)
763
- QObject *value;
351
+ data_file=<str> - File name of an external data file
764
- const QDictEntry *entry, *next;
352
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
765
- char *new_key;
353
encrypt.cipher-mode=<str> - Name of encryption cipher mode
766
- bool delete;
354
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
767
-
355
@@ -XXX,XX +XXX,XX @@ Supported options:
768
- entry = qdict_first(qdict);
356
backing_fmt=<str> - Image format of the base image
769
-
357
cluster_size=<size> - qcow2 cluster size
770
- while (entry != NULL) {
358
compat=<str> - Compatibility level (0.10 or 1.1)
771
-
359
+ data_file=<str> - File name of an external data file
772
- next = qdict_next(qdict, entry);
360
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
773
- value = qdict_entry_value(entry);
361
encrypt.cipher-mode=<str> - Name of encryption cipher mode
774
- new_key = NULL;
362
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
775
- delete = false;
363
@@ -XXX,XX +XXX,XX @@ Supported options:
776
-
364
backing_fmt=<str> - Image format of the base image
777
- if (prefix) {
365
cluster_size=<size> - qcow2 cluster size
778
- new_key = g_strdup_printf("%s.%s", prefix, entry->key);
366
compat=<str> - Compatibility level (0.10 or 1.1)
779
- }
367
+ data_file=<str> - File name of an external data file
780
-
368
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
781
- if (qobject_type(value) == QTYPE_QDICT) {
369
encrypt.cipher-mode=<str> - Name of encryption cipher mode
782
- /* Entries of QDicts are processed recursively, the QDict object
370
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
783
- * itself disappears. */
371
@@ -XXX,XX +XXX,XX @@ Supported options:
784
- qdict_flatten_qdict(qobject_to(QDict, value), target,
372
backing_fmt=<str> - Image format of the base image
785
- new_key ? new_key : entry->key);
373
cluster_size=<size> - qcow2 cluster size
786
- delete = true;
374
compat=<str> - Compatibility level (0.10 or 1.1)
787
- } else if (qobject_type(value) == QTYPE_QLIST) {
375
+ data_file=<str> - File name of an external data file
788
- qdict_flatten_qlist(qobject_to(QList, value), target,
376
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
789
- new_key ? new_key : entry->key);
377
encrypt.cipher-mode=<str> - Name of encryption cipher mode
790
- delete = true;
378
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
791
- } else if (prefix) {
379
@@ -XXX,XX +XXX,XX @@ Supported options:
792
- /* All other objects are moved to the target unchanged. */
380
backing_fmt=<str> - Image format of the base image
793
- qdict_put_obj(target, new_key, qobject_ref(value));
381
cluster_size=<size> - qcow2 cluster size
794
- delete = true;
382
compat=<str> - Compatibility level (0.10 or 1.1)
795
- }
383
+ data_file=<str> - File name of an external data file
796
-
384
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
797
- g_free(new_key);
385
encrypt.cipher-mode=<str> - Name of encryption cipher mode
798
-
386
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
799
- if (delete) {
387
@@ -XXX,XX +XXX,XX @@ Supported options:
800
- qdict_del(qdict, entry->key);
388
backing_fmt=<str> - Image format of the base image
801
-
389
cluster_size=<size> - qcow2 cluster size
802
- /* Restart loop after modifying the iterated QDict */
390
compat=<str> - Compatibility level (0.10 or 1.1)
803
- entry = qdict_first(qdict);
391
+ data_file=<str> - File name of an external data file
804
- continue;
392
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
805
- }
393
encrypt.cipher-mode=<str> - Name of encryption cipher mode
806
-
394
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
807
- entry = next;
395
@@ -XXX,XX +XXX,XX @@ Supported options:
808
- }
396
backing_fmt=<str> - Image format of the base image
809
-}
397
cluster_size=<size> - qcow2 cluster size
810
-
398
compat=<str> - Compatibility level (0.10 or 1.1)
811
-/**
399
+ data_file=<str> - File name of an external data file
812
- * qdict_flatten(): For each nested QDict with key x, all fields with key y
400
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
813
- * are moved to this QDict and their key is renamed to "x.y". For each nested
401
encrypt.cipher-mode=<str> - Name of encryption cipher mode
814
- * QList with key x, the field at index y is moved to this QDict with the key
402
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
815
- * "x.y" (i.e., the reverse of what qdict_array_split() does).
403
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
816
- * This operation is applied recursively for nested QDicts and QLists.
404
backing_fmt=<str> - Image format of the base image
817
- */
405
cluster_size=<size> - qcow2 cluster size
818
-void qdict_flatten(QDict *qdict)
406
compat=<str> - Compatibility level (0.10 or 1.1)
819
-{
407
+ data_file=<str> - File name of an external data file
820
- qdict_flatten_qdict(qdict, qdict, NULL);
408
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
821
-}
409
encrypt.cipher-mode=<str> - Name of encryption cipher mode
822
-
410
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
823
-/* extract all the src QDict entries starting by start into dst */
411
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
824
-void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start)
412
backing_fmt=<str> - Image format of the base image
825
-
413
cluster_size=<size> - qcow2 cluster size
826
-{
414
compat=<str> - Compatibility level (0.10 or 1.1)
827
- const QDictEntry *entry, *next;
415
+ data_file=<str> - File name of an external data file
828
- const char *p;
416
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
829
-
417
encrypt.cipher-mode=<str> - Name of encryption cipher mode
830
- *dst = qdict_new();
418
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
831
- entry = qdict_first(src);
419
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
832
-
420
backing_fmt=<str> - Image format of the base image
833
- while (entry != NULL) {
421
cluster_size=<size> - qcow2 cluster size
834
- next = qdict_next(src, entry);
422
compat=<str> - Compatibility level (0.10 or 1.1)
835
- if (strstart(entry->key, start, &p)) {
423
+ data_file=<str> - File name of an external data file
836
- qdict_put_obj(*dst, p, qobject_ref(entry->value));
424
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
837
- qdict_del(src, entry->key);
425
encrypt.cipher-mode=<str> - Name of encryption cipher mode
838
- }
426
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
839
- entry = next;
427
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
840
- }
428
backing_fmt=<str> - Image format of the base image
841
-}
429
cluster_size=<size> - qcow2 cluster size
842
-
430
compat=<str> - Compatibility level (0.10 or 1.1)
843
-static int qdict_count_prefixed_entries(const QDict *src, const char *start)
431
+ data_file=<str> - File name of an external data file
844
-{
432
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
845
- const QDictEntry *entry;
433
encrypt.cipher-mode=<str> - Name of encryption cipher mode
846
- int count = 0;
434
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
847
-
435
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
848
- for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
436
backing_fmt=<str> - Image format of the base image
849
- if (strstart(entry->key, start, NULL)) {
437
cluster_size=<size> - qcow2 cluster size
850
- if (count == INT_MAX) {
438
compat=<str> - Compatibility level (0.10 or 1.1)
851
- return -ERANGE;
439
+ data_file=<str> - File name of an external data file
852
- }
440
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
853
- count++;
441
encrypt.cipher-mode=<str> - Name of encryption cipher mode
854
- }
442
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
855
- }
443
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
856
-
444
backing_fmt=<str> - Image format of the base image
857
- return count;
445
cluster_size=<size> - qcow2 cluster size
858
-}
446
compat=<str> - Compatibility level (0.10 or 1.1)
859
-
447
+ data_file=<str> - File name of an external data file
860
-/**
448
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
861
- * qdict_array_split(): This function moves array-like elements of a QDict into
449
encrypt.cipher-mode=<str> - Name of encryption cipher mode
862
- * a new QList. Every entry in the original QDict with a key "%u" or one
450
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
863
- * prefixed "%u.", where %u designates an unsigned integer starting at 0 and
451
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
864
- * incrementally counting up, will be moved to a new QDict at index %u in the
452
backing_fmt=<str> - Image format of the base image
865
- * output QList with the key prefix removed, if that prefix is "%u.". If the
453
cluster_size=<size> - qcow2 cluster size
866
- * whole key is just "%u", the whole QObject will be moved unchanged without
454
compat=<str> - Compatibility level (0.10 or 1.1)
867
- * creating a new QDict. The function terminates when there is no entry in the
455
+ data_file=<str> - File name of an external data file
868
- * QDict with a prefix directly (incrementally) following the last one; it also
456
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
869
- * returns if there are both entries with "%u" and "%u." for the same index %u.
457
encrypt.cipher-mode=<str> - Name of encryption cipher mode
870
- * Example: {"0.a": 42, "0.b": 23, "1.x": 0, "4.y": 1, "o.o": 7, "2": 66}
458
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
871
- * (or {"1.x": 0, "4.y": 1, "0.a": 42, "o.o": 7, "0.b": 23, "2": 66})
459
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
872
- * => [{"a": 42, "b": 23}, {"x": 0}, 66]
460
backing_fmt=<str> - Image format of the base image
873
- * and {"4.y": 1, "o.o": 7} (remainder of the old QDict)
461
cluster_size=<size> - qcow2 cluster size
874
- */
462
compat=<str> - Compatibility level (0.10 or 1.1)
875
-void qdict_array_split(QDict *src, QList **dst)
463
+ data_file=<str> - File name of an external data file
876
-{
464
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
877
- unsigned i;
465
encrypt.cipher-mode=<str> - Name of encryption cipher mode
878
-
466
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
879
- *dst = qlist_new();
467
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
880
-
468
backing_fmt=<str> - Image format of the base image
881
- for (i = 0; i < UINT_MAX; i++) {
469
cluster_size=<size> - qcow2 cluster size
882
- QObject *subqobj;
470
compat=<str> - Compatibility level (0.10 or 1.1)
883
- bool is_subqdict;
471
+ data_file=<str> - File name of an external data file
884
- QDict *subqdict;
472
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
885
- char indexstr[32], prefix[32];
473
encrypt.cipher-mode=<str> - Name of encryption cipher mode
886
- size_t snprintf_ret;
474
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
887
-
888
- snprintf_ret = snprintf(indexstr, 32, "%u", i);
889
- assert(snprintf_ret < 32);
890
-
891
- subqobj = qdict_get(src, indexstr);
892
-
893
- snprintf_ret = snprintf(prefix, 32, "%u.", i);
894
- assert(snprintf_ret < 32);
895
-
896
- /* Overflow is the same as positive non-zero results */
897
- is_subqdict = qdict_count_prefixed_entries(src, prefix);
898
-
899
- // There may be either a single subordinate object (named "%u") or
900
- // multiple objects (each with a key prefixed "%u."), but not both.
901
- if (!subqobj == !is_subqdict) {
902
- break;
903
- }
904
-
905
- if (is_subqdict) {
906
- qdict_extract_subqdict(src, &subqdict, prefix);
907
- assert(qdict_size(subqdict) > 0);
908
- } else {
909
- qobject_ref(subqobj);
910
- qdict_del(src, indexstr);
911
- }
912
-
913
- qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict));
914
- }
915
-}
916
-
917
-/**
918
- * qdict_split_flat_key:
919
- * @key: the key string to split
920
- * @prefix: non-NULL pointer to hold extracted prefix
921
- * @suffix: non-NULL pointer to remaining suffix
922
- *
923
- * Given a flattened key such as 'foo.0.bar', split it into two parts
924
- * at the first '.' separator. Allows double dot ('..') to escape the
925
- * normal separator.
926
- *
927
- * e.g.
928
- * 'foo.0.bar' -> prefix='foo' and suffix='0.bar'
929
- * 'foo..0.bar' -> prefix='foo.0' and suffix='bar'
930
- *
931
- * The '..' sequence will be unescaped in the returned 'prefix'
932
- * string. The 'suffix' string will be left in escaped format, so it
933
- * can be fed back into the qdict_split_flat_key() key as the input
934
- * later.
935
- *
936
- * The caller is responsible for freeing the string returned in @prefix
937
- * using g_free().
938
- */
939
-static void qdict_split_flat_key(const char *key, char **prefix,
940
- const char **suffix)
941
-{
942
- const char *separator;
943
- size_t i, j;
944
-
945
- /* Find first '.' separator, but if there is a pair '..'
946
- * that acts as an escape, so skip over '..' */
947
- separator = NULL;
948
- do {
949
- if (separator) {
950
- separator += 2;
951
- } else {
952
- separator = key;
953
- }
954
- separator = strchr(separator, '.');
955
- } while (separator && separator[1] == '.');
956
-
957
- if (separator) {
958
- *prefix = g_strndup(key, separator - key);
959
- *suffix = separator + 1;
960
- } else {
961
- *prefix = g_strdup(key);
962
- *suffix = NULL;
963
- }
964
-
965
- /* Unescape the '..' sequence into '.' */
966
- for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) {
967
- if ((*prefix)[i] == '.') {
968
- assert((*prefix)[i + 1] == '.');
969
- i++;
970
- }
971
- (*prefix)[j] = (*prefix)[i];
972
- }
973
- (*prefix)[j] = '\0';
974
-}
975
-
976
-/**
977
- * qdict_is_list:
978
- * @maybe_list: dict to check if keys represent list elements.
979
- *
980
- * Determine whether all keys in @maybe_list are valid list elements.
981
- * If @maybe_list is non-zero in length and all the keys look like
982
- * valid list indexes, this will return 1. If @maybe_list is zero
983
- * length or all keys are non-numeric then it will return 0 to indicate
984
- * it is a normal qdict. If there is a mix of numeric and non-numeric
985
- * keys, or the list indexes are non-contiguous, an error is reported.
986
- *
987
- * Returns: 1 if a valid list, 0 if a dict, -1 on error
988
- */
989
-static int qdict_is_list(QDict *maybe_list, Error **errp)
990
-{
991
- const QDictEntry *ent;
992
- ssize_t len = 0;
993
- ssize_t max = -1;
994
- int is_list = -1;
995
- int64_t val;
996
-
997
- for (ent = qdict_first(maybe_list); ent != NULL;
998
- ent = qdict_next(maybe_list, ent)) {
999
-
1000
- if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) {
1001
- if (is_list == -1) {
1002
- is_list = 1;
1003
- } else if (!is_list) {
1004
- error_setg(errp,
1005
- "Cannot mix list and non-list keys");
1006
- return -1;
1007
- }
1008
- len++;
1009
- if (val > max) {
1010
- max = val;
1011
- }
1012
- } else {
1013
- if (is_list == -1) {
1014
- is_list = 0;
1015
- } else if (is_list) {
1016
- error_setg(errp,
1017
- "Cannot mix list and non-list keys");
1018
- return -1;
1019
- }
1020
- }
1021
- }
1022
-
1023
- if (is_list == -1) {
1024
- assert(!qdict_size(maybe_list));
1025
- is_list = 0;
1026
- }
1027
-
1028
- /* NB this isn't a perfect check - e.g. it won't catch
1029
- * a list containing '1', '+1', '01', '3', but that
1030
- * does not matter - we've still proved that the
1031
- * input is a list. It is up the caller to do a
1032
- * stricter check if desired */
1033
- if (len != (max + 1)) {
1034
- error_setg(errp, "List indices are not contiguous, "
1035
- "saw %zd elements but %zd largest index",
1036
- len, max);
1037
- return -1;
1038
- }
1039
-
1040
- return is_list;
1041
-}
1042
-
1043
-/**
1044
- * qdict_crumple:
1045
- * @src: the original flat dictionary (only scalar values) to crumple
1046
- *
1047
- * Takes a flat dictionary whose keys use '.' separator to indicate
1048
- * nesting, and values are scalars, and crumples it into a nested
1049
- * structure.
1050
- *
1051
- * To include a literal '.' in a key name, it must be escaped as '..'
1052
- *
1053
- * For example, an input of:
1054
- *
1055
- * { 'foo.0.bar': 'one', 'foo.0.wizz': '1',
1056
- * 'foo.1.bar': 'two', 'foo.1.wizz': '2' }
1057
- *
1058
- * will result in an output of:
1059
- *
1060
- * {
1061
- * 'foo': [
1062
- * { 'bar': 'one', 'wizz': '1' },
1063
- * { 'bar': 'two', 'wizz': '2' }
1064
- * ],
1065
- * }
1066
- *
1067
- * The following scenarios in the input dict will result in an
1068
- * error being returned:
1069
- *
1070
- * - Any values in @src are non-scalar types
1071
- * - If keys in @src imply that a particular level is both a
1072
- * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar".
1073
- * - If keys in @src imply that a particular level is a list,
1074
- * but the indices are non-contiguous. e.g. "foo.0.bar" and
1075
- * "foo.2.bar" without any "foo.1.bar" present.
1076
- * - If keys in @src represent list indexes, but are not in
1077
- * the "%zu" format. e.g. "foo.+0.bar"
1078
- *
1079
- * Returns: either a QDict or QList for the nested data structure, or NULL
1080
- * on error
1081
- */
1082
-QObject *qdict_crumple(const QDict *src, Error **errp)
1083
-{
1084
- const QDictEntry *ent;
1085
- QDict *two_level, *multi_level = NULL;
1086
- QObject *dst = NULL, *child;
1087
- size_t i;
1088
- char *prefix = NULL;
1089
- const char *suffix = NULL;
1090
- int is_list;
1091
-
1092
- two_level = qdict_new();
1093
-
1094
- /* Step 1: split our totally flat dict into a two level dict */
1095
- for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) {
1096
- if (qobject_type(ent->value) == QTYPE_QDICT ||
1097
- qobject_type(ent->value) == QTYPE_QLIST) {
1098
- error_setg(errp, "Value %s is not a scalar",
1099
- ent->key);
1100
- goto error;
1101
- }
1102
-
1103
- qdict_split_flat_key(ent->key, &prefix, &suffix);
1104
-
1105
- child = qdict_get(two_level, prefix);
1106
- if (suffix) {
1107
- QDict *child_dict = qobject_to(QDict, child);
1108
- if (!child_dict) {
1109
- if (child) {
1110
- error_setg(errp, "Key %s prefix is already set as a scalar",
1111
- prefix);
1112
- goto error;
1113
- }
1114
-
1115
- child_dict = qdict_new();
1116
- qdict_put_obj(two_level, prefix, QOBJECT(child_dict));
1117
- }
1118
-
1119
- qdict_put_obj(child_dict, suffix, qobject_ref(ent->value));
1120
- } else {
1121
- if (child) {
1122
- error_setg(errp, "Key %s prefix is already set as a dict",
1123
- prefix);
1124
- goto error;
1125
- }
1126
- qdict_put_obj(two_level, prefix, qobject_ref(ent->value));
1127
- }
1128
-
1129
- g_free(prefix);
1130
- prefix = NULL;
1131
- }
1132
-
1133
- /* Step 2: optionally process the two level dict recursively
1134
- * into a multi-level dict */
1135
- multi_level = qdict_new();
1136
- for (ent = qdict_first(two_level); ent != NULL;
1137
- ent = qdict_next(two_level, ent)) {
1138
- QDict *dict = qobject_to(QDict, ent->value);
1139
- if (dict) {
1140
- child = qdict_crumple(dict, errp);
1141
- if (!child) {
1142
- goto error;
1143
- }
1144
-
1145
- qdict_put_obj(multi_level, ent->key, child);
1146
- } else {
1147
- qdict_put_obj(multi_level, ent->key, qobject_ref(ent->value));
1148
- }
1149
- }
1150
- qobject_unref(two_level);
1151
- two_level = NULL;
1152
-
1153
- /* Step 3: detect if we need to turn our dict into list */
1154
- is_list = qdict_is_list(multi_level, errp);
1155
- if (is_list < 0) {
1156
- goto error;
1157
- }
1158
-
1159
- if (is_list) {
1160
- dst = QOBJECT(qlist_new());
1161
-
1162
- for (i = 0; i < qdict_size(multi_level); i++) {
1163
- char *key = g_strdup_printf("%zu", i);
1164
-
1165
- child = qdict_get(multi_level, key);
1166
- g_free(key);
1167
-
1168
- if (!child) {
1169
- error_setg(errp, "Missing list index %zu", i);
1170
- goto error;
1171
- }
1172
-
1173
- qlist_append_obj(qobject_to(QList, dst), qobject_ref(child));
1174
- }
1175
- qobject_unref(multi_level);
1176
- multi_level = NULL;
1177
- } else {
1178
- dst = QOBJECT(multi_level);
1179
- }
1180
-
1181
- return dst;
1182
-
1183
- error:
1184
- g_free(prefix);
1185
- qobject_unref(multi_level);
1186
- qobject_unref(two_level);
1187
- qobject_unref(dst);
1188
- return NULL;
1189
-}
1190
-
1191
-/**
1192
- * qdict_array_entries(): Returns the number of direct array entries if the
1193
- * sub-QDict of src specified by the prefix in subqdict (or src itself for
1194
- * prefix == "") is valid as an array, i.e. the length of the created list if
1195
- * the sub-QDict would become empty after calling qdict_array_split() on it. If
1196
- * the array is not valid, -EINVAL is returned.
1197
- */
1198
-int qdict_array_entries(QDict *src, const char *subqdict)
1199
-{
1200
- const QDictEntry *entry;
1201
- unsigned i;
1202
- unsigned entries = 0;
1203
- size_t subqdict_len = strlen(subqdict);
1204
-
1205
- assert(!subqdict_len || subqdict[subqdict_len - 1] == '.');
1206
-
1207
- /* qdict_array_split() loops until UINT_MAX, but as we want to return
1208
- * negative errors, we only have a signed return value here. Any additional
1209
- * entries will lead to -EINVAL. */
1210
- for (i = 0; i < INT_MAX; i++) {
1211
- QObject *subqobj;
1212
- int subqdict_entries;
1213
- char *prefix = g_strdup_printf("%s%u.", subqdict, i);
1214
-
1215
- subqdict_entries = qdict_count_prefixed_entries(src, prefix);
1216
-
1217
- /* Remove ending "." */
1218
- prefix[strlen(prefix) - 1] = 0;
1219
- subqobj = qdict_get(src, prefix);
1220
-
1221
- g_free(prefix);
1222
-
1223
- if (subqdict_entries < 0) {
1224
- return subqdict_entries;
1225
- }
1226
-
1227
- /* There may be either a single subordinate object (named "%u") or
1228
- * multiple objects (each with a key prefixed "%u."), but not both. */
1229
- if (subqobj && subqdict_entries) {
1230
- return -EINVAL;
1231
- } else if (!subqobj && !subqdict_entries) {
1232
- break;
1233
- }
1234
-
1235
- entries += subqdict_entries ? subqdict_entries : 1;
1236
- }
1237
-
1238
- /* Consider everything handled that isn't part of the given sub-QDict */
1239
- for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
1240
- if (!strstart(qdict_entry_key(entry), subqdict, NULL)) {
1241
- entries++;
1242
- }
1243
- }
1244
-
1245
- /* Anything left in the sub-QDict that wasn't handled? */
1246
- if (qdict_size(src) != entries) {
1247
- return -EINVAL;
1248
- }
1249
-
1250
- return i;
1251
-}
1252
-
1253
-/**
1254
- * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
1255
- * elements from src to dest.
1256
- *
1257
- * If an element from src has a key already present in dest, it will not be
1258
- * moved unless overwrite is true.
1259
- *
1260
- * If overwrite is true, the conflicting values in dest will be discarded and
1261
- * replaced by the corresponding values from src.
1262
- *
1263
- * Therefore, with overwrite being true, the src QDict will always be empty when
1264
- * this function returns. If overwrite is false, the src QDict will be empty
1265
- * iff there were no conflicts.
1266
- */
1267
-void qdict_join(QDict *dest, QDict *src, bool overwrite)
1268
-{
1269
- const QDictEntry *entry, *next;
1270
-
1271
- entry = qdict_first(src);
1272
- while (entry) {
1273
- next = qdict_next(src, entry);
1274
-
1275
- if (overwrite || !qdict_haskey(dest, entry->key)) {
1276
- qdict_put_obj(dest, entry->key, qobject_ref(entry->value));
1277
- qdict_del(src, entry->key);
1278
- }
1279
-
1280
- entry = next;
1281
- }
1282
-}
1283
-
1284
-/**
1285
- * qdict_rename_keys(): Rename keys in qdict according to the replacements
1286
- * specified in the array renames. The array must be terminated by an entry
1287
- * with from = NULL.
1288
- *
1289
- * The renames are performed individually in the order of the array, so entries
1290
- * may be renamed multiple times and may or may not conflict depending on the
1291
- * order of the renames array.
1292
- *
1293
- * Returns true for success, false in error cases.
1294
- */
1295
-bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
1296
-{
1297
- QObject *qobj;
1298
-
1299
- while (renames->from) {
1300
- if (qdict_haskey(qdict, renames->from)) {
1301
- if (qdict_haskey(qdict, renames->to)) {
1302
- error_setg(errp, "'%s' and its alias '%s' can't be used at the "
1303
- "same time", renames->to, renames->from);
1304
- return false;
1305
- }
1306
-
1307
- qobj = qdict_get(qdict, renames->from);
1308
- qdict_put_obj(qdict, renames->to, qobject_ref(qobj));
1309
- qdict_del(qdict, renames->from);
1310
- }
1311
-
1312
- renames++;
1313
- }
1314
- return true;
1315
-}
1316
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
1317
new file mode 100644
1318
index XXXXXXX..XXXXXXX
1319
--- /dev/null
1320
+++ b/tests/check-block-qdict.c
1321
@@ -XXX,XX +XXX,XX @@
1322
+/*
1323
+ * Unit-tests for Block layer QDict extras
1324
+ *
1325
+ * Copyright (c) 2013-2018 Red Hat, Inc.
1326
+ *
1327
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
1328
+ * See the COPYING.LIB file in the top-level directory.
1329
+ */
1330
+
1331
+#include "qemu/osdep.h"
1332
+#include "block/qdict.h"
1333
+#include "qapi/qmp/qlist.h"
1334
+#include "qapi/qmp/qnum.h"
1335
+#include "qapi/error.h"
1336
+
1337
+static void qdict_defaults_test(void)
1338
+{
1339
+ QDict *dict, *copy;
1340
+
1341
+ dict = qdict_new();
1342
+ copy = qdict_new();
1343
+
1344
+ qdict_set_default_str(dict, "foo", "abc");
1345
+ qdict_set_default_str(dict, "foo", "def");
1346
+ g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "abc");
1347
+ qdict_set_default_str(dict, "bar", "ghi");
1348
+
1349
+ qdict_copy_default(copy, dict, "foo");
1350
+ g_assert_cmpstr(qdict_get_str(copy, "foo"), ==, "abc");
1351
+ qdict_set_default_str(copy, "bar", "xyz");
1352
+ qdict_copy_default(copy, dict, "bar");
1353
+ g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz");
1354
+
1355
+ qobject_unref(copy);
1356
+ qobject_unref(dict);
1357
+}
1358
+
1359
+static void qdict_flatten_test(void)
1360
+{
1361
+ QList *list1 = qlist_new();
1362
+ QList *list2 = qlist_new();
1363
+ QDict *dict1 = qdict_new();
1364
+ QDict *dict2 = qdict_new();
1365
+ QDict *dict3 = qdict_new();
1366
+
1367
+ /*
1368
+ * Test the flattening of
1369
+ *
1370
+ * {
1371
+ * "e": [
1372
+ * 42,
1373
+ * [
1374
+ * 23,
1375
+ * 66,
1376
+ * {
1377
+ * "a": 0,
1378
+ * "b": 1
1379
+ * }
1380
+ * ]
1381
+ * ],
1382
+ * "f": {
1383
+ * "c": 2,
1384
+ * "d": 3,
1385
+ * },
1386
+ * "g": 4
1387
+ * }
1388
+ *
1389
+ * to
1390
+ *
1391
+ * {
1392
+ * "e.0": 42,
1393
+ * "e.1.0": 23,
1394
+ * "e.1.1": 66,
1395
+ * "e.1.2.a": 0,
1396
+ * "e.1.2.b": 1,
1397
+ * "f.c": 2,
1398
+ * "f.d": 3,
1399
+ * "g": 4
1400
+ * }
1401
+ */
1402
+
1403
+ qdict_put_int(dict1, "a", 0);
1404
+ qdict_put_int(dict1, "b", 1);
1405
+
1406
+ qlist_append_int(list1, 23);
1407
+ qlist_append_int(list1, 66);
1408
+ qlist_append(list1, dict1);
1409
+ qlist_append_int(list2, 42);
1410
+ qlist_append(list2, list1);
1411
+
1412
+ qdict_put_int(dict2, "c", 2);
1413
+ qdict_put_int(dict2, "d", 3);
1414
+ qdict_put(dict3, "e", list2);
1415
+ qdict_put(dict3, "f", dict2);
1416
+ qdict_put_int(dict3, "g", 4);
1417
+
1418
+ qdict_flatten(dict3);
1419
+
1420
+ g_assert(qdict_get_int(dict3, "e.0") == 42);
1421
+ g_assert(qdict_get_int(dict3, "e.1.0") == 23);
1422
+ g_assert(qdict_get_int(dict3, "e.1.1") == 66);
1423
+ g_assert(qdict_get_int(dict3, "e.1.2.a") == 0);
1424
+ g_assert(qdict_get_int(dict3, "e.1.2.b") == 1);
1425
+ g_assert(qdict_get_int(dict3, "f.c") == 2);
1426
+ g_assert(qdict_get_int(dict3, "f.d") == 3);
1427
+ g_assert(qdict_get_int(dict3, "g") == 4);
1428
+
1429
+ g_assert(qdict_size(dict3) == 8);
1430
+
1431
+ qobject_unref(dict3);
1432
+}
1433
+
1434
+static void qdict_array_split_test(void)
1435
+{
1436
+ QDict *test_dict = qdict_new();
1437
+ QDict *dict1, *dict2;
1438
+ QNum *int1;
1439
+ QList *test_list;
1440
+
1441
+ /*
1442
+ * Test the split of
1443
+ *
1444
+ * {
1445
+ * "1.x": 0,
1446
+ * "4.y": 1,
1447
+ * "0.a": 42,
1448
+ * "o.o": 7,
1449
+ * "0.b": 23,
1450
+ * "2": 66
1451
+ * }
1452
+ *
1453
+ * to
1454
+ *
1455
+ * [
1456
+ * {
1457
+ * "a": 42,
1458
+ * "b": 23
1459
+ * },
1460
+ * {
1461
+ * "x": 0
1462
+ * },
1463
+ * 66
1464
+ * ]
1465
+ *
1466
+ * and
1467
+ *
1468
+ * {
1469
+ * "4.y": 1,
1470
+ * "o.o": 7
1471
+ * }
1472
+ *
1473
+ * (remaining in the old QDict)
1474
+ *
1475
+ * This example is given in the comment of qdict_array_split().
1476
+ */
1477
+
1478
+ qdict_put_int(test_dict, "1.x", 0);
1479
+ qdict_put_int(test_dict, "4.y", 1);
1480
+ qdict_put_int(test_dict, "0.a", 42);
1481
+ qdict_put_int(test_dict, "o.o", 7);
1482
+ qdict_put_int(test_dict, "0.b", 23);
1483
+ qdict_put_int(test_dict, "2", 66);
1484
+
1485
+ qdict_array_split(test_dict, &test_list);
1486
+
1487
+ dict1 = qobject_to(QDict, qlist_pop(test_list));
1488
+ dict2 = qobject_to(QDict, qlist_pop(test_list));
1489
+ int1 = qobject_to(QNum, qlist_pop(test_list));
1490
+
1491
+ g_assert(dict1);
1492
+ g_assert(dict2);
1493
+ g_assert(int1);
1494
+ g_assert(qlist_empty(test_list));
1495
+
1496
+ qobject_unref(test_list);
1497
+
1498
+ g_assert(qdict_get_int(dict1, "a") == 42);
1499
+ g_assert(qdict_get_int(dict1, "b") == 23);
1500
+
1501
+ g_assert(qdict_size(dict1) == 2);
1502
+
1503
+ qobject_unref(dict1);
1504
+
1505
+ g_assert(qdict_get_int(dict2, "x") == 0);
1506
+
1507
+ g_assert(qdict_size(dict2) == 1);
1508
+
1509
+ qobject_unref(dict2);
1510
+
1511
+ g_assert_cmpint(qnum_get_int(int1), ==, 66);
1512
+
1513
+ qobject_unref(int1);
1514
+
1515
+ g_assert(qdict_get_int(test_dict, "4.y") == 1);
1516
+ g_assert(qdict_get_int(test_dict, "o.o") == 7);
1517
+
1518
+ g_assert(qdict_size(test_dict) == 2);
1519
+
1520
+ qobject_unref(test_dict);
1521
+
1522
+ /*
1523
+ * Test the split of
1524
+ *
1525
+ * {
1526
+ * "0": 42,
1527
+ * "1": 23,
1528
+ * "1.x": 84
1529
+ * }
1530
+ *
1531
+ * to
1532
+ *
1533
+ * [
1534
+ * 42
1535
+ * ]
1536
+ *
1537
+ * and
1538
+ *
1539
+ * {
1540
+ * "1": 23,
1541
+ * "1.x": 84
1542
+ * }
1543
+ *
1544
+ * That is, test whether splitting stops if there is both an entry with key
1545
+ * of "%u" and other entries with keys prefixed "%u." for the same index.
1546
+ */
1547
+
1548
+ test_dict = qdict_new();
1549
+
1550
+ qdict_put_int(test_dict, "0", 42);
1551
+ qdict_put_int(test_dict, "1", 23);
1552
+ qdict_put_int(test_dict, "1.x", 84);
1553
+
1554
+ qdict_array_split(test_dict, &test_list);
1555
+
1556
+ int1 = qobject_to(QNum, qlist_pop(test_list));
1557
+
1558
+ g_assert(int1);
1559
+ g_assert(qlist_empty(test_list));
1560
+
1561
+ qobject_unref(test_list);
1562
+
1563
+ g_assert_cmpint(qnum_get_int(int1), ==, 42);
1564
+
1565
+ qobject_unref(int1);
1566
+
1567
+ g_assert(qdict_get_int(test_dict, "1") == 23);
1568
+ g_assert(qdict_get_int(test_dict, "1.x") == 84);
1569
+
1570
+ g_assert(qdict_size(test_dict) == 2);
1571
+
1572
+ qobject_unref(test_dict);
1573
+}
1574
+
1575
+static void qdict_array_entries_test(void)
1576
+{
1577
+ QDict *dict = qdict_new();
1578
+
1579
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
1580
+
1581
+ qdict_put_int(dict, "bar", 0);
1582
+ qdict_put_int(dict, "baz.0", 0);
1583
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
1584
+
1585
+ qdict_put_int(dict, "foo.1", 0);
1586
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
1587
+ qdict_put_int(dict, "foo.0", 0);
1588
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2);
1589
+ qdict_put_int(dict, "foo.bar", 0);
1590
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
1591
+ qdict_del(dict, "foo.bar");
1592
+
1593
+ qdict_put_int(dict, "foo.2.a", 0);
1594
+ qdict_put_int(dict, "foo.2.b", 0);
1595
+ qdict_put_int(dict, "foo.2.c", 0);
1596
+ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3);
1597
+ g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
1598
+
1599
+ qobject_unref(dict);
1600
+
1601
+ dict = qdict_new();
1602
+ qdict_put_int(dict, "1", 0);
1603
+ g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
1604
+ qdict_put_int(dict, "0", 0);
1605
+ g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2);
1606
+ qdict_put_int(dict, "bar", 0);
1607
+ g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
1608
+ qdict_del(dict, "bar");
1609
+
1610
+ qdict_put_int(dict, "2.a", 0);
1611
+ qdict_put_int(dict, "2.b", 0);
1612
+ qdict_put_int(dict, "2.c", 0);
1613
+ g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3);
1614
+
1615
+ qobject_unref(dict);
1616
+}
1617
+
1618
+static void qdict_join_test(void)
1619
+{
1620
+ QDict *dict1, *dict2;
1621
+ bool overwrite = false;
1622
+ int i;
1623
+
1624
+ dict1 = qdict_new();
1625
+ dict2 = qdict_new();
1626
+
1627
+ /* Test everything once without overwrite and once with */
1628
+ do {
1629
+ /* Test empty dicts */
1630
+ qdict_join(dict1, dict2, overwrite);
1631
+
1632
+ g_assert(qdict_size(dict1) == 0);
1633
+ g_assert(qdict_size(dict2) == 0);
1634
+
1635
+ /* First iteration: Test movement */
1636
+ /* Second iteration: Test empty source and non-empty destination */
1637
+ qdict_put_int(dict2, "foo", 42);
1638
+
1639
+ for (i = 0; i < 2; i++) {
1640
+ qdict_join(dict1, dict2, overwrite);
1641
+
1642
+ g_assert(qdict_size(dict1) == 1);
1643
+ g_assert(qdict_size(dict2) == 0);
1644
+
1645
+ g_assert(qdict_get_int(dict1, "foo") == 42);
1646
+ }
1647
+
1648
+ /* Test non-empty source and destination without conflict */
1649
+ qdict_put_int(dict2, "bar", 23);
1650
+
1651
+ qdict_join(dict1, dict2, overwrite);
1652
+
1653
+ g_assert(qdict_size(dict1) == 2);
1654
+ g_assert(qdict_size(dict2) == 0);
1655
+
1656
+ g_assert(qdict_get_int(dict1, "foo") == 42);
1657
+ g_assert(qdict_get_int(dict1, "bar") == 23);
1658
+
1659
+ /* Test conflict */
1660
+ qdict_put_int(dict2, "foo", 84);
1661
+
1662
+ qdict_join(dict1, dict2, overwrite);
1663
+
1664
+ g_assert(qdict_size(dict1) == 2);
1665
+ g_assert(qdict_size(dict2) == !overwrite);
1666
+
1667
+ g_assert(qdict_get_int(dict1, "foo") == (overwrite ? 84 : 42));
1668
+ g_assert(qdict_get_int(dict1, "bar") == 23);
1669
+
1670
+ if (!overwrite) {
1671
+ g_assert(qdict_get_int(dict2, "foo") == 84);
1672
+ }
1673
+
1674
+ /* Check the references */
1675
+ g_assert(qdict_get(dict1, "foo")->base.refcnt == 1);
1676
+ g_assert(qdict_get(dict1, "bar")->base.refcnt == 1);
1677
+
1678
+ if (!overwrite) {
1679
+ g_assert(qdict_get(dict2, "foo")->base.refcnt == 1);
1680
+ }
1681
+
1682
+ /* Clean up */
1683
+ qdict_del(dict1, "foo");
1684
+ qdict_del(dict1, "bar");
1685
+
1686
+ if (!overwrite) {
1687
+ qdict_del(dict2, "foo");
1688
+ }
1689
+ } while (overwrite ^= true);
1690
+
1691
+ qobject_unref(dict1);
1692
+ qobject_unref(dict2);
1693
+}
1694
+
1695
+static void qdict_crumple_test_recursive(void)
1696
+{
1697
+ QDict *src, *dst, *rule, *vnc, *acl, *listen;
1698
+ QList *rules;
1699
+
1700
+ src = qdict_new();
1701
+ qdict_put_str(src, "vnc.listen.addr", "127.0.0.1");
1702
+ qdict_put_str(src, "vnc.listen.port", "5901");
1703
+ qdict_put_str(src, "vnc.acl.rules.0.match", "fred");
1704
+ qdict_put_str(src, "vnc.acl.rules.0.policy", "allow");
1705
+ qdict_put_str(src, "vnc.acl.rules.1.match", "bob");
1706
+ qdict_put_str(src, "vnc.acl.rules.1.policy", "deny");
1707
+ qdict_put_str(src, "vnc.acl.default", "deny");
1708
+ qdict_put_str(src, "vnc.acl..name", "acl0");
1709
+ qdict_put_str(src, "vnc.acl.rule..name", "acl0");
1710
+
1711
+ dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
1712
+ g_assert(dst);
1713
+ g_assert_cmpint(qdict_size(dst), ==, 1);
1714
+
1715
+ vnc = qdict_get_qdict(dst, "vnc");
1716
+ g_assert(vnc);
1717
+ g_assert_cmpint(qdict_size(vnc), ==, 3);
1718
+
1719
+ listen = qdict_get_qdict(vnc, "listen");
1720
+ g_assert(listen);
1721
+ g_assert_cmpint(qdict_size(listen), ==, 2);
1722
+ g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr"));
1723
+ g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port"));
1724
+
1725
+ acl = qdict_get_qdict(vnc, "acl");
1726
+ g_assert(acl);
1727
+ g_assert_cmpint(qdict_size(acl), ==, 3);
1728
+
1729
+ rules = qdict_get_qlist(acl, "rules");
1730
+ g_assert(rules);
1731
+ g_assert_cmpint(qlist_size(rules), ==, 2);
1732
+
1733
+ rule = qobject_to(QDict, qlist_pop(rules));
1734
+ g_assert(rule);
1735
+ g_assert_cmpint(qdict_size(rule), ==, 2);
1736
+ g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match"));
1737
+ g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy"));
1738
+ qobject_unref(rule);
1739
+
1740
+ rule = qobject_to(QDict, qlist_pop(rules));
1741
+ g_assert(rule);
1742
+ g_assert_cmpint(qdict_size(rule), ==, 2);
1743
+ g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match"));
1744
+ g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy"));
1745
+ qobject_unref(rule);
1746
+
1747
+ /* With recursive crumpling, we should see all names unescaped */
1748
+ g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name"));
1749
+ g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name"));
1750
+
1751
+ qobject_unref(src);
1752
+ qobject_unref(dst);
1753
+}
1754
+
1755
+static void qdict_crumple_test_empty(void)
1756
+{
1757
+ QDict *src, *dst;
1758
+
1759
+ src = qdict_new();
1760
+
1761
+ dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
1762
+
1763
+ g_assert_cmpint(qdict_size(dst), ==, 0);
1764
+
1765
+ qobject_unref(src);
1766
+ qobject_unref(dst);
1767
+}
1768
+
1769
+static int qdict_count_entries(QDict *dict)
1770
+{
1771
+ const QDictEntry *e;
1772
+ int count = 0;
1773
+
1774
+ for (e = qdict_first(dict); e; e = qdict_next(dict, e)) {
1775
+ count++;
1776
+ }
1777
+
1778
+ return count;
1779
+}
1780
+
1781
+static void qdict_rename_keys_test(void)
1782
+{
1783
+ QDict *dict = qdict_new();
1784
+ QDict *copy;
1785
+ QDictRenames *renames;
1786
+ Error *local_err = NULL;
1787
+
1788
+ qdict_put_str(dict, "abc", "foo");
1789
+ qdict_put_str(dict, "abcdef", "bar");
1790
+ qdict_put_int(dict, "number", 42);
1791
+ qdict_put_bool(dict, "flag", true);
1792
+ qdict_put_null(dict, "nothing");
1793
+
1794
+ /* Empty rename list */
1795
+ renames = (QDictRenames[]) {
1796
+ { NULL, "this can be anything" }
1797
+ };
1798
+ copy = qdict_clone_shallow(dict);
1799
+ qdict_rename_keys(copy, renames, &error_abort);
1800
+
1801
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
1802
+ g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
1803
+ g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
1804
+ g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
1805
+ g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
1806
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
1807
+
1808
+ qobject_unref(copy);
1809
+
1810
+ /* Simple rename of all entries */
1811
+ renames = (QDictRenames[]) {
1812
+ { "abc", "str1" },
1813
+ { "abcdef", "str2" },
1814
+ { "number", "int" },
1815
+ { "flag", "bool" },
1816
+ { "nothing", "null" },
1817
+ { NULL , NULL }
1818
+ };
1819
+ copy = qdict_clone_shallow(dict);
1820
+ qdict_rename_keys(copy, renames, &error_abort);
1821
+
1822
+ g_assert(!qdict_haskey(copy, "abc"));
1823
+ g_assert(!qdict_haskey(copy, "abcdef"));
1824
+ g_assert(!qdict_haskey(copy, "number"));
1825
+ g_assert(!qdict_haskey(copy, "flag"));
1826
+ g_assert(!qdict_haskey(copy, "nothing"));
1827
+
1828
+ g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo");
1829
+ g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar");
1830
+ g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42);
1831
+ g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true);
1832
+ g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL);
1833
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
1834
+
1835
+ qobject_unref(copy);
1836
+
1837
+ /* Renames are processed top to bottom */
1838
+ renames = (QDictRenames[]) {
1839
+ { "abc", "tmp" },
1840
+ { "abcdef", "abc" },
1841
+ { "number", "abcdef" },
1842
+ { "flag", "number" },
1843
+ { "nothing", "flag" },
1844
+ { "tmp", "nothing" },
1845
+ { NULL , NULL }
1846
+ };
1847
+ copy = qdict_clone_shallow(dict);
1848
+ qdict_rename_keys(copy, renames, &error_abort);
1849
+
1850
+ g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo");
1851
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar");
1852
+ g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42);
1853
+ g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true);
1854
+ g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL);
1855
+ g_assert(!qdict_haskey(copy, "tmp"));
1856
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
1857
+
1858
+ qobject_unref(copy);
1859
+
1860
+ /* Conflicting rename */
1861
+ renames = (QDictRenames[]) {
1862
+ { "abcdef", "abc" },
1863
+ { NULL , NULL }
1864
+ };
1865
+ copy = qdict_clone_shallow(dict);
1866
+ qdict_rename_keys(copy, renames, &local_err);
1867
+
1868
+ g_assert(local_err != NULL);
1869
+ error_free(local_err);
1870
+ local_err = NULL;
1871
+
1872
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
1873
+ g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
1874
+ g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
1875
+ g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
1876
+ g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
1877
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
1878
+
1879
+ qobject_unref(copy);
1880
+
1881
+ /* Renames in an empty dict */
1882
+ renames = (QDictRenames[]) {
1883
+ { "abcdef", "abc" },
1884
+ { NULL , NULL }
1885
+ };
1886
+
1887
+ qobject_unref(dict);
1888
+ dict = qdict_new();
1889
+
1890
+ qdict_rename_keys(dict, renames, &error_abort);
1891
+ g_assert(qdict_first(dict) == NULL);
1892
+
1893
+ qobject_unref(dict);
1894
+}
1895
+
1896
+static void qdict_crumple_test_bad_inputs(void)
1897
+{
1898
+ QDict *src;
1899
+ Error *error = NULL;
1900
+
1901
+ src = qdict_new();
1902
+ /* rule.0 can't be both a string and a dict */
1903
+ qdict_put_str(src, "rule.0", "fred");
1904
+ qdict_put_str(src, "rule.0.policy", "allow");
1905
+
1906
+ g_assert(qdict_crumple(src, &error) == NULL);
1907
+ g_assert(error != NULL);
1908
+ error_free(error);
1909
+ error = NULL;
1910
+ qobject_unref(src);
1911
+
1912
+ src = qdict_new();
1913
+ /* rule can't be both a list and a dict */
1914
+ qdict_put_str(src, "rule.0", "fred");
1915
+ qdict_put_str(src, "rule.a", "allow");
1916
+
1917
+ g_assert(qdict_crumple(src, &error) == NULL);
1918
+ g_assert(error != NULL);
1919
+ error_free(error);
1920
+ error = NULL;
1921
+ qobject_unref(src);
1922
+
1923
+ src = qdict_new();
1924
+ /* The input should be flat, ie no dicts or lists */
1925
+ qdict_put(src, "rule.a", qdict_new());
1926
+ qdict_put_str(src, "rule.b", "allow");
1927
+
1928
+ g_assert(qdict_crumple(src, &error) == NULL);
1929
+ g_assert(error != NULL);
1930
+ error_free(error);
1931
+ error = NULL;
1932
+ qobject_unref(src);
1933
+
1934
+ src = qdict_new();
1935
+ /* List indexes must not have gaps */
1936
+ qdict_put_str(src, "rule.0", "deny");
1937
+ qdict_put_str(src, "rule.3", "allow");
1938
+
1939
+ g_assert(qdict_crumple(src, &error) == NULL);
1940
+ g_assert(error != NULL);
1941
+ error_free(error);
1942
+ error = NULL;
1943
+ qobject_unref(src);
1944
+
1945
+ src = qdict_new();
1946
+ /* List indexes must be in %zu format */
1947
+ qdict_put_str(src, "rule.0", "deny");
1948
+ qdict_put_str(src, "rule.+1", "allow");
1949
+
1950
+ g_assert(qdict_crumple(src, &error) == NULL);
1951
+ g_assert(error != NULL);
1952
+ error_free(error);
1953
+ error = NULL;
1954
+ qobject_unref(src);
1955
+}
1956
+
1957
+int main(int argc, char **argv)
1958
+{
1959
+ g_test_init(&argc, &argv, NULL);
1960
+
1961
+ g_test_add_func("/public/defaults", qdict_defaults_test);
1962
+ g_test_add_func("/public/flatten", qdict_flatten_test);
1963
+ g_test_add_func("/public/array_split", qdict_array_split_test);
1964
+ g_test_add_func("/public/array_entries", qdict_array_entries_test);
1965
+ g_test_add_func("/public/join", qdict_join_test);
1966
+ g_test_add_func("/public/crumple/recursive",
1967
+ qdict_crumple_test_recursive);
1968
+ g_test_add_func("/public/crumple/empty",
1969
+ qdict_crumple_test_empty);
1970
+ g_test_add_func("/public/crumple/bad_inputs",
1971
+ qdict_crumple_test_bad_inputs);
1972
+
1973
+ g_test_add_func("/public/rename_keys", qdict_rename_keys_test);
1974
+
1975
+ return g_test_run();
1976
+}
1977
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
1978
index XXXXXXX..XXXXXXX 100644
1979
--- a/tests/check-qdict.c
1980
+++ b/tests/check-qdict.c
1981
@@ -XXX,XX +XXX,XX @@
1982
*/
1983
1984
#include "qemu/osdep.h"
1985
-#include "block/qdict.h"
1986
#include "qapi/qmp/qdict.h"
1987
-#include "qapi/qmp/qlist.h"
1988
-#include "qapi/qmp/qnum.h"
1989
-#include "qapi/qmp/qstring.h"
1990
-#include "qapi/error.h"
1991
-#include "qemu-common.h"
1992
1993
/*
1994
* Public Interface test-cases
1995
@@ -XXX,XX +XXX,XX @@ static void qdict_get_try_str_test(void)
1996
qobject_unref(tests_dict);
1997
}
1998
1999
-static void qdict_defaults_test(void)
2000
-{
2001
- QDict *dict, *copy;
2002
-
2003
- dict = qdict_new();
2004
- copy = qdict_new();
2005
-
2006
- qdict_set_default_str(dict, "foo", "abc");
2007
- qdict_set_default_str(dict, "foo", "def");
2008
- g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "abc");
2009
- qdict_set_default_str(dict, "bar", "ghi");
2010
-
2011
- qdict_copy_default(copy, dict, "foo");
2012
- g_assert_cmpstr(qdict_get_str(copy, "foo"), ==, "abc");
2013
- qdict_set_default_str(copy, "bar", "xyz");
2014
- qdict_copy_default(copy, dict, "bar");
2015
- g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz");
2016
-
2017
- qobject_unref(copy);
2018
- qobject_unref(dict);
2019
-}
2020
-
2021
static void qdict_haskey_not_test(void)
2022
{
2023
QDict *tests_dict = qdict_new();
2024
@@ -XXX,XX +XXX,XX @@ static void qdict_iterapi_test(void)
2025
qobject_unref(tests_dict);
2026
}
2027
2028
-static void qdict_flatten_test(void)
2029
-{
2030
- QList *list1 = qlist_new();
2031
- QList *list2 = qlist_new();
2032
- QDict *dict1 = qdict_new();
2033
- QDict *dict2 = qdict_new();
2034
- QDict *dict3 = qdict_new();
2035
-
2036
- /*
2037
- * Test the flattening of
2038
- *
2039
- * {
2040
- * "e": [
2041
- * 42,
2042
- * [
2043
- * 23,
2044
- * 66,
2045
- * {
2046
- * "a": 0,
2047
- * "b": 1
2048
- * }
2049
- * ]
2050
- * ],
2051
- * "f": {
2052
- * "c": 2,
2053
- * "d": 3,
2054
- * },
2055
- * "g": 4
2056
- * }
2057
- *
2058
- * to
2059
- *
2060
- * {
2061
- * "e.0": 42,
2062
- * "e.1.0": 23,
2063
- * "e.1.1": 66,
2064
- * "e.1.2.a": 0,
2065
- * "e.1.2.b": 1,
2066
- * "f.c": 2,
2067
- * "f.d": 3,
2068
- * "g": 4
2069
- * }
2070
- */
2071
-
2072
- qdict_put_int(dict1, "a", 0);
2073
- qdict_put_int(dict1, "b", 1);
2074
-
2075
- qlist_append_int(list1, 23);
2076
- qlist_append_int(list1, 66);
2077
- qlist_append(list1, dict1);
2078
- qlist_append_int(list2, 42);
2079
- qlist_append(list2, list1);
2080
-
2081
- qdict_put_int(dict2, "c", 2);
2082
- qdict_put_int(dict2, "d", 3);
2083
- qdict_put(dict3, "e", list2);
2084
- qdict_put(dict3, "f", dict2);
2085
- qdict_put_int(dict3, "g", 4);
2086
-
2087
- qdict_flatten(dict3);
2088
-
2089
- g_assert(qdict_get_int(dict3, "e.0") == 42);
2090
- g_assert(qdict_get_int(dict3, "e.1.0") == 23);
2091
- g_assert(qdict_get_int(dict3, "e.1.1") == 66);
2092
- g_assert(qdict_get_int(dict3, "e.1.2.a") == 0);
2093
- g_assert(qdict_get_int(dict3, "e.1.2.b") == 1);
2094
- g_assert(qdict_get_int(dict3, "f.c") == 2);
2095
- g_assert(qdict_get_int(dict3, "f.d") == 3);
2096
- g_assert(qdict_get_int(dict3, "g") == 4);
2097
-
2098
- g_assert(qdict_size(dict3) == 8);
2099
-
2100
- qobject_unref(dict3);
2101
-}
2102
-
2103
-static void qdict_array_split_test(void)
2104
-{
2105
- QDict *test_dict = qdict_new();
2106
- QDict *dict1, *dict2;
2107
- QNum *int1;
2108
- QList *test_list;
2109
-
2110
- /*
2111
- * Test the split of
2112
- *
2113
- * {
2114
- * "1.x": 0,
2115
- * "4.y": 1,
2116
- * "0.a": 42,
2117
- * "o.o": 7,
2118
- * "0.b": 23,
2119
- * "2": 66
2120
- * }
2121
- *
2122
- * to
2123
- *
2124
- * [
2125
- * {
2126
- * "a": 42,
2127
- * "b": 23
2128
- * },
2129
- * {
2130
- * "x": 0
2131
- * },
2132
- * 66
2133
- * ]
2134
- *
2135
- * and
2136
- *
2137
- * {
2138
- * "4.y": 1,
2139
- * "o.o": 7
2140
- * }
2141
- *
2142
- * (remaining in the old QDict)
2143
- *
2144
- * This example is given in the comment of qdict_array_split().
2145
- */
2146
-
2147
- qdict_put_int(test_dict, "1.x", 0);
2148
- qdict_put_int(test_dict, "4.y", 1);
2149
- qdict_put_int(test_dict, "0.a", 42);
2150
- qdict_put_int(test_dict, "o.o", 7);
2151
- qdict_put_int(test_dict, "0.b", 23);
2152
- qdict_put_int(test_dict, "2", 66);
2153
-
2154
- qdict_array_split(test_dict, &test_list);
2155
-
2156
- dict1 = qobject_to(QDict, qlist_pop(test_list));
2157
- dict2 = qobject_to(QDict, qlist_pop(test_list));
2158
- int1 = qobject_to(QNum, qlist_pop(test_list));
2159
-
2160
- g_assert(dict1);
2161
- g_assert(dict2);
2162
- g_assert(int1);
2163
- g_assert(qlist_empty(test_list));
2164
-
2165
- qobject_unref(test_list);
2166
-
2167
- g_assert(qdict_get_int(dict1, "a") == 42);
2168
- g_assert(qdict_get_int(dict1, "b") == 23);
2169
-
2170
- g_assert(qdict_size(dict1) == 2);
2171
-
2172
- qobject_unref(dict1);
2173
-
2174
- g_assert(qdict_get_int(dict2, "x") == 0);
2175
-
2176
- g_assert(qdict_size(dict2) == 1);
2177
-
2178
- qobject_unref(dict2);
2179
-
2180
- g_assert_cmpint(qnum_get_int(int1), ==, 66);
2181
-
2182
- qobject_unref(int1);
2183
-
2184
- g_assert(qdict_get_int(test_dict, "4.y") == 1);
2185
- g_assert(qdict_get_int(test_dict, "o.o") == 7);
2186
-
2187
- g_assert(qdict_size(test_dict) == 2);
2188
-
2189
- qobject_unref(test_dict);
2190
-
2191
- /*
2192
- * Test the split of
2193
- *
2194
- * {
2195
- * "0": 42,
2196
- * "1": 23,
2197
- * "1.x": 84
2198
- * }
2199
- *
2200
- * to
2201
- *
2202
- * [
2203
- * 42
2204
- * ]
2205
- *
2206
- * and
2207
- *
2208
- * {
2209
- * "1": 23,
2210
- * "1.x": 84
2211
- * }
2212
- *
2213
- * That is, test whether splitting stops if there is both an entry with key
2214
- * of "%u" and other entries with keys prefixed "%u." for the same index.
2215
- */
2216
-
2217
- test_dict = qdict_new();
2218
-
2219
- qdict_put_int(test_dict, "0", 42);
2220
- qdict_put_int(test_dict, "1", 23);
2221
- qdict_put_int(test_dict, "1.x", 84);
2222
-
2223
- qdict_array_split(test_dict, &test_list);
2224
-
2225
- int1 = qobject_to(QNum, qlist_pop(test_list));
2226
-
2227
- g_assert(int1);
2228
- g_assert(qlist_empty(test_list));
2229
-
2230
- qobject_unref(test_list);
2231
-
2232
- g_assert_cmpint(qnum_get_int(int1), ==, 42);
2233
-
2234
- qobject_unref(int1);
2235
-
2236
- g_assert(qdict_get_int(test_dict, "1") == 23);
2237
- g_assert(qdict_get_int(test_dict, "1.x") == 84);
2238
-
2239
- g_assert(qdict_size(test_dict) == 2);
2240
-
2241
- qobject_unref(test_dict);
2242
-}
2243
-
2244
-static void qdict_array_entries_test(void)
2245
-{
2246
- QDict *dict = qdict_new();
2247
-
2248
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
2249
-
2250
- qdict_put_int(dict, "bar", 0);
2251
- qdict_put_int(dict, "baz.0", 0);
2252
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
2253
-
2254
- qdict_put_int(dict, "foo.1", 0);
2255
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
2256
- qdict_put_int(dict, "foo.0", 0);
2257
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2);
2258
- qdict_put_int(dict, "foo.bar", 0);
2259
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
2260
- qdict_del(dict, "foo.bar");
2261
-
2262
- qdict_put_int(dict, "foo.2.a", 0);
2263
- qdict_put_int(dict, "foo.2.b", 0);
2264
- qdict_put_int(dict, "foo.2.c", 0);
2265
- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3);
2266
- g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
2267
-
2268
- qobject_unref(dict);
2269
-
2270
- dict = qdict_new();
2271
- qdict_put_int(dict, "1", 0);
2272
- g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
2273
- qdict_put_int(dict, "0", 0);
2274
- g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2);
2275
- qdict_put_int(dict, "bar", 0);
2276
- g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
2277
- qdict_del(dict, "bar");
2278
-
2279
- qdict_put_int(dict, "2.a", 0);
2280
- qdict_put_int(dict, "2.b", 0);
2281
- qdict_put_int(dict, "2.c", 0);
2282
- g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3);
2283
-
2284
- qobject_unref(dict);
2285
-}
2286
-
2287
-static void qdict_join_test(void)
2288
-{
2289
- QDict *dict1, *dict2;
2290
- bool overwrite = false;
2291
- int i;
2292
-
2293
- dict1 = qdict_new();
2294
- dict2 = qdict_new();
2295
-
2296
- /* Test everything once without overwrite and once with */
2297
- do
2298
- {
2299
- /* Test empty dicts */
2300
- qdict_join(dict1, dict2, overwrite);
2301
-
2302
- g_assert(qdict_size(dict1) == 0);
2303
- g_assert(qdict_size(dict2) == 0);
2304
-
2305
- /* First iteration: Test movement */
2306
- /* Second iteration: Test empty source and non-empty destination */
2307
- qdict_put_int(dict2, "foo", 42);
2308
-
2309
- for (i = 0; i < 2; i++) {
2310
- qdict_join(dict1, dict2, overwrite);
2311
-
2312
- g_assert(qdict_size(dict1) == 1);
2313
- g_assert(qdict_size(dict2) == 0);
2314
-
2315
- g_assert(qdict_get_int(dict1, "foo") == 42);
2316
- }
2317
-
2318
- /* Test non-empty source and destination without conflict */
2319
- qdict_put_int(dict2, "bar", 23);
2320
-
2321
- qdict_join(dict1, dict2, overwrite);
2322
-
2323
- g_assert(qdict_size(dict1) == 2);
2324
- g_assert(qdict_size(dict2) == 0);
2325
-
2326
- g_assert(qdict_get_int(dict1, "foo") == 42);
2327
- g_assert(qdict_get_int(dict1, "bar") == 23);
2328
-
2329
- /* Test conflict */
2330
- qdict_put_int(dict2, "foo", 84);
2331
-
2332
- qdict_join(dict1, dict2, overwrite);
2333
-
2334
- g_assert(qdict_size(dict1) == 2);
2335
- g_assert(qdict_size(dict2) == !overwrite);
2336
-
2337
- g_assert(qdict_get_int(dict1, "foo") == (overwrite ? 84 : 42));
2338
- g_assert(qdict_get_int(dict1, "bar") == 23);
2339
-
2340
- if (!overwrite) {
2341
- g_assert(qdict_get_int(dict2, "foo") == 84);
2342
- }
2343
-
2344
- /* Check the references */
2345
- g_assert(qdict_get(dict1, "foo")->base.refcnt == 1);
2346
- g_assert(qdict_get(dict1, "bar")->base.refcnt == 1);
2347
-
2348
- if (!overwrite) {
2349
- g_assert(qdict_get(dict2, "foo")->base.refcnt == 1);
2350
- }
2351
-
2352
- /* Clean up */
2353
- qdict_del(dict1, "foo");
2354
- qdict_del(dict1, "bar");
2355
-
2356
- if (!overwrite) {
2357
- qdict_del(dict2, "foo");
2358
- }
2359
- }
2360
- while (overwrite ^= true);
2361
-
2362
- qobject_unref(dict1);
2363
- qobject_unref(dict2);
2364
-}
2365
-
2366
-static void qdict_crumple_test_recursive(void)
2367
-{
2368
- QDict *src, *dst, *rule, *vnc, *acl, *listen;
2369
- QList *rules;
2370
-
2371
- src = qdict_new();
2372
- qdict_put_str(src, "vnc.listen.addr", "127.0.0.1");
2373
- qdict_put_str(src, "vnc.listen.port", "5901");
2374
- qdict_put_str(src, "vnc.acl.rules.0.match", "fred");
2375
- qdict_put_str(src, "vnc.acl.rules.0.policy", "allow");
2376
- qdict_put_str(src, "vnc.acl.rules.1.match", "bob");
2377
- qdict_put_str(src, "vnc.acl.rules.1.policy", "deny");
2378
- qdict_put_str(src, "vnc.acl.default", "deny");
2379
- qdict_put_str(src, "vnc.acl..name", "acl0");
2380
- qdict_put_str(src, "vnc.acl.rule..name", "acl0");
2381
-
2382
- dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
2383
- g_assert(dst);
2384
- g_assert_cmpint(qdict_size(dst), ==, 1);
2385
-
2386
- vnc = qdict_get_qdict(dst, "vnc");
2387
- g_assert(vnc);
2388
- g_assert_cmpint(qdict_size(vnc), ==, 3);
2389
-
2390
- listen = qdict_get_qdict(vnc, "listen");
2391
- g_assert(listen);
2392
- g_assert_cmpint(qdict_size(listen), ==, 2);
2393
- g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr"));
2394
- g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port"));
2395
-
2396
- acl = qdict_get_qdict(vnc, "acl");
2397
- g_assert(acl);
2398
- g_assert_cmpint(qdict_size(acl), ==, 3);
2399
-
2400
- rules = qdict_get_qlist(acl, "rules");
2401
- g_assert(rules);
2402
- g_assert_cmpint(qlist_size(rules), ==, 2);
2403
-
2404
- rule = qobject_to(QDict, qlist_pop(rules));
2405
- g_assert(rule);
2406
- g_assert_cmpint(qdict_size(rule), ==, 2);
2407
- g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match"));
2408
- g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy"));
2409
- qobject_unref(rule);
2410
-
2411
- rule = qobject_to(QDict, qlist_pop(rules));
2412
- g_assert(rule);
2413
- g_assert_cmpint(qdict_size(rule), ==, 2);
2414
- g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match"));
2415
- g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy"));
2416
- qobject_unref(rule);
2417
-
2418
- /* With recursive crumpling, we should see all names unescaped */
2419
- g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name"));
2420
- g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name"));
2421
-
2422
- qobject_unref(src);
2423
- qobject_unref(dst);
2424
-}
2425
-
2426
-static void qdict_crumple_test_empty(void)
2427
-{
2428
- QDict *src, *dst;
2429
-
2430
- src = qdict_new();
2431
-
2432
- dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
2433
-
2434
- g_assert_cmpint(qdict_size(dst), ==, 0);
2435
-
2436
- qobject_unref(src);
2437
- qobject_unref(dst);
2438
-}
2439
-
2440
-static int qdict_count_entries(QDict *dict)
2441
-{
2442
- const QDictEntry *e;
2443
- int count = 0;
2444
-
2445
- for (e = qdict_first(dict); e; e = qdict_next(dict, e)) {
2446
- count++;
2447
- }
2448
-
2449
- return count;
2450
-}
2451
-
2452
-static void qdict_rename_keys_test(void)
2453
-{
2454
- QDict *dict = qdict_new();
2455
- QDict *copy;
2456
- QDictRenames *renames;
2457
- Error *local_err = NULL;
2458
-
2459
- qdict_put_str(dict, "abc", "foo");
2460
- qdict_put_str(dict, "abcdef", "bar");
2461
- qdict_put_int(dict, "number", 42);
2462
- qdict_put_bool(dict, "flag", true);
2463
- qdict_put_null(dict, "nothing");
2464
-
2465
- /* Empty rename list */
2466
- renames = (QDictRenames[]) {
2467
- { NULL, "this can be anything" }
2468
- };
2469
- copy = qdict_clone_shallow(dict);
2470
- qdict_rename_keys(copy, renames, &error_abort);
2471
-
2472
- g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
2473
- g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
2474
- g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
2475
- g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
2476
- g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
2477
- g_assert_cmpint(qdict_count_entries(copy), ==, 5);
2478
-
2479
- qobject_unref(copy);
2480
-
2481
- /* Simple rename of all entries */
2482
- renames = (QDictRenames[]) {
2483
- { "abc", "str1" },
2484
- { "abcdef", "str2" },
2485
- { "number", "int" },
2486
- { "flag", "bool" },
2487
- { "nothing", "null" },
2488
- { NULL , NULL }
2489
- };
2490
- copy = qdict_clone_shallow(dict);
2491
- qdict_rename_keys(copy, renames, &error_abort);
2492
-
2493
- g_assert(!qdict_haskey(copy, "abc"));
2494
- g_assert(!qdict_haskey(copy, "abcdef"));
2495
- g_assert(!qdict_haskey(copy, "number"));
2496
- g_assert(!qdict_haskey(copy, "flag"));
2497
- g_assert(!qdict_haskey(copy, "nothing"));
2498
-
2499
- g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo");
2500
- g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar");
2501
- g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42);
2502
- g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true);
2503
- g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL);
2504
- g_assert_cmpint(qdict_count_entries(copy), ==, 5);
2505
-
2506
- qobject_unref(copy);
2507
-
2508
- /* Renames are processed top to bottom */
2509
- renames = (QDictRenames[]) {
2510
- { "abc", "tmp" },
2511
- { "abcdef", "abc" },
2512
- { "number", "abcdef" },
2513
- { "flag", "number" },
2514
- { "nothing", "flag" },
2515
- { "tmp", "nothing" },
2516
- { NULL , NULL }
2517
- };
2518
- copy = qdict_clone_shallow(dict);
2519
- qdict_rename_keys(copy, renames, &error_abort);
2520
-
2521
- g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo");
2522
- g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar");
2523
- g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42);
2524
- g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true);
2525
- g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL);
2526
- g_assert(!qdict_haskey(copy, "tmp"));
2527
- g_assert_cmpint(qdict_count_entries(copy), ==, 5);
2528
-
2529
- qobject_unref(copy);
2530
-
2531
- /* Conflicting rename */
2532
- renames = (QDictRenames[]) {
2533
- { "abcdef", "abc" },
2534
- { NULL , NULL }
2535
- };
2536
- copy = qdict_clone_shallow(dict);
2537
- qdict_rename_keys(copy, renames, &local_err);
2538
-
2539
- g_assert(local_err != NULL);
2540
- error_free(local_err);
2541
- local_err = NULL;
2542
-
2543
- g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
2544
- g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
2545
- g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
2546
- g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
2547
- g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
2548
- g_assert_cmpint(qdict_count_entries(copy), ==, 5);
2549
-
2550
- qobject_unref(copy);
2551
-
2552
- /* Renames in an empty dict */
2553
- renames = (QDictRenames[]) {
2554
- { "abcdef", "abc" },
2555
- { NULL , NULL }
2556
- };
2557
-
2558
- qobject_unref(dict);
2559
- dict = qdict_new();
2560
-
2561
- qdict_rename_keys(dict, renames, &error_abort);
2562
- g_assert(qdict_first(dict) == NULL);
2563
-
2564
- qobject_unref(dict);
2565
-}
2566
-
2567
-static void qdict_crumple_test_bad_inputs(void)
2568
-{
2569
- QDict *src;
2570
- Error *error = NULL;
2571
-
2572
- src = qdict_new();
2573
- /* rule.0 can't be both a string and a dict */
2574
- qdict_put_str(src, "rule.0", "fred");
2575
- qdict_put_str(src, "rule.0.policy", "allow");
2576
-
2577
- g_assert(qdict_crumple(src, &error) == NULL);
2578
- g_assert(error != NULL);
2579
- error_free(error);
2580
- error = NULL;
2581
- qobject_unref(src);
2582
-
2583
- src = qdict_new();
2584
- /* rule can't be both a list and a dict */
2585
- qdict_put_str(src, "rule.0", "fred");
2586
- qdict_put_str(src, "rule.a", "allow");
2587
-
2588
- g_assert(qdict_crumple(src, &error) == NULL);
2589
- g_assert(error != NULL);
2590
- error_free(error);
2591
- error = NULL;
2592
- qobject_unref(src);
2593
-
2594
- src = qdict_new();
2595
- /* The input should be flat, ie no dicts or lists */
2596
- qdict_put(src, "rule.a", qdict_new());
2597
- qdict_put_str(src, "rule.b", "allow");
2598
-
2599
- g_assert(qdict_crumple(src, &error) == NULL);
2600
- g_assert(error != NULL);
2601
- error_free(error);
2602
- error = NULL;
2603
- qobject_unref(src);
2604
-
2605
- src = qdict_new();
2606
- /* List indexes must not have gaps */
2607
- qdict_put_str(src, "rule.0", "deny");
2608
- qdict_put_str(src, "rule.3", "allow");
2609
-
2610
- g_assert(qdict_crumple(src, &error) == NULL);
2611
- g_assert(error != NULL);
2612
- error_free(error);
2613
- error = NULL;
2614
- qobject_unref(src);
2615
-
2616
- src = qdict_new();
2617
- /* List indexes must be in %zu format */
2618
- qdict_put_str(src, "rule.0", "deny");
2619
- qdict_put_str(src, "rule.+1", "allow");
2620
-
2621
- g_assert(qdict_crumple(src, &error) == NULL);
2622
- g_assert(error != NULL);
2623
- error_free(error);
2624
- error = NULL;
2625
- qobject_unref(src);
2626
-}
2627
-
2628
/*
2629
* Errors test-cases
2630
*/
2631
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
2632
g_test_add_func("/public/get_try_int", qdict_get_try_int_test);
2633
g_test_add_func("/public/get_str", qdict_get_str_test);
2634
g_test_add_func("/public/get_try_str", qdict_get_try_str_test);
2635
- g_test_add_func("/public/defaults", qdict_defaults_test);
2636
g_test_add_func("/public/haskey_not", qdict_haskey_not_test);
2637
g_test_add_func("/public/haskey", qdict_haskey_test);
2638
g_test_add_func("/public/del", qdict_del_test);
2639
g_test_add_func("/public/to_qdict", qobject_to_qdict_test);
2640
g_test_add_func("/public/iterapi", qdict_iterapi_test);
2641
- g_test_add_func("/public/flatten", qdict_flatten_test);
2642
- g_test_add_func("/public/array_split", qdict_array_split_test);
2643
- g_test_add_func("/public/array_entries", qdict_array_entries_test);
2644
- g_test_add_func("/public/join", qdict_join_test);
2645
2646
g_test_add_func("/errors/put_exists", qdict_put_exists_test);
2647
g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);
2648
2649
- g_test_add_func("/public/crumple/recursive",
2650
- qdict_crumple_test_recursive);
2651
- g_test_add_func("/public/crumple/empty",
2652
- qdict_crumple_test_empty);
2653
- g_test_add_func("/public/crumple/bad_inputs",
2654
- qdict_crumple_test_bad_inputs);
2655
-
2656
- g_test_add_func("/public/rename_keys", qdict_rename_keys_test);
2657
-
2658
/* The Big one */
2659
if (g_test_slow()) {
2660
g_test_add_func("/stress/test", qdict_stress_test);
2661
diff --git a/MAINTAINERS b/MAINTAINERS
2662
index XXXXXXX..XXXXXXX 100644
2663
--- a/MAINTAINERS
2664
+++ b/MAINTAINERS
2665
@@ -XXX,XX +XXX,XX @@ F: qemu-img*
2666
F: qemu-io*
2667
F: tests/qemu-iotests/
2668
F: util/qemu-progress.c
2669
+F: qobject/block-qdict.c
2670
+F: test/check-block-qdict.c
2671
T: git git://repo.or.cz/qemu/kevin.git block
2672
2673
Block I/O path
2674
diff --git a/qobject/Makefile.objs b/qobject/Makefile.objs
2675
index XXXXXXX..XXXXXXX 100644
2676
--- a/qobject/Makefile.objs
2677
+++ b/qobject/Makefile.objs
2678
@@ -XXX,XX +XXX,XX @@
2679
util-obj-y = qnull.o qnum.o qstring.o qdict.o qlist.o qbool.o qlit.o
2680
util-obj-y += qjson.o qobject.o json-lexer.o json-streamer.o json-parser.o
2681
+util-obj-y += block-qdict.o
2682
diff --git a/tests/Makefile.include b/tests/Makefile.include
2683
index XXXXXXX..XXXXXXX 100644
2684
--- a/tests/Makefile.include
2685
+++ b/tests/Makefile.include
2686
@@ -XXX,XX +XXX,XX @@ SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \
2687
2688
check-unit-y = tests/check-qdict$(EXESUF)
2689
gcov-files-check-qdict-y = qobject/qdict.c
2690
+check-unit-y = tests/check-block-qdict$(EXESUF)
2691
+gcov-files-check-block-qdict-y = qobject/block-qdict.c
2692
check-unit-y += tests/test-char$(EXESUF)
2693
gcov-files-check-qdict-y = chardev/char.c
2694
check-unit-y += tests/check-qnum$(EXESUF)
2695
@@ -XXX,XX +XXX,XX @@ GENERATED_FILES += tests/test-qapi-types.h tests/test-qapi-visit.h \
2696
test-obj-y = tests/check-qnum.o tests/check-qstring.o tests/check-qdict.o \
2697
    tests/check-qlist.o tests/check-qnull.o tests/check-qobject.o \
2698
    tests/check-qjson.o tests/check-qlit.o \
2699
+    tests/check-block-qtest.o \
2700
    tests/test-coroutine.o tests/test-string-output-visitor.o \
2701
    tests/test-string-input-visitor.o tests/test-qobject-output-visitor.o \
2702
    tests/test-clone-visitor.o \
2703
@@ -XXX,XX +XXX,XX @@ test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o
2704
tests/check-qnum$(EXESUF): tests/check-qnum.o $(test-util-obj-y)
2705
tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y)
2706
tests/check-qdict$(EXESUF): tests/check-qdict.o $(test-util-obj-y)
2707
+tests/check-block-qdict$(EXESUF): tests/check-block-qdict.o $(test-util-obj-y)
2708
tests/check-qlist$(EXESUF): tests/check-qlist.o $(test-util-obj-y)
2709
tests/check-qnull$(EXESUF): tests/check-qnull.o $(test-util-obj-y)
2710
tests/check-qobject$(EXESUF): tests/check-qobject.o $(test-util-obj-y)
2711
--
475
--
2712
2.13.6
476
2.20.1
2713
477
2714
478
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
Provide an option to force QEMU to always keep the external data file
2
consistent as a standalone read-only raw image.
2
3
3
Legacy -drive supports "password-secret" parameter that isn't
4
At the moment, this means making sure that write_zeroes requests are
4
available with -blockdev / blockdev-add. That's because we backed out
5
forwarded to the data file instead of just updating the metadata, and
5
our first try to provide it there due to interface design doubts, in
6
checking that no backing file is used.
6
commit 577d8c9a811, v2.9.0.
7
7
8
This is the second try. It brings back the parameter, except it's
9
named "key-secret" now.
10
11
Let's review our reasons for backing out the first try, as stated in
12
the commit message:
13
14
* BlockdevOptionsRbd member @password-secret isn't actually a
15
password, it's a key generated by Ceph.
16
17
Addressed by the rename.
18
19
* We're not sure where member @password-secret belongs (see the
20
previous commit).
21
22
See previous commit.
23
24
* How @password-secret interacts with settings from a configuration
25
file specified with @conf is undocumented.
26
27
Not actually true, the documentation for @conf says "Values in the
28
configuration file will be overridden by options specified via QAPI",
29
and we've tested this.
30
31
Signed-off-by: Markus Armbruster <armbru@redhat.com>
32
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
33
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
---
9
---
35
qapi/block-core.json | 6 ++++++
10
qapi/block-core.json | 9 ++++++
36
block/rbd.c | 41 +++++++++++++++++++++++++----------------
11
block/qcow2.h | 9 +++++-
37
2 files changed, 31 insertions(+), 16 deletions(-)
12
include/block/block_int.h | 1 +
13
block/qcow2-cluster.c | 10 +++++++
14
block/qcow2.c | 56 ++++++++++++++++++++++++++++++++++++--
15
tests/qemu-iotests/082.out | 27 ++++++++++++++++++
16
6 files changed, 109 insertions(+), 3 deletions(-)
38
17
39
diff --git a/qapi/block-core.json b/qapi/block-core.json
18
diff --git a/qapi/block-core.json b/qapi/block-core.json
40
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
41
--- a/qapi/block-core.json
20
--- a/qapi/block-core.json
42
+++ b/qapi/block-core.json
21
+++ b/qapi/block-core.json
43
@@ -XXX,XX +XXX,XX @@
22
@@ -XXX,XX +XXX,XX @@
44
# This maps to Ceph configuration option
23
# @data-file: the filename of the external data file that is stored in the
45
# "auth_client_required". (Since 3.0)
24
# image and used as a default for opening the image (since: 4.0)
46
#
25
#
47
+# @key-secret: ID of a QCryptoSecret object providing a key
26
+# @data-file-raw: True if the external data file must stay valid as a
48
+# for cephx authentication.
27
+# standalone (read-only) raw image without looking at qcow2
49
+# This maps to Ceph configuration option
28
+# metadata (since: 4.0)
50
+# "key". (Since 3.0)
51
+#
29
+#
52
# @server: Monitor host address and port. This maps
30
# @lazy-refcounts: on or off; only valid for compat >= 1.1
53
# to the "mon_host" Ceph option.
54
#
31
#
32
# @corrupt: true if the image has been marked corrupt; only valid for
55
@@ -XXX,XX +XXX,XX @@
33
@@ -XXX,XX +XXX,XX @@
56
'*snapshot': 'str',
34
'data': {
57
'*user': 'str',
35
'compat': 'str',
58
'*auth-client-required': ['RbdAuthMode'],
36
'*data-file': 'str',
59
+ '*key-secret': 'str',
37
+ '*data-file-raw': 'bool',
60
'*server': ['InetSocketAddressBase'] } }
38
'*lazy-refcounts': 'bool',
61
39
'*corrupt': 'bool',
62
##
40
'refcount-bits': 'int',
63
diff --git a/block/rbd.c b/block/rbd.c
41
@@ -XXX,XX +XXX,XX @@
64
index XXXXXXX..XXXXXXX 100644
42
# @data-file Node to use as an external data file in which all guest
65
--- a/block/rbd.c
43
# data is stored so that only metadata remains in the qcow2
66
+++ b/block/rbd.c
44
# file (since: 4.0)
67
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_refresh_limits(BlockDriverState *bs, Error **errp)
45
+# @data-file-raw True if the external data file must stay valid as a
46
+# standalone (read-only) raw image without looking at qcow2
47
+# metadata (default: false; since: 4.0)
48
# @size Size of the virtual disk in bytes
49
# @version Compatibility level (default: v3)
50
# @backing-file File name of the backing file if a backing file
51
@@ -XXX,XX +XXX,XX @@
52
{ 'struct': 'BlockdevCreateOptionsQcow2',
53
'data': { 'file': 'BlockdevRef',
54
'*data-file': 'BlockdevRef',
55
+ '*data-file-raw': 'bool',
56
'size': 'size',
57
'*version': 'BlockdevQcow2Version',
58
'*backing-file': 'str',
59
diff --git a/block/qcow2.h b/block/qcow2.h
60
index XXXXXXX..XXXXXXX 100644
61
--- a/block/qcow2.h
62
+++ b/block/qcow2.h
63
@@ -XXX,XX +XXX,XX @@ enum {
64
QCOW2_AUTOCLEAR_BITMAPS = 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR,
65
QCOW2_AUTOCLEAR_DATA_FILE_RAW = 1 << QCOW2_AUTOCLEAR_DATA_FILE_RAW_BITNR,
66
67
- QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS,
68
+ QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS
69
+ | QCOW2_AUTOCLEAR_DATA_FILE_RAW,
70
};
71
72
enum qcow2_discard_type {
73
@@ -XXX,XX +XXX,XX @@ static inline bool has_data_file(BlockDriverState *bs)
74
return (s->data_file != bs->file);
68
}
75
}
69
76
70
77
+static inline bool data_file_is_raw(BlockDriverState *bs)
71
-static int qemu_rbd_set_auth(rados_t cluster, const char *secretid,
78
+{
72
- BlockdevOptionsRbd *opts,
79
+ BDRVQcow2State *s = bs->opaque;
73
+static int qemu_rbd_set_auth(rados_t cluster, BlockdevOptionsRbd *opts,
80
+ return !!(s->autoclear_features & QCOW2_AUTOCLEAR_DATA_FILE_RAW);
74
Error **errp)
81
+}
82
+
83
static inline int64_t start_of_cluster(BDRVQcow2State *s, int64_t offset)
75
{
84
{
76
- char *acr;
85
return offset & ~(s->cluster_size - 1);
77
+ char *key, *acr;
86
diff --git a/include/block/block_int.h b/include/block/block_int.h
78
int r;
87
index XXXXXXX..XXXXXXX 100644
79
GString *accu;
88
--- a/include/block/block_int.h
80
RbdAuthModeList *auth;
89
+++ b/include/block/block_int.h
81
90
@@ -XXX,XX +XXX,XX @@
82
- if (secretid) {
91
#define BLOCK_OPT_OBJECT_SIZE "object_size"
83
- gchar *secret = qcrypto_secret_lookup_as_base64(secretid,
92
#define BLOCK_OPT_REFCOUNT_BITS "refcount_bits"
84
- errp);
93
#define BLOCK_OPT_DATA_FILE "data_file"
85
- if (!secret) {
94
+#define BLOCK_OPT_DATA_FILE_RAW "data_file_raw"
86
- return -1;
95
87
+ if (opts->key_secret) {
96
#define BLOCK_PROBE_BUF_SIZE 512
88
+ key = qcrypto_secret_lookup_as_base64(opts->key_secret, errp);
97
89
+ if (!key) {
98
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
90
+ return -EIO;
99
index XXXXXXX..XXXXXXX 100644
100
--- a/block/qcow2-cluster.c
101
+++ b/block/qcow2-cluster.c
102
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
103
int64_t cleared;
104
int ret;
105
106
+ /* If we have to stay in sync with an external data file, zero out
107
+ * s->data_file first. */
108
+ if (data_file_is_raw(bs)) {
109
+ assert(has_data_file(bs));
110
+ ret = bdrv_co_pwrite_zeroes(s->data_file, offset, bytes, flags);
111
+ if (ret < 0) {
112
+ return ret;
91
+ }
113
+ }
92
+ r = rados_conf_set(cluster, "key", key);
114
+ }
93
+ g_free(key);
115
+
94
+ if (r < 0) {
116
/* Caller must pass aligned values, except at image end */
95
+ error_setg_errno(errp, -r, "Could not set 'key'");
117
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
96
+ return r;
118
assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
97
}
119
diff --git a/block/qcow2.c b/block/qcow2.c
98
-
120
index XXXXXXX..XXXXXXX 100644
99
- rados_conf_set(cluster, "key", secret);
121
--- a/block/qcow2.c
100
- g_free(secret);
122
+++ b/block/qcow2.c
101
}
123
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
102
124
"external data file");
103
if (opts->has_auth_client_required) {
125
ret = -EINVAL;
104
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
126
goto fail;
105
},
127
- } else {
106
};
128
- s->data_file = bs->file;
107
108
-/* FIXME Deprecate and remove keypairs or make it available in QMP.
109
- * password_secret should eventually be configurable in opts->location. Support
110
- * for it in .bdrv_open will make it work here as well. */
111
+/* FIXME Deprecate and remove keypairs or make it available in QMP. */
112
static int qemu_rbd_do_create(BlockdevCreateOptions *options,
113
const char *keypairs, const char *password_secret,
114
Error **errp)
115
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
116
Error *local_err = NULL;
117
int r;
118
119
+ if (secretid) {
120
+ if (opts->key_secret) {
121
+ error_setg(errp,
122
+ "Legacy 'password-secret' clashes with 'key-secret'");
123
+ return -EINVAL;
124
+ }
129
+ }
125
+ opts->key_secret = g_strdup(secretid);
130
+
126
+ opts->has_key_secret = true;
131
+ s->data_file = bs->file;
127
+ }
132
+
128
+
133
+ if (data_file_is_raw(bs)) {
129
mon_host = qemu_rbd_mon_host(opts, &local_err);
134
+ error_setg(errp, "data-file-raw requires a data file");
130
if (local_err) {
135
+ ret = -EINVAL;
131
error_propagate(errp, local_err);
136
+ goto fail;
132
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
133
}
137
}
134
}
138
}
135
139
136
- if (qemu_rbd_set_auth(*cluster, secretid, opts, errp) < 0) {
140
@@ -XXX,XX +XXX,XX @@ static int qcow2_change_backing_file(BlockDriverState *bs,
137
- r = -EIO;
141
{
138
+ r = qemu_rbd_set_auth(*cluster, opts, errp);
142
BDRVQcow2State *s = bs->opaque;
139
+ if (r < 0) {
143
140
goto failed_shutdown;
144
+ /* Adding a backing file means that the external data file alone won't be
145
+ * enough to make sense of the content */
146
+ if (backing_file && data_file_is_raw(bs)) {
147
+ return -EINVAL;
148
+ }
149
+
150
if (backing_file && strlen(backing_file) > 1023) {
151
return -EINVAL;
141
}
152
}
142
153
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
154
}
155
refcount_order = ctz32(qcow2_opts->refcount_bits);
156
157
+ if (qcow2_opts->data_file_raw && !qcow2_opts->data_file) {
158
+ error_setg(errp, "data-file-raw requires data-file");
159
+ ret = -EINVAL;
160
+ goto out;
161
+ }
162
+ if (qcow2_opts->data_file_raw && qcow2_opts->has_backing_file) {
163
+ error_setg(errp, "Backing file and data-file-raw cannot be used at "
164
+ "the same time");
165
+ ret = -EINVAL;
166
+ goto out;
167
+ }
168
+
169
if (qcow2_opts->data_file) {
170
if (version < 3) {
171
error_setg(errp, "External data files are only supported with "
172
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
173
header->incompatible_features |=
174
cpu_to_be64(QCOW2_INCOMPAT_DATA_FILE);
175
}
176
+ if (qcow2_opts->data_file_raw) {
177
+ header->autoclear_features |=
178
+ cpu_to_be64(QCOW2_AUTOCLEAR_DATA_FILE_RAW);
179
+ }
180
181
ret = blk_pwrite(blk, 0, header, cluster_size, 0);
182
g_free(header);
183
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
184
{ BLOCK_OPT_REFCOUNT_BITS, "refcount-bits" },
185
{ BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT },
186
{ BLOCK_OPT_COMPAT_LEVEL, "version" },
187
+ { BLOCK_OPT_DATA_FILE_RAW, "data-file-raw" },
188
{ NULL, NULL },
189
};
190
191
@@ -XXX,XX +XXX,XX @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs,
192
.bitmaps = bitmaps,
193
.has_data_file = !!s->image_data_file,
194
.data_file = g_strdup(s->image_data_file),
195
+ .has_data_file_raw = has_data_file(bs),
196
+ .data_file_raw = data_file_is_raw(bs),
197
};
198
} else {
199
/* if this assertion fails, this probably means a new version was
200
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
201
uint64_t new_size = 0;
202
const char *backing_file = NULL, *backing_format = NULL, *data_file = NULL;
203
bool lazy_refcounts = s->use_lazy_refcounts;
204
+ bool data_file_raw = data_file_is_raw(bs);
205
const char *compat = NULL;
206
uint64_t cluster_size = s->cluster_size;
207
bool encrypt;
208
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
209
"use an external data file");
210
return -EINVAL;
211
}
212
+ } else if (!strcmp(desc->name, BLOCK_OPT_DATA_FILE_RAW)) {
213
+ data_file_raw = qemu_opt_get_bool(opts, BLOCK_OPT_DATA_FILE_RAW,
214
+ data_file_raw);
215
+ if (data_file_raw && !data_file_is_raw(bs)) {
216
+ error_setg(errp, "data-file-raw cannot be set on existing "
217
+ "images");
218
+ return -EINVAL;
219
+ }
220
} else {
221
/* if this point is reached, this probably means a new option was
222
* added without having it covered here */
223
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
224
}
225
}
226
227
+ /* data-file-raw blocks backing files, so clear it first if requested */
228
+ if (data_file_raw) {
229
+ s->autoclear_features |= QCOW2_AUTOCLEAR_DATA_FILE_RAW;
230
+ } else {
231
+ s->autoclear_features &= ~QCOW2_AUTOCLEAR_DATA_FILE_RAW;
232
+ }
233
+
234
if (data_file) {
235
g_free(s->image_data_file);
236
s->image_data_file = *data_file ? g_strdup(data_file) : NULL;
237
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_create_opts = {
238
.type = QEMU_OPT_STRING,
239
.help = "File name of an external data file"
240
},
241
+ {
242
+ .name = BLOCK_OPT_DATA_FILE_RAW,
243
+ .type = QEMU_OPT_BOOL,
244
+ .help = "The external data file must stay valid as a raw image"
245
+ },
246
{
247
.name = BLOCK_OPT_ENCRYPT,
248
.type = QEMU_OPT_BOOL,
249
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
250
index XXXXXXX..XXXXXXX 100644
251
--- a/tests/qemu-iotests/082.out
252
+++ b/tests/qemu-iotests/082.out
253
@@ -XXX,XX +XXX,XX @@ Supported options:
254
cluster_size=<size> - qcow2 cluster size
255
compat=<str> - Compatibility level (0.10 or 1.1)
256
data_file=<str> - File name of an external data file
257
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
258
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
259
encrypt.cipher-mode=<str> - Name of encryption cipher mode
260
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
261
@@ -XXX,XX +XXX,XX @@ Supported options:
262
cluster_size=<size> - qcow2 cluster size
263
compat=<str> - Compatibility level (0.10 or 1.1)
264
data_file=<str> - File name of an external data file
265
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
266
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
267
encrypt.cipher-mode=<str> - Name of encryption cipher mode
268
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
269
@@ -XXX,XX +XXX,XX @@ Supported options:
270
cluster_size=<size> - qcow2 cluster size
271
compat=<str> - Compatibility level (0.10 or 1.1)
272
data_file=<str> - File name of an external data file
273
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
274
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
275
encrypt.cipher-mode=<str> - Name of encryption cipher mode
276
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
277
@@ -XXX,XX +XXX,XX @@ Supported options:
278
cluster_size=<size> - qcow2 cluster size
279
compat=<str> - Compatibility level (0.10 or 1.1)
280
data_file=<str> - File name of an external data file
281
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
282
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
283
encrypt.cipher-mode=<str> - Name of encryption cipher mode
284
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
285
@@ -XXX,XX +XXX,XX @@ Supported options:
286
cluster_size=<size> - qcow2 cluster size
287
compat=<str> - Compatibility level (0.10 or 1.1)
288
data_file=<str> - File name of an external data file
289
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
290
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
291
encrypt.cipher-mode=<str> - Name of encryption cipher mode
292
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
293
@@ -XXX,XX +XXX,XX @@ Supported options:
294
cluster_size=<size> - qcow2 cluster size
295
compat=<str> - Compatibility level (0.10 or 1.1)
296
data_file=<str> - File name of an external data file
297
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
298
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
299
encrypt.cipher-mode=<str> - Name of encryption cipher mode
300
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
301
@@ -XXX,XX +XXX,XX @@ Supported options:
302
cluster_size=<size> - qcow2 cluster size
303
compat=<str> - Compatibility level (0.10 or 1.1)
304
data_file=<str> - File name of an external data file
305
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
306
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
307
encrypt.cipher-mode=<str> - Name of encryption cipher mode
308
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
309
@@ -XXX,XX +XXX,XX @@ Supported options:
310
cluster_size=<size> - qcow2 cluster size
311
compat=<str> - Compatibility level (0.10 or 1.1)
312
data_file=<str> - File name of an external data file
313
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
314
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
315
encrypt.cipher-mode=<str> - Name of encryption cipher mode
316
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
317
@@ -XXX,XX +XXX,XX @@ Supported options:
318
cluster_size=<size> - qcow2 cluster size
319
compat=<str> - Compatibility level (0.10 or 1.1)
320
data_file=<str> - File name of an external data file
321
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
322
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
323
encrypt.cipher-mode=<str> - Name of encryption cipher mode
324
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
325
@@ -XXX,XX +XXX,XX @@ Supported options:
326
cluster_size=<size> - qcow2 cluster size
327
compat=<str> - Compatibility level (0.10 or 1.1)
328
data_file=<str> - File name of an external data file
329
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
330
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
331
encrypt.cipher-mode=<str> - Name of encryption cipher mode
332
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
333
@@ -XXX,XX +XXX,XX @@ Supported options:
334
cluster_size=<size> - qcow2 cluster size
335
compat=<str> - Compatibility level (0.10 or 1.1)
336
data_file=<str> - File name of an external data file
337
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
338
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
339
encrypt.cipher-mode=<str> - Name of encryption cipher mode
340
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
341
@@ -XXX,XX +XXX,XX @@ Supported options:
342
cluster_size=<size> - qcow2 cluster size
343
compat=<str> - Compatibility level (0.10 or 1.1)
344
data_file=<str> - File name of an external data file
345
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
346
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
347
encrypt.cipher-mode=<str> - Name of encryption cipher mode
348
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
349
@@ -XXX,XX +XXX,XX @@ Supported options:
350
cluster_size=<size> - qcow2 cluster size
351
compat=<str> - Compatibility level (0.10 or 1.1)
352
data_file=<str> - File name of an external data file
353
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
354
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
355
encrypt.cipher-mode=<str> - Name of encryption cipher mode
356
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
357
@@ -XXX,XX +XXX,XX @@ Supported options:
358
cluster_size=<size> - qcow2 cluster size
359
compat=<str> - Compatibility level (0.10 or 1.1)
360
data_file=<str> - File name of an external data file
361
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
362
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
363
encrypt.cipher-mode=<str> - Name of encryption cipher mode
364
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
365
@@ -XXX,XX +XXX,XX @@ Supported options:
366
cluster_size=<size> - qcow2 cluster size
367
compat=<str> - Compatibility level (0.10 or 1.1)
368
data_file=<str> - File name of an external data file
369
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
370
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
371
encrypt.cipher-mode=<str> - Name of encryption cipher mode
372
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
373
@@ -XXX,XX +XXX,XX @@ Supported options:
374
cluster_size=<size> - qcow2 cluster size
375
compat=<str> - Compatibility level (0.10 or 1.1)
376
data_file=<str> - File name of an external data file
377
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
378
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
379
encrypt.cipher-mode=<str> - Name of encryption cipher mode
380
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
381
@@ -XXX,XX +XXX,XX @@ Supported options:
382
cluster_size=<size> - qcow2 cluster size
383
compat=<str> - Compatibility level (0.10 or 1.1)
384
data_file=<str> - File name of an external data file
385
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
386
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
387
encrypt.cipher-mode=<str> - Name of encryption cipher mode
388
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
389
@@ -XXX,XX +XXX,XX @@ Supported options:
390
cluster_size=<size> - qcow2 cluster size
391
compat=<str> - Compatibility level (0.10 or 1.1)
392
data_file=<str> - File name of an external data file
393
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
394
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
395
encrypt.cipher-mode=<str> - Name of encryption cipher mode
396
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
397
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
398
cluster_size=<size> - qcow2 cluster size
399
compat=<str> - Compatibility level (0.10 or 1.1)
400
data_file=<str> - File name of an external data file
401
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
402
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
403
encrypt.cipher-mode=<str> - Name of encryption cipher mode
404
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
405
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
406
cluster_size=<size> - qcow2 cluster size
407
compat=<str> - Compatibility level (0.10 or 1.1)
408
data_file=<str> - File name of an external data file
409
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
410
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
411
encrypt.cipher-mode=<str> - Name of encryption cipher mode
412
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
413
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
414
cluster_size=<size> - qcow2 cluster size
415
compat=<str> - Compatibility level (0.10 or 1.1)
416
data_file=<str> - File name of an external data file
417
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
418
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
419
encrypt.cipher-mode=<str> - Name of encryption cipher mode
420
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
421
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
422
cluster_size=<size> - qcow2 cluster size
423
compat=<str> - Compatibility level (0.10 or 1.1)
424
data_file=<str> - File name of an external data file
425
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
426
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
427
encrypt.cipher-mode=<str> - Name of encryption cipher mode
428
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
429
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
430
cluster_size=<size> - qcow2 cluster size
431
compat=<str> - Compatibility level (0.10 or 1.1)
432
data_file=<str> - File name of an external data file
433
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
434
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
435
encrypt.cipher-mode=<str> - Name of encryption cipher mode
436
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
437
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
438
cluster_size=<size> - qcow2 cluster size
439
compat=<str> - Compatibility level (0.10 or 1.1)
440
data_file=<str> - File name of an external data file
441
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
442
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
443
encrypt.cipher-mode=<str> - Name of encryption cipher mode
444
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
445
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
446
cluster_size=<size> - qcow2 cluster size
447
compat=<str> - Compatibility level (0.10 or 1.1)
448
data_file=<str> - File name of an external data file
449
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
450
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
451
encrypt.cipher-mode=<str> - Name of encryption cipher mode
452
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
453
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
454
cluster_size=<size> - qcow2 cluster size
455
compat=<str> - Compatibility level (0.10 or 1.1)
456
data_file=<str> - File name of an external data file
457
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
458
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
459
encrypt.cipher-mode=<str> - Name of encryption cipher mode
460
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
461
@@ -XXX,XX +XXX,XX @@ Creation options for 'qcow2':
462
cluster_size=<size> - qcow2 cluster size
463
compat=<str> - Compatibility level (0.10 or 1.1)
464
data_file=<str> - File name of an external data file
465
+ data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image
466
encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
467
encrypt.cipher-mode=<str> - Name of encryption cipher mode
468
encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
143
--
469
--
144
2.13.6
470
2.20.1
145
471
146
472
diff view generated by jsdifflib
1
The -drive option addr was deprecated in QEMU 2.10. It's time to remove
1
Test that preallocating metadata results in a somewhat larger qcow2
2
it.
2
file, but preallocating data only affects the disk usage of the data
3
file and the qcow2 file stays small.
3
4
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Markus Armbruster <armbru@redhat.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
---
6
---
8
include/sysemu/blockdev.h | 1 -
7
tests/qemu-iotests/243 | 22 ++++++++++++++++++++++
9
blockdev.c | 17 +----------------
8
tests/qemu-iotests/243.out | 32 ++++++++++++++++++++++++++++++++
10
device-hotplug.c | 4 ----
9
2 files changed, 54 insertions(+)
11
qemu-doc.texi | 5 -----
12
qemu-options.hx | 5 +----
13
5 files changed, 2 insertions(+), 30 deletions(-)
14
10
15
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
11
diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243
12
index XXXXXXX..XXXXXXX 100755
13
--- a/tests/qemu-iotests/243
14
+++ b/tests/qemu-iotests/243
15
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
16
_cleanup()
17
{
18
_cleanup_test_img
19
+ rm -f $TEST_IMG.data
20
}
21
trap "_cleanup; exit \$status" 0 1 2 3 15
22
23
@@ -XXX,XX +XXX,XX @@ for mode in off metadata falloc full; do
24
25
done
26
27
+for mode in off metadata falloc full; do
28
+
29
+ echo
30
+ echo "=== External data file: preallocation=$mode ==="
31
+ echo
32
+
33
+ IMGOPTS="data_file=$TEST_IMG.data,preallocation=$mode" _make_test_img 64M
34
+
35
+ echo -n "qcow2 file size: "
36
+ du -b $TEST_IMG | cut -f1
37
+ echo -n "data file size: "
38
+ du -b $TEST_IMG.data | cut -f1
39
+
40
+ # Can't use precise numbers here because they differ between filesystems
41
+ echo -n "qcow2 disk usage: "
42
+ [ $(du -B1 $TEST_IMG | cut -f1) -lt 1048576 ] && echo "low" || echo "high"
43
+ echo -n "data disk usage: "
44
+ [ $(du -B1 $TEST_IMG.data | cut -f1) -lt 1048576 ] && echo "low" || echo "high"
45
+
46
+done
47
+
48
# success, all done
49
echo "*** done"
50
rm -f $seq.full
51
diff --git a/tests/qemu-iotests/243.out b/tests/qemu-iotests/243.out
16
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
17
--- a/include/sysemu/blockdev.h
53
--- a/tests/qemu-iotests/243.out
18
+++ b/include/sysemu/blockdev.h
54
+++ b/tests/qemu-iotests/243.out
19
@@ -XXX,XX +XXX,XX @@ typedef enum {
55
@@ -XXX,XX +XXX,XX @@ Disk usage: high
20
} BlockInterfaceType;
56
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=full
21
57
File size: 67436544
22
struct DriveInfo {
58
Disk usage: high
23
- const char *devaddr;
59
+
24
BlockInterfaceType type;
60
+=== External data file: preallocation=off ===
25
int bus;
61
+
26
int unit;
62
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=off
27
diff --git a/blockdev.c b/blockdev.c
63
+qcow2 file size: 196616
28
index XXXXXXX..XXXXXXX 100644
64
+data file size: 67108864
29
--- a/blockdev.c
65
+qcow2 disk usage: low
30
+++ b/blockdev.c
66
+data disk usage: low
31
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
67
+
32
.type = QEMU_OPT_STRING,
68
+=== External data file: preallocation=metadata ===
33
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
69
+
34
},{
70
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=metadata
35
- .name = "addr",
71
+qcow2 file size: 327680
36
- .type = QEMU_OPT_STRING,
72
+data file size: 67108864
37
- .help = "pci address (virtio only)",
73
+qcow2 disk usage: low
38
- },{
74
+data disk usage: low
39
.name = "serial",
75
+
40
.type = QEMU_OPT_STRING,
76
+=== External data file: preallocation=falloc ===
41
.help = "disk serial number",
77
+
42
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
78
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=falloc
43
DriveMediaType media = MEDIA_DISK;
79
+qcow2 file size: 327680
44
BlockInterfaceType type;
80
+data file size: 67108864
45
int max_devs, bus_id, unit_id, index;
81
+qcow2 disk usage: low
46
- const char *devaddr;
82
+data disk usage: high
47
const char *werror, *rerror;
83
+
48
bool read_only = false;
84
+=== External data file: preallocation=full ===
49
bool copy_on_read;
85
+
50
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
86
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=full
51
Error *local_err = NULL;
87
+qcow2 file size: 327680
52
int i;
88
+data file size: 67108864
53
const char *deprecated[] = {
89
+qcow2 disk usage: low
54
- "serial", "addr"
90
+data disk usage: high
55
+ "serial"
91
*** done
56
};
57
58
/* Change legacy command line options into QMP ones */
59
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
60
}
61
62
/* Add virtio block device */
63
- devaddr = qemu_opt_get(legacy_opts, "addr");
64
- if (devaddr && type != IF_VIRTIO) {
65
- error_report("addr is not supported by this bus type");
66
- goto fail;
67
- }
68
-
69
if (type == IF_VIRTIO) {
70
QemuOpts *devopts;
71
devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
72
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
73
}
74
qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
75
&error_abort);
76
- if (devaddr) {
77
- qemu_opt_set(devopts, "addr", devaddr, &error_abort);
78
- }
79
}
80
81
filename = qemu_opt_get(legacy_opts, "file");
82
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
83
dinfo->type = type;
84
dinfo->bus = bus_id;
85
dinfo->unit = unit_id;
86
- dinfo->devaddr = devaddr;
87
dinfo->serial = g_strdup(serial);
88
89
blk_set_legacy_dinfo(blk, dinfo);
90
diff --git a/device-hotplug.c b/device-hotplug.c
91
index XXXXXXX..XXXXXXX 100644
92
--- a/device-hotplug.c
93
+++ b/device-hotplug.c
94
@@ -XXX,XX +XXX,XX @@ void hmp_drive_add(Monitor *mon, const QDict *qdict)
95
if (!dinfo) {
96
goto err;
97
}
98
- if (dinfo->devaddr) {
99
- monitor_printf(mon, "Parameter addr not supported\n");
100
- goto err;
101
- }
102
103
switch (dinfo->type) {
104
case IF_NONE:
105
diff --git a/qemu-doc.texi b/qemu-doc.texi
106
index XXXXXXX..XXXXXXX 100644
107
--- a/qemu-doc.texi
108
+++ b/qemu-doc.texi
109
@@ -XXX,XX +XXX,XX @@ provided per NIC.
110
The drive serial argument is replaced by the the serial argument
111
that can be specified with the ``-device'' parameter.
112
113
-@subsection -drive addr=... (since 2.10.0)
114
-
115
-The drive addr argument is replaced by the the addr argument
116
-that can be specified with the ``-device'' parameter.
117
-
118
@subsection -usbdevice (since 2.10.0)
119
120
The ``-usbdevice DEV'' argument is now a synonym for setting
121
diff --git a/qemu-options.hx b/qemu-options.hx
122
index XXXXXXX..XXXXXXX 100644
123
--- a/qemu-options.hx
124
+++ b/qemu-options.hx
125
@@ -XXX,XX +XXX,XX @@ ETEXI
126
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
127
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
128
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
129
- " [,snapshot=on|off][,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
130
+ " [,snapshot=on|off][,serial=s][,rerror=ignore|stop|report]\n"
131
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
132
" [,readonly=on|off][,copy-on-read=on|off]\n"
133
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
134
@@ -XXX,XX +XXX,XX @@ an untrusted format header.
135
This option specifies the serial number to assign to the device. This
136
parameter is deprecated, use the corresponding parameter of @code{-device}
137
instead.
138
-@item addr=@var{addr}
139
-Specify the controller's PCI address (if=virtio only). This parameter is
140
-deprecated, use the corresponding parameter of @code{-device} instead.
141
@item werror=@var{action},rerror=@var{action}
142
Specify which @var{action} to take on write and read errors. Valid actions are:
143
"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
144
--
92
--
145
2.13.6
93
2.20.1
146
94
147
95
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
2
3
Although qemu-img creates aligned files (by rounding up), it
4
must also gracefully handle files that are not sector-aligned.
5
Test that the bug fixed in the previous patch does not recur.
6
7
It's a bit annoying that we can see the (implicit) hole past
8
the end of the file on to the next sector boundary, so if we
9
ever reach the point where we report a byte-accurate size rather
10
than our current behavior of always rounding up, this test will
11
probably need a slight modification.
12
13
Signed-off-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
2
---
16
tests/qemu-iotests/221 | 60 ++++++++++++++++++++++++++++++++++++++++++++++
3
tests/qemu-iotests/244 | 200 +++++++++++++++++++++++++++++++++++++
17
tests/qemu-iotests/221.out | 16 +++++++++++++
4
tests/qemu-iotests/244.out | 125 +++++++++++++++++++++++
18
tests/qemu-iotests/group | 1 +
5
tests/qemu-iotests/group | 1 +
19
3 files changed, 77 insertions(+)
6
3 files changed, 326 insertions(+)
20
create mode 100755 tests/qemu-iotests/221
7
create mode 100755 tests/qemu-iotests/244
21
create mode 100644 tests/qemu-iotests/221.out
8
create mode 100644 tests/qemu-iotests/244.out
22
9
23
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
10
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
24
new file mode 100755
11
new file mode 100755
25
index XXXXXXX..XXXXXXX
12
index XXXXXXX..XXXXXXX
26
--- /dev/null
13
--- /dev/null
27
+++ b/tests/qemu-iotests/221
14
+++ b/tests/qemu-iotests/244
28
@@ -XXX,XX +XXX,XX @@
15
@@ -XXX,XX +XXX,XX @@
29
+#!/bin/bash
16
+#!/bin/bash
30
+#
17
+#
31
+# Test qemu-img vs. unaligned images
18
+# Test qcow2 with external data files
32
+#
19
+#
33
+# Copyright (C) 2018 Red Hat, Inc.
20
+# Copyright (C) 2019 Red Hat, Inc.
34
+#
21
+#
35
+# This program is free software; you can redistribute it and/or modify
22
+# This program is free software; you can redistribute it and/or modify
36
+# it under the terms of the GNU General Public License as published by
23
+# it under the terms of the GNU General Public License as published by
37
+# the Free Software Foundation; either version 2 of the License, or
24
+# the Free Software Foundation; either version 2 of the License, or
38
+# (at your option) any later version.
25
+# (at your option) any later version.
...
...
44
+#
31
+#
45
+# You should have received a copy of the GNU General Public License
32
+# You should have received a copy of the GNU General Public License
46
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
33
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
47
+#
34
+#
48
+
35
+
49
+seq="$(basename $0)"
36
+# creator
37
+owner=kwolf@redhat.com
38
+
39
+seq=$(basename $0)
50
+echo "QA output created by $seq"
40
+echo "QA output created by $seq"
51
+
41
+
52
+here="$PWD"
42
+status=1    # failure is the default!
53
+status=1 # failure is the default!
54
+
43
+
55
+_cleanup()
44
+_cleanup()
56
+{
45
+{
57
+ _cleanup_test_img
46
+ _cleanup_test_img
47
+ rm -f $TEST_IMG.data
48
+ rm -f $TEST_IMG.src
58
+}
49
+}
59
+trap "_cleanup; exit \$status" 0 1 2 3 15
50
+trap "_cleanup; exit \$status" 0 1 2 3 15
60
+
51
+
61
+# get standard environment, filters and checks
52
+# get standard environment, filters and checks
62
+. ./common.rc
53
+. ./common.rc
63
+. ./common.filter
54
+. ./common.filter
64
+
55
+
65
+_supported_fmt raw
56
+_supported_fmt qcow2
66
+_supported_proto file
57
+_supported_proto file
67
+_supported_os Linux
58
+_supported_os Linux
68
+
59
+
69
+echo
60
+echo
70
+echo "=== Check mapping of unaligned raw image ==="
61
+echo "=== Create and open image with external data file ==="
71
+echo
62
+echo
72
+
63
+
73
+_make_test_img 43009 # qemu-img create rounds size up
64
+echo "With data file name in the image:"
74
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
65
+IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
75
+
66
+_check_test_img
76
+truncate --size=43009 "$TEST_IMG" # so we resize it and check again
67
+
77
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
68
+$QEMU_IO -c "open $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir
78
+
69
+$QEMU_IO -c "open -odata-file.filename=$TEST_IMG.data $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir
79
+$QEMU_IO -c 'w 43008 1' "$TEST_IMG" | _filter_qemu_io # writing also rounds up
70
+$QEMU_IO -c "open -odata-file.filename=inexistent $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir
80
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
71
+
81
+
72
+echo
82
+truncate --size=43009 "$TEST_IMG" # so we resize it and check again
73
+echo "Data file required, but without data file name in the image:"
83
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
74
+$QEMU_IMG amend -odata_file= $TEST_IMG
75
+
76
+$QEMU_IO -c "open $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir
77
+$QEMU_IO -c "open -odata-file.filename=$TEST_IMG.data $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir
78
+$QEMU_IO -c "open -odata-file.filename=inexistent $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir
79
+
80
+echo
81
+echo "Setting data-file for an image with internal data:"
82
+_make_test_img 64M
83
+
84
+$QEMU_IO -c "open -odata-file.filename=$TEST_IMG.data $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir
85
+$QEMU_IO -c "open -odata-file.filename=inexistent $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir
86
+
87
+echo
88
+echo "=== Conflicting features ==="
89
+echo
90
+
91
+echo "Convert to compressed target with data file:"
92
+TEST_IMG="$TEST_IMG.src" _make_test_img 64M
93
+
94
+$QEMU_IO -c 'write -P 0x11 0 1M' \
95
+ -f $IMGFMT "$TEST_IMG.src" |
96
+ _filter_qemu_io
97
+
98
+$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -c -odata_file="$TEST_IMG.data" \
99
+ "$TEST_IMG.src" "$TEST_IMG"
100
+
101
+echo
102
+echo "Convert uncompressed, then write compressed data manually:"
103
+$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -odata_file="$TEST_IMG.data" \
104
+ "$TEST_IMG.src" "$TEST_IMG"
105
+$QEMU_IMG compare "$TEST_IMG.src" "$TEST_IMG"
106
+
107
+$QEMU_IO -c 'write -c -P 0x22 0 1M' \
108
+ -f $IMGFMT "$TEST_IMG" |
109
+ _filter_qemu_io
110
+_check_test_img
111
+
112
+echo
113
+echo "Take an internal snapshot:"
114
+
115
+$QEMU_IMG snapshot -c test "$TEST_IMG"
116
+_check_test_img
117
+
118
+echo
119
+echo "=== Standalone image with external data file (efficient) ==="
120
+echo
121
+
122
+IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
123
+
124
+echo -n "qcow2 file size before I/O: "
125
+du -b $TEST_IMG | cut -f1
126
+
127
+# Create image with the following layout
128
+# 0-1 MB: Unallocated
129
+# 1-2 MB: Written (pattern 0x11)
130
+# 2-3 MB: Discarded
131
+# 3-4 MB: Zero write over discarded space
132
+# 4-5 MB: Zero write over written space
133
+# 5-6 MB: Zero write over unallocated space
134
+
135
+echo
136
+$QEMU_IO -c 'write -P 0x11 1M 4M' \
137
+ -c 'discard 2M 2M' \
138
+ -c 'write -z 3M 3M' \
139
+ -f $IMGFMT "$TEST_IMG" |
140
+ _filter_qemu_io
141
+_check_test_img
142
+
143
+echo
144
+$QEMU_IMG map --output=json "$TEST_IMG"
145
+
146
+echo
147
+$QEMU_IO -c 'read -P 0 0 1M' \
148
+ -c 'read -P 0x11 1M 1M' \
149
+ -c 'read -P 0 2M 4M' \
150
+ -f $IMGFMT "$TEST_IMG" |
151
+ _filter_qemu_io
152
+
153
+# Zero clusters are only marked as such in the qcow2 metadata, but contain
154
+# stale data in the external data file
155
+echo
156
+$QEMU_IO -c 'read -P 0 0 1M' \
157
+ -c 'read -P 0x11 1M 1M' \
158
+ -c 'read -P 0 2M 2M' \
159
+ -c 'read -P 0x11 4M 1M' \
160
+ -c 'read -P 0 5M 1M' \
161
+ -f raw "$TEST_IMG.data" |
162
+ _filter_qemu_io
163
+
164
+
165
+echo -n "qcow2 file size after I/O: "
166
+du -b $TEST_IMG | cut -f1
167
+
168
+echo
169
+echo "=== Standalone image with external data file (valid raw) ==="
170
+echo
171
+
172
+IMGOPTS="data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M
173
+
174
+echo -n "qcow2 file size before I/O: "
175
+du -b $TEST_IMG | cut -f1
176
+
177
+echo
178
+$QEMU_IO -c 'write -P 0x11 1M 4M' \
179
+ -c 'discard 2M 2M' \
180
+ -c 'write -z 3M 3M' \
181
+ -f $IMGFMT "$TEST_IMG" |
182
+ _filter_qemu_io
183
+_check_test_img
184
+
185
+echo
186
+$QEMU_IMG map --output=json "$TEST_IMG"
187
+
188
+echo
189
+$QEMU_IO -c 'read -P 0 0 1M' \
190
+ -c 'read -P 0x11 1M 1M' \
191
+ -c 'read -P 0 2M 4M' \
192
+ -f $IMGFMT "$TEST_IMG" |
193
+ _filter_qemu_io
194
+
195
+echo
196
+$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.data"
197
+
198
+echo -n "qcow2 file size after I/O: "
199
+du -b $TEST_IMG | cut -f1
200
+
201
+echo
202
+echo "=== bdrv_co_block_status test for file and offset=0 ==="
203
+echo
204
+
205
+IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
206
+
207
+$QEMU_IO -c 'write -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
208
+$QEMU_IO -c 'read -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
209
+$QEMU_IMG map --output=human "$TEST_IMG" | _filter_testdir
210
+$QEMU_IMG map --output=json "$TEST_IMG"
84
+
211
+
85
+# success, all done
212
+# success, all done
86
+echo '*** done'
213
+echo "*** done"
87
+rm -f $seq.full
214
+rm -f $seq.full
88
+status=0
215
+status=0
89
diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out
216
diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out
90
new file mode 100644
217
new file mode 100644
91
index XXXXXXX..XXXXXXX
218
index XXXXXXX..XXXXXXX
92
--- /dev/null
219
--- /dev/null
93
+++ b/tests/qemu-iotests/221.out
220
+++ b/tests/qemu-iotests/244.out
94
@@ -XXX,XX +XXX,XX @@
221
@@ -XXX,XX +XXX,XX @@
95
+QA output created by 221
222
+QA output created by 244
96
+
223
+
97
+=== Check mapping of unaligned raw image ===
224
+=== Create and open image with external data file ===
98
+
225
+
99
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=43009
226
+With data file name in the image:
100
+[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
227
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
101
+[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
228
+No errors were found on the image.
102
+wrote 1/1 bytes at offset 43008
229
+read 65536/65536 bytes at offset 0
103
+1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
230
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
104
+[{ "start": 0, "length": 40960, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
231
+read 65536/65536 bytes at offset 0
105
+{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
232
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
106
+{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
233
+can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory
107
+[{ "start": 0, "length": 40960, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
234
+no file open, try 'help open'
108
+{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
235
+
109
+{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
236
+Data file required, but without data file name in the image:
237
+can't open device TEST_DIR/t.qcow2: 'data-file' is required for this image
238
+no file open, try 'help open'
239
+read 65536/65536 bytes at offset 0
240
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
241
+can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory
242
+no file open, try 'help open'
243
+
244
+Setting data-file for an image with internal data:
245
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
246
+can't open device TEST_DIR/t.qcow2: 'data-file' can only be set for images with an external data file
247
+no file open, try 'help open'
248
+can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory
249
+no file open, try 'help open'
250
+
251
+=== Conflicting features ===
252
+
253
+Convert to compressed target with data file:
254
+Formatting 'TEST_DIR/t.IMGFMT.src', fmt=IMGFMT size=67108864
255
+wrote 1048576/1048576 bytes at offset 0
256
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
257
+qemu-img: error while writing sector 0: Operation not supported
258
+
259
+Convert uncompressed, then write compressed data manually:
260
+Images are identical.
261
+write failed: Operation not supported
262
+No errors were found on the image.
263
+
264
+Take an internal snapshot:
265
+qemu-img: Could not create snapshot 'test': -95 (Operation not supported)
266
+No errors were found on the image.
267
+
268
+=== Standalone image with external data file (efficient) ===
269
+
270
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
271
+qcow2 file size before I/O: 196616
272
+
273
+wrote 4194304/4194304 bytes at offset 1048576
274
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
275
+discard 2097152/2097152 bytes at offset 2097152
276
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
277
+wrote 3145728/3145728 bytes at offset 3145728
278
+3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
279
+No errors were found on the image.
280
+
281
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false},
282
+{ "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 1048576},
283
+{ "start": 2097152, "length": 2097152, "depth": 0, "zero": true, "data": false},
284
+{ "start": 4194304, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": 4194304},
285
+{ "start": 5242880, "length": 61865984, "depth": 0, "zero": true, "data": false}]
286
+
287
+read 1048576/1048576 bytes at offset 0
288
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
289
+read 1048576/1048576 bytes at offset 1048576
290
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
291
+read 4194304/4194304 bytes at offset 2097152
292
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
293
+
294
+read 1048576/1048576 bytes at offset 0
295
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
296
+read 1048576/1048576 bytes at offset 1048576
297
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
298
+read 2097152/2097152 bytes at offset 2097152
299
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
300
+read 1048576/1048576 bytes at offset 4194304
301
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
302
+read 1048576/1048576 bytes at offset 5242880
303
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
304
+qcow2 file size after I/O: 327680
305
+
306
+=== Standalone image with external data file (valid raw) ===
307
+
308
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on
309
+qcow2 file size before I/O: 196616
310
+
311
+wrote 4194304/4194304 bytes at offset 1048576
312
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
313
+discard 2097152/2097152 bytes at offset 2097152
314
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
315
+wrote 3145728/3145728 bytes at offset 3145728
316
+3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
317
+No errors were found on the image.
318
+
319
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false},
320
+{ "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 1048576},
321
+{ "start": 2097152, "length": 2097152, "depth": 0, "zero": true, "data": false},
322
+{ "start": 4194304, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": 4194304},
323
+{ "start": 5242880, "length": 61865984, "depth": 0, "zero": true, "data": false}]
324
+
325
+read 1048576/1048576 bytes at offset 0
326
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
327
+read 1048576/1048576 bytes at offset 1048576
328
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
329
+read 4194304/4194304 bytes at offset 2097152
330
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
331
+
332
+Images are identical.
333
+qcow2 file size after I/O: 327680
334
+
335
+=== bdrv_co_block_status test for file and offset=0 ===
336
+
337
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
338
+wrote 1048576/1048576 bytes at offset 0
339
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
340
+read 1048576/1048576 bytes at offset 0
341
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
342
+Offset Length Mapped to File
343
+0 0x100000 0 TEST_DIR/t.qcow2.data
344
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 0},
345
+{ "start": 1048576, "length": 66060288, "depth": 0, "zero": true, "data": false}]
110
+*** done
346
+*** done
111
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
347
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
112
index XXXXXXX..XXXXXXX 100644
348
index XXXXXXX..XXXXXXX 100644
113
--- a/tests/qemu-iotests/group
349
--- a/tests/qemu-iotests/group
114
+++ b/tests/qemu-iotests/group
350
+++ b/tests/qemu-iotests/group
115
@@ -XXX,XX +XXX,XX @@
351
@@ -XXX,XX +XXX,XX @@
116
217 rw auto quick
352
240 auto quick
117
218 rw auto quick
353
242 rw auto quick
118
219 rw auto
354
243 rw auto quick
119
+221 rw auto quick
355
+244 rw auto quick
120
--
356
--
121
2.13.6
357
2.20.1
122
358
123
359
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
2
3
Parameter "filename" is deprecated since commit 91589d9e5ca, v2.10.0.
4
Time to get rid of it.
5
6
Signed-off-by: Markus Armbruster <armbru@redhat.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
2
---
10
block/rbd.c | 16 ----------------
3
tests/qemu-iotests/061 | 45 ++++++++++++++++++-
11
1 file changed, 16 deletions(-)
4
tests/qemu-iotests/061.out | 89 ++++++++++++++++++++++++++++++++++++++
5
2 files changed, 133 insertions(+), 1 deletion(-)
12
6
13
diff --git a/block/rbd.c b/block/rbd.c
7
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
8
index XXXXXXX..XXXXXXX 100755
9
--- a/tests/qemu-iotests/061
10
+++ b/tests/qemu-iotests/061
11
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
12
13
_cleanup()
14
{
15
-    _cleanup_test_img
16
+ _cleanup_test_img
17
+ rm -f $TEST_IMG.data
18
}
19
trap "_cleanup; exit \$status" 0 1 2 3 15
20
21
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG snapshot -c foo "$TEST_IMG"
22
$QEMU_IMG amend -p -o "compat=0.10" "$TEST_IMG"
23
_check_test_img
24
25
+echo
26
+echo "=== Testing version downgrade with external data file ==="
27
+echo
28
+IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M
29
+$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
30
+_img_info --format-specific
31
+_check_test_img
32
+
33
+echo
34
+echo "=== Try changing the external data file ==="
35
+echo
36
+IMGOPTS="compat=1.1" _make_test_img 64M
37
+$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
38
+
39
+echo
40
+IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M
41
+$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
42
+_img_info --format-specific
43
+TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
44
+
45
+echo
46
+$QEMU_IMG amend -o "data_file=" --image-opts "data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG"
47
+_img_info --format-specific
48
+TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
49
+
50
+echo
51
+echo "=== Clearing and setting data-file-raw ==="
52
+echo
53
+IMGOPTS="compat=1.1,data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M
54
+$QEMU_IMG amend -o "data_file_raw=on" "$TEST_IMG"
55
+_img_info --format-specific
56
+_check_test_img
57
+
58
+$QEMU_IMG amend -o "data_file_raw=off" "$TEST_IMG"
59
+_img_info --format-specific
60
+_check_test_img
61
+
62
+$QEMU_IMG amend -o "data_file_raw=on" "$TEST_IMG"
63
+_img_info --format-specific
64
+_check_test_img
65
+
66
+
67
# success, all done
68
echo "*** done"
69
rm -f $seq.full
70
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
14
index XXXXXXX..XXXXXXX 100644
71
index XXXXXXX..XXXXXXX 100644
15
--- a/block/rbd.c
72
--- a/tests/qemu-iotests/061.out
16
+++ b/block/rbd.c
73
+++ b/tests/qemu-iotests/061.out
17
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
74
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 3221225472
18
QObject *crumpled = NULL;
75
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
19
const QDictEntry *e;
76
(0.00/100%)
20
Error *local_err = NULL;
77
(6.25/100%)
21
- const char *filename;
78
(12.50/100%)
22
char *keypairs, *secretid;
79
(18.75/100%)
23
int r;
80
(25.00/100%)
24
81
(31.25/100%)
25
- /* If we are given a filename, parse the filename, with precedence given to
82
(37.50/100%)
26
- * filename encoded options */
83
(43.75/100%)
27
- filename = qdict_get_try_str(options, "filename");
84
(50.00/100%)
28
- if (filename) {
85
(56.25/100%)
29
- warn_report("'filename' option specified. "
86
(62.50/100%)
30
- "This is an unsupported option, and may be deprecated "
87
(68.75/100%)
31
- "in the future");
88
(75.00/100%)
32
- qemu_rbd_parse_filename(filename, options, &local_err);
89
(81.25/100%)
33
- qdict_del(options, "filename");
90
(87.50/100%)
34
- if (local_err) {
91
(93.75/100%)
35
- error_propagate(errp, local_err);
92
(100.00/100%)
36
- return -EINVAL;
93
(100.00/100%)
37
- }
94
No errors were found on the image.
38
- }
95
+
39
-
96
+=== Testing version downgrade with external data file ===
40
keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs"));
97
+
41
if (keypairs) {
98
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
42
qdict_del(options, "=keyvalue-pairs");
99
+qemu-img: Cannot downgrade an image with a data file
100
+image: TEST_DIR/t.IMGFMT
101
+file format: IMGFMT
102
+virtual size: 64M (67108864 bytes)
103
+cluster_size: 65536
104
+Format specific information:
105
+ compat: 1.1
106
+ lazy refcounts: false
107
+ refcount bits: 16
108
+ data file: TEST_DIR/t.IMGFMT.data
109
+ data file raw: false
110
+ corrupt: false
111
+No errors were found on the image.
112
+
113
+=== Try changing the external data file ===
114
+
115
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
116
+qemu-img: data-file can only be set for images that use an external data file
117
+
118
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
119
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'foo': No such file or directory
120
+image: TEST_DIR/t.IMGFMT
121
+file format: IMGFMT
122
+virtual size: 64M (67108864 bytes)
123
+cluster_size: 65536
124
+Format specific information:
125
+ compat: 1.1
126
+ lazy refcounts: false
127
+ refcount bits: 16
128
+ data file: foo
129
+ data file raw: false
130
+ corrupt: false
131
+
132
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'data-file' is required for this image
133
+image: TEST_DIR/t.IMGFMT
134
+file format: IMGFMT
135
+virtual size: 64M (67108864 bytes)
136
+cluster_size: 65536
137
+Format specific information:
138
+ compat: 1.1
139
+ lazy refcounts: false
140
+ refcount bits: 16
141
+ data file raw: false
142
+ corrupt: false
143
+
144
+=== Clearing and setting data-file-raw ===
145
+
146
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on
147
+image: TEST_DIR/t.IMGFMT
148
+file format: IMGFMT
149
+virtual size: 64M (67108864 bytes)
150
+cluster_size: 65536
151
+Format specific information:
152
+ compat: 1.1
153
+ lazy refcounts: false
154
+ refcount bits: 16
155
+ data file: TEST_DIR/t.IMGFMT.data
156
+ data file raw: true
157
+ corrupt: false
158
+No errors were found on the image.
159
+image: TEST_DIR/t.IMGFMT
160
+file format: IMGFMT
161
+virtual size: 64M (67108864 bytes)
162
+cluster_size: 65536
163
+Format specific information:
164
+ compat: 1.1
165
+ lazy refcounts: false
166
+ refcount bits: 16
167
+ data file: TEST_DIR/t.IMGFMT.data
168
+ data file raw: false
169
+ corrupt: false
170
+No errors were found on the image.
171
+qemu-img: data-file-raw cannot be set on existing images
172
+image: TEST_DIR/t.IMGFMT
173
+file format: IMGFMT
174
+virtual size: 64M (67108864 bytes)
175
+cluster_size: 65536
176
+Format specific information:
177
+ compat: 1.1
178
+ lazy refcounts: false
179
+ refcount bits: 16
180
+ data file: TEST_DIR/t.IMGFMT.data
181
+ data file raw: false
182
+ corrupt: false
183
+No errors were found on the image.
184
*** done
43
--
185
--
44
2.13.6
186
2.20.1
45
187
46
188
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
During the design for manual completion, we decided not to use the
3
Since the ahci-test uses qemu-img, add a dependency to build it
4
"manual" property as a shorthand for both auto-dismiss and auto-finalize.
4
before using it.
5
This fixes:
5
6
6
Fix the wording.
7
$ gmake check-qtest V=1
8
QTEST_QEMU_BINARY=x86_64-softmmu/qemu-system-x86_64 QTEST_QEMU_IMG=qemu-img tests/ahci-test
9
Failed to execute child process "/tmp/qemu-test.19tMRF/qemu-img" (No such file or directory)
10
ERROR:tests/libqos/libqos.c:192:mkimg: assertion failed: (ret && !err)
7
11
8
Signed-off-by: John Snow <jsnow@redhat.com>
12
Reviewed-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
13
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
10
Reviewed-by: Markus Armbruster <armbru@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
15
---
13
qapi/job.json | 11 ++++++-----
16
tests/Makefile.include | 2 +-
14
1 file changed, 6 insertions(+), 5 deletions(-)
17
1 file changed, 1 insertion(+), 1 deletion(-)
15
18
16
diff --git a/qapi/job.json b/qapi/job.json
19
diff --git a/tests/Makefile.include b/tests/Makefile.include
17
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
18
--- a/qapi/job.json
21
--- a/tests/Makefile.include
19
+++ b/qapi/job.json
22
+++ b/tests/Makefile.include
20
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@ tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y)
21
# the last job in a transaction.
24
tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y)
22
#
25
tests/fdc-test$(EXESUF): tests/fdc-test.o
23
# @pending: The job has finished its work, but has finalization steps that it
26
tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
24
-# needs to make prior to completing. These changes may require
27
-tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y)
25
-# manual intervention by the management process if manual was set
28
+tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) qemu-img$(EXESUF)
26
-# to true. These changes may still fail.
29
tests/ipmi-kcs-test$(EXESUF): tests/ipmi-kcs-test.o
27
+# needs to make prior to completing. These changes will require
30
tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o
28
+# manual intervention via @job-finalize if auto-finalize was set to
31
tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
29
+# false. These pending changes may still fail.
30
#
31
# @aborting: The job is in the process of being aborted, and will finish with
32
# an error. The job will afterwards report that it is @concluded.
33
# This status may not be visible to the management process.
34
#
35
-# @concluded: The job has finished all work. If manual was set to true, the job
36
-# will remain in the query list until it is dismissed.
37
+# @concluded: The job has finished all work. If auto-dismiss was set to false,
38
+# the job will remain in the query list until it is dismissed via
39
+# @job-dismiss.
40
#
41
# @null: The job is in the process of being dismantled. This state should not
42
# ever be visible externally.
43
--
32
--
44
2.13.6
33
2.20.1
45
34
46
35
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
Commit a290f085 exposed a latent bug in qemu-img map introduced
3
Since a9660664fde, some iotests use qemu-nbd.
4
during the conversion of block status to be byte-based. Earlier in
4
Add a dependency to build it before using it.
5
commit 5e344dd8, the internal interface get_block_status() switched
5
This fixes:
6
to take byte-based parameters, but still called a sector-based
7
block layer function; as such, rounding was added in the lone
8
caller to obey the contract. However, commit 237d78f8 changed
9
get_block_status() to truly be byte-based, at which point rounding
10
to sector boundaries can result in calling bdrv_block_status() with
11
'bytes == 0' (a coding error) when the boundary between data and a
12
hole falls mid-sector (true for the past-EOF implicit hole present
13
in POSIX files). Fix things by removing the rounding that is now
14
no longer necessary.
15
6
16
See also https://bugzilla.redhat.com/1589738
7
$ make check-block
8
GEN qemu-img-cmds.h
9
CC qemu-img.o
10
LINK qemu-img
11
CC qemu-io.o
12
LINK qemu-io
13
CC tests/qemu-iotests/socket_scm_helper.o
14
LINK tests/qemu-iotests/socket_scm_helper
15
tests/qemu-iotests-quick.sh
16
check: qemu-nbd not found
17
make: *** [tests/Makefile.include:1059: check-tests/qemu-iotests-quick.sh] Error 1
17
18
18
Fixes: 237d78f8
19
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Reported-by: Dan Kenigsberg <danken@redhat.com>
20
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
20
Reported-by: Nir Soffer <nsoffer@redhat.com>
21
Reported-by: Maor Lipchuk <mlipchuk@redhat.com>
22
CC: qemu-stable@nongnu.org
23
Signed-off-by: Eric Blake <eblake@redhat.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
22
---
26
qemu-img.c | 2 +-
23
tests/Makefile.include | 2 +-
27
1 file changed, 1 insertion(+), 1 deletion(-)
24
1 file changed, 1 insertion(+), 1 deletion(-)
28
25
29
diff --git a/qemu-img.c b/qemu-img.c
26
diff --git a/tests/Makefile.include b/tests/Makefile.include
30
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
31
--- a/qemu-img.c
28
--- a/tests/Makefile.include
32
+++ b/qemu-img.c
29
+++ b/tests/Makefile.include
33
@@ -XXX,XX +XXX,XX @@ static int img_map(int argc, char **argv)
30
@@ -XXX,XX +XXX,XX @@ clean-tcg: $(CLEAN_TCG_TARGET_RULES)
34
int64_t n;
31
QEMU_IOTESTS_HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) = tests/qemu-iotests/socket_scm_helper$(EXESUF)
35
32
36
/* Probe up to 1 GiB at a time. */
33
.PHONY: check-tests/qemu-iotests-quick.sh
37
- n = QEMU_ALIGN_DOWN(MIN(1 << 30, length - offset), BDRV_SECTOR_SIZE);
34
-check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) $(QEMU_IOTESTS_HELPERS-y)
38
+ n = MIN(1 << 30, length - offset);
35
+check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) qemu-nbd$(EXESUF) $(QEMU_IOTESTS_HELPERS-y)
39
ret = get_block_status(bs, offset, n, &next);
36
    $<
40
37
41
if (ret < 0) {
38
.PHONY: $(patsubst %, check-%, $(check-qapi-schema-y))
42
--
39
--
43
2.13.6
40
2.20.1
44
41
45
42
diff view generated by jsdifflib
New patch
1
Be more specific about the string representation in header extensions.
1
2
3
Suggested-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
8
docs/interop/qcow2.txt | 14 ++++++++++++--
9
1 file changed, 12 insertions(+), 2 deletions(-)
10
11
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
12
index XXXXXXX..XXXXXXX 100644
13
--- a/docs/interop/qcow2.txt
14
+++ b/docs/interop/qcow2.txt
15
@@ -XXX,XX +XXX,XX @@ be stored. Each extension has a structure like the following:
16
17
Byte 0 - 3: Header extension type:
18
0x00000000 - End of the header extension area
19
- 0xE2792ACA - Backing file format name
20
+ 0xE2792ACA - Backing file format name string
21
0x6803f857 - Feature name table
22
0x23852875 - Bitmaps extension
23
0x0537be77 - Full disk encryption header pointer
24
- 0x44415441 - External data file name
25
+ 0x44415441 - External data file name string
26
other - Unknown header extension, can be safely
27
ignored
28
29
@@ -XXX,XX +XXX,XX @@ data of compatible features that it doesn't support. Compatible features that
30
need space for additional data can use a header extension.
31
32
33
+== String header extensions ==
34
+
35
+Some header extensions (such as the backing file format name and the external
36
+data file name) are just a single string. In this case, the header extension
37
+length is the string length and the string is not '\0' terminated. (The header
38
+extension padding can make it look like a string is '\0' terminated, but
39
+neither is padding always necessary nor is there a guarantee that zero bytes
40
+are used for padding.)
41
+
42
+
43
== Feature name table ==
44
45
The feature name table is an optional header extension that contains the name
46
--
47
2.20.1
48
49
diff view generated by jsdifflib