1
The following changes since commit 7b1db0908d88f0c9cfac24e214ff72a860692e23:
1
The following changes since commit dfaecc04c46d298e9ee81bd0ca96d8754f1c27ed:
2
2
3
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180323' into staging (2018-03-25 13:51:33 +0100)
3
Merge tag 'pull-riscv-to-apply-20250407-1' of https://github.com/alistair23/qemu into staging (2025-04-07 09:18:33 -0400)
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
https://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to 0b7e7f66813a7e346e12d47be977a32a530a6316:
9
for you to fetch changes up to f8222bfba3409a3ce09c191941127a8cf2c7e623:
10
10
11
qemu-iotests: Test vhdx image creation with QMP (2018-03-26 12:17:43 +0200)
11
test-bdrv-drain: Fix data races (2025-04-08 15:00:01 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches
14
Block layer patches
15
15
16
- scsi-disk: Apply error policy for host_status errors again
17
- qcow2: Fix qemu-img info crash with missing crypto header
18
- qemu-img bench: Fix division by zero for zero-sized images
19
- test-bdrv-drain: Fix data races
20
16
----------------------------------------------------------------
21
----------------------------------------------------------------
17
Alberto Garcia (1):
22
Denis Rastyogin (1):
18
qcow2: Reset free_cluster_index when allocating a new refcount block
23
qemu-img: fix division by zero in bench_cb() for zero-sized images
19
24
20
Eric Blake (1):
25
Kevin Wolf (2):
21
iotests: 163 is not quick
26
qcow2: Don't crash qemu-img info with missing crypto header
27
scsi-disk: Apply error policy for host_status errors again
22
28
23
Fabiano Rosas (5):
29
Vitalii Mordan (1):
24
block/replication: Remove protocol_name field
30
test-bdrv-drain: Fix data races
25
block/quorum: Remove protocol-related fields
26
block/throttle: Remove protocol-related fields
27
block/blkreplay: Remove protocol-related fields
28
include/block/block_int: Document protocol related functions
29
31
30
Kevin Wolf (12):
32
include/qemu/job.h | 3 ++
31
vdi: Change 'static' create option to 'preallocation' in QMP
33
block/qcow2.c | 4 +-
32
vdi: Fix build with CONFIG_VDI_DEBUG
34
hw/scsi/scsi-disk.c | 39 +++++++++-----
33
qemu-iotests: Test vdi image creation with QMP
35
job.c | 6 +++
34
qemu-iotests: Enable 025 for luks
36
qemu-img.c | 6 ++-
35
luks: Turn another invalid assertion into check
37
tests/unit/test-bdrv-drain.c | 32 +++++++-----
36
qemu-iotests: Test invalid resize on luks
38
tests/qemu-iotests/tests/qcow2-encryption | 75 +++++++++++++++++++++++++++
37
parallels: Check maximum cluster size on create
39
tests/qemu-iotests/tests/qcow2-encryption.out | 32 ++++++++++++
38
qemu-iotests: Test parallels image creation with QMP
40
8 files changed, 167 insertions(+), 30 deletions(-)
39
vhdx: Require power-of-two block size on create
41
create mode 100755 tests/qemu-iotests/tests/qcow2-encryption
40
vhdx: Don't use error_setg_errno() with constant errno
42
create mode 100644 tests/qemu-iotests/tests/qcow2-encryption.out
41
vhdx: Check for 4 GB maximum log size on creation
42
qemu-iotests: Test vhdx image creation with QMP
43
44
qapi/block-core.json | 7 +-
45
include/block/block_int.h | 8 ++
46
replication.h | 1 -
47
block/blkreplay.c | 3 +-
48
block/crypto.c | 6 +-
49
block/parallels.c | 5 +
50
block/qcow2-refcount.c | 7 +
51
block/quorum.c | 3 +-
52
block/replication.c | 1 -
53
block/throttle.c | 3 +-
54
block/vdi.c | 46 ++++--
55
block/vhdx.c | 17 ++-
56
tests/qemu-iotests/025 | 9 +-
57
tests/qemu-iotests/026.out | 6 +-
58
tests/qemu-iotests/121 | 20 +++
59
tests/qemu-iotests/121.out | 10 ++
60
tests/qemu-iotests/210 | 37 +++++
61
tests/qemu-iotests/210.out | 16 +++
62
tests/qemu-iotests/211 | 246 ++++++++++++++++++++++++++++++++
63
tests/qemu-iotests/211.out | 97 +++++++++++++
64
tests/qemu-iotests/212 | 326 ++++++++++++++++++++++++++++++++++++++++++
65
tests/qemu-iotests/212.out | 111 ++++++++++++++
66
tests/qemu-iotests/213 | 349 +++++++++++++++++++++++++++++++++++++++++++++
67
tests/qemu-iotests/213.out | 121 ++++++++++++++++
68
tests/qemu-iotests/group | 5 +-
69
25 files changed, 1423 insertions(+), 37 deletions(-)
70
create mode 100755 tests/qemu-iotests/211
71
create mode 100644 tests/qemu-iotests/211.out
72
create mode 100755 tests/qemu-iotests/212
73
create mode 100644 tests/qemu-iotests/212.out
74
create mode 100755 tests/qemu-iotests/213
75
create mode 100644 tests/qemu-iotests/213.out
76
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
Testing on ext4, most 'quick' qcow2 tests took less than 5 seconds,
4
but 163 took more than 20. Let's remove it from the quick set.
5
6
Signed-off-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
tests/qemu-iotests/group | 2 +-
10
1 file changed, 1 insertion(+), 1 deletion(-)
11
12
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
13
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/qemu-iotests/group
15
+++ b/tests/qemu-iotests/group
16
@@ -XXX,XX +XXX,XX @@
17
159 rw auto quick
18
160 rw auto quick
19
162 auto quick
20
-163 rw auto quick
21
+163 rw auto
22
165 rw auto quick
23
169 rw auto quick
24
170 rw auto quick
25
--
26
2.13.6
27
28
diff view generated by jsdifflib
1
From: Fabiano Rosas <farosas@linux.vnet.ibm.com>
1
From: Denis Rastyogin <gerben@altlinux.org>
2
2
3
The quorum driver is not a protocol so it should implement bdrv_open
3
This error was discovered by fuzzing qemu-img.
4
instead of bdrv_file_open and not provide a protocol_name.
5
4
6
Attempts to invoke this driver using protocol syntax
5
This commit fixes a division by zero error in the bench_cb() function
7
(i.e. quorum:<filename:options:...>) will now fail gracefully:
6
that occurs when using the bench command with a zero-sized image.
8
7
9
$ qemu-img info quorum:foo
8
The issue arises because b->image_size can be zero, leading to a
10
qemu-img: Could not open 'quorum:foo': Unknown protocol 'quorum'
9
division by zero in the modulo operation (b->offset %= b->image_size).
10
This patch adds a check for b->image_size == 0 and resets b->offset
11
to 0 in such cases, preventing the error.
11
12
12
Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
13
Signed-off-by: Denis Rastyogin <gerben@altlinux.org>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Message-ID: <20250318101933.255617-1-gerben@altlinux.org>
14
Reviewed-by: Alberto Garcia <berto@igalia.com>
15
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
---
17
block/quorum.c | 3 +--
18
qemu-img.c | 6 +++++-
18
1 file changed, 1 insertion(+), 2 deletions(-)
19
1 file changed, 5 insertions(+), 1 deletion(-)
19
20
20
diff --git a/block/quorum.c b/block/quorum.c
21
diff --git a/qemu-img.c b/qemu-img.c
21
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
22
--- a/block/quorum.c
23
--- a/qemu-img.c
23
+++ b/block/quorum.c
24
+++ b/qemu-img.c
24
@@ -XXX,XX +XXX,XX @@ static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
25
@@ -XXX,XX +XXX,XX @@ static void bench_cb(void *opaque, int ret)
25
26
*/
26
static BlockDriver bdrv_quorum = {
27
b->in_flight++;
27
.format_name = "quorum",
28
b->offset += b->step;
28
- .protocol_name = "quorum",
29
- b->offset %= b->image_size;
29
30
+ if (b->image_size == 0) {
30
.instance_size = sizeof(BDRVQuorumState),
31
+ b->offset = 0;
31
32
+ } else {
32
- .bdrv_file_open = quorum_open,
33
+ b->offset %= b->image_size;
33
+ .bdrv_open = quorum_open,
34
+ }
34
.bdrv_close = quorum_close,
35
if (b->write) {
35
.bdrv_refresh_filename = quorum_refresh_filename,
36
acb = blk_aio_pwritev(b->blk, offset, b->qiov, 0, bench_cb, b);
36
37
} else {
37
--
38
--
38
2.13.6
39
2.49.0
39
40
diff view generated by jsdifflib
1
qcow2_refresh_limits() assumes that s->crypto is non-NULL whenever
2
bs->encrypted is true. This is actually not the case: qcow2_do_open()
3
allows to open an image with a missing crypto header for BDRV_O_NO_IO,
4
and then bs->encrypted is true, but s->crypto is still NULL.
5
6
It doesn't make sense to open an invalid image, so remove the exception
7
for BDRV_O_NO_IO. This catches the problem early and any code that makes
8
the same assumption is safe now.
9
10
At the same time, in the name of defensive programming, we shouldn't
11
make the assumption in the first place. Let qcow2_refresh_limits() check
12
s->crypto rather than bs->encrypted. If s->crypto is NULL, it also can't
13
make any requirement on request alignment.
14
15
Finally, start a qcow2-encryption test case that only serves as a
16
regression test for this crash for now.
17
18
Reported-by: Leonid Reviakin <L.reviakin@fobos-nt.ru>
19
Reported-by: Denis Rastyogin <gerben@altlinux.org>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
Message-ID: <20250318201143.70657-1-kwolf@redhat.com>
22
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
---
24
---
3
tests/qemu-iotests/213 | 349 +++++++++++++++++++++++++++++++++++++++++++++
25
block/qcow2.c | 4 +-
4
tests/qemu-iotests/213.out | 121 ++++++++++++++++
26
tests/qemu-iotests/tests/qcow2-encryption | 75 +++++++++++++++++++
5
tests/qemu-iotests/group | 1 +
27
tests/qemu-iotests/tests/qcow2-encryption.out | 32 ++++++++
6
3 files changed, 471 insertions(+)
28
3 files changed, 109 insertions(+), 2 deletions(-)
7
create mode 100755 tests/qemu-iotests/213
29
create mode 100755 tests/qemu-iotests/tests/qcow2-encryption
8
create mode 100644 tests/qemu-iotests/213.out
30
create mode 100644 tests/qemu-iotests/tests/qcow2-encryption.out
9
31
10
diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213
32
diff --git a/block/qcow2.c b/block/qcow2.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/block/qcow2.c
35
+++ b/block/qcow2.c
36
@@ -XXX,XX +XXX,XX @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
37
ret = -EINVAL;
38
goto fail;
39
}
40
- } else if (!(flags & BDRV_O_NO_IO)) {
41
+ } else {
42
error_setg(errp, "Missing CRYPTO header for crypt method %d",
43
s->crypt_method_header);
44
ret = -EINVAL;
45
@@ -XXX,XX +XXX,XX @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
46
{
47
BDRVQcow2State *s = bs->opaque;
48
49
- if (bs->encrypted) {
50
+ if (s->crypto) {
51
/* Encryption works on a sector granularity */
52
bs->bl.request_alignment = qcrypto_block_get_sector_size(s->crypto);
53
}
54
diff --git a/tests/qemu-iotests/tests/qcow2-encryption b/tests/qemu-iotests/tests/qcow2-encryption
11
new file mode 100755
55
new file mode 100755
12
index XXXXXXX..XXXXXXX
56
index XXXXXXX..XXXXXXX
13
--- /dev/null
57
--- /dev/null
14
+++ b/tests/qemu-iotests/213
58
+++ b/tests/qemu-iotests/tests/qcow2-encryption
15
@@ -XXX,XX +XXX,XX @@
59
@@ -XXX,XX +XXX,XX @@
16
+#!/bin/bash
60
+#!/usr/bin/env bash
61
+# group: rw quick
17
+#
62
+#
18
+# Test vhdx and file image creation
63
+# Test case for encryption support in qcow2
19
+#
64
+#
20
+# Copyright (C) 2018 Red Hat, Inc.
65
+# Copyright (C) 2025 Red Hat, Inc.
21
+#
66
+#
22
+# This program is free software; you can redistribute it and/or modify
67
+# This program is free software; you can redistribute it and/or modify
23
+# it under the terms of the GNU General Public License as published by
68
+# it under the terms of the GNU General Public License as published by
24
+# the Free Software Foundation; either version 2 of the License, or
69
+# the Free Software Foundation; either version 2 of the License, or
25
+# (at your option) any later version.
70
+# (at your option) any later version.
...
...
34
+#
79
+#
35
+
80
+
36
+# creator
81
+# creator
37
+owner=kwolf@redhat.com
82
+owner=kwolf@redhat.com
38
+
83
+
39
+seq=`basename $0`
84
+seq="$(basename $0)"
40
+echo "QA output created by $seq"
85
+echo "QA output created by $seq"
41
+
86
+
42
+here=`pwd`
43
+status=1    # failure is the default!
87
+status=1    # failure is the default!
44
+
88
+
89
+_cleanup()
90
+{
91
+    _cleanup_test_img
92
+}
93
+trap "_cleanup; exit \$status" 0 1 2 3 15
94
+
45
+# get standard environment, filters and checks
95
+# get standard environment, filters and checks
46
+. ./common.rc
96
+. ../common.rc
47
+. ./common.filter
97
+. ../common.filter
48
+
98
+
49
+_supported_fmt vhdx
99
+# This tests qcow2-specific low-level functionality
100
+_supported_fmt qcow2
50
+_supported_proto file
101
+_supported_proto file
51
+_supported_os Linux
102
+_require_working_luks
52
+
103
+
53
+function do_run_qemu()
104
+IMG_SIZE=64M
54
+{
55
+ echo Testing: "$@"
56
+ $QEMU -nographic -qmp stdio -serial none "$@"
57
+ echo
58
+}
59
+
60
+function run_qemu()
61
+{
62
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
63
+ | _filter_qemu | _filter_imgfmt \
64
+ | _filter_actual_image_size
65
+}
66
+
105
+
67
+echo
106
+echo
68
+echo "=== Successful image creation (defaults) ==="
107
+echo "=== Create an encrypted image ==="
69
+echo
108
+echo
70
+
109
+
71
+size=$((128 * 1024 * 1024))
110
+_make_test_img --object secret,id=sec0,data=123456 -o encrypt.format=luks,encrypt.key-secret=sec0 $IMG_SIZE
72
+
111
+$PYTHON ../qcow2.py "$TEST_IMG" dump-header-exts
73
+run_qemu <<EOF
112
+_img_info
74
+{ "execute": "qmp_capabilities" }
113
+$QEMU_IMG check \
75
+{ "execute": "x-blockdev-create",
114
+ --object secret,id=sec0,data=123456 \
76
+ "arguments": {
115
+ --image-opts file.filename="$TEST_IMG",encrypt.key-secret=sec0 \
77
+ "driver": "file",
116
+ | _filter_qemu_img_check
78
+ "filename": "$TEST_IMG",
79
+ "size": 0
80
+ }
81
+}
82
+{ "execute": "blockdev-add",
83
+ "arguments": {
84
+ "driver": "file",
85
+ "node-name": "imgfile",
86
+ "filename": "$TEST_IMG"
87
+ }
88
+}
89
+{ "execute": "x-blockdev-create",
90
+ "arguments": {
91
+ "driver": "$IMGFMT",
92
+ "file": "imgfile",
93
+ "size": $size
94
+ }
95
+}
96
+{ "execute": "quit" }
97
+EOF
98
+
99
+_img_info --format-specific | _filter_img_info --format-specific
100
+
117
+
101
+echo
118
+echo
102
+echo "=== Successful image creation (explicit defaults) ==="
119
+echo "=== Remove the header extension ==="
103
+echo
120
+echo
104
+
121
+
105
+# Choose a different size to show that we got a new image
122
+$PYTHON ../qcow2.py "$TEST_IMG" del-header-ext 0x0537be77
106
+size=$((64 * 1024 * 1024))
123
+$PYTHON ../qcow2.py "$TEST_IMG" dump-header-exts
107
+
124
+_img_info
108
+run_qemu <<EOF
125
+$QEMU_IMG check \
109
+{ "execute": "qmp_capabilities" }
126
+ --object secret,id=sec0,data=123456 \
110
+{ "execute": "x-blockdev-create",
127
+ --image-opts file.filename="$TEST_IMG",encrypt.key-secret=sec0 2>&1 \
111
+ "arguments": {
128
+ | _filter_qemu_img_check \
112
+ "driver": "file",
129
+ | _filter_testdir
113
+ "filename": "$TEST_IMG",
114
+ "size": 0
115
+ }
116
+}
117
+{ "execute": "x-blockdev-create",
118
+ "arguments": {
119
+ "driver": "$IMGFMT",
120
+ "file": {
121
+ "driver": "file",
122
+ "filename": "$TEST_IMG"
123
+ },
124
+ "size": $size,
125
+ "log-size": 1048576,
126
+ "block-size": 8388608,
127
+ "subformat": "dynamic",
128
+ "block-state-zero": true
129
+ }
130
+}
131
+{ "execute": "quit" }
132
+EOF
133
+
134
+_img_info --format-specific | _filter_img_info --format-specific
135
+
136
+echo
137
+echo "=== Successful image creation (with non-default options) ==="
138
+echo
139
+
140
+# Choose a different size to show that we got a new image
141
+size=$((32 * 1024 * 1024))
142
+
143
+run_qemu <<EOF
144
+{ "execute": "qmp_capabilities" }
145
+{ "execute": "x-blockdev-create",
146
+ "arguments": {
147
+ "driver": "file",
148
+ "filename": "$TEST_IMG",
149
+ "size": 0
150
+ }
151
+}
152
+{ "execute": "x-blockdev-create",
153
+ "arguments": {
154
+ "driver": "$IMGFMT",
155
+ "file": {
156
+ "driver": "file",
157
+ "filename": "$TEST_IMG"
158
+ },
159
+ "size": $size,
160
+ "log-size": 8388608,
161
+ "block-size": 268435456,
162
+ "subformat": "fixed",
163
+ "block-state-zero": false
164
+ }
165
+}
166
+{ "execute": "quit" }
167
+EOF
168
+
169
+_img_info --format-specific | _filter_img_info --format-specific
170
+
171
+echo
172
+echo "=== Invalid BlockdevRef ==="
173
+echo
174
+
175
+run_qemu <<EOF
176
+{ "execute": "qmp_capabilities" }
177
+{ "execute": "x-blockdev-create",
178
+ "arguments": {
179
+ "driver": "$IMGFMT",
180
+ "file": "this doesn't exist",
181
+ "size": $size
182
+ }
183
+}
184
+{ "execute": "quit" }
185
+EOF
186
+
187
+echo
188
+echo "=== Zero size ==="
189
+echo
190
+
191
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
192
+{ "execute": "qmp_capabilities" }
193
+{ "execute": "x-blockdev-create",
194
+ "arguments": {
195
+ "driver": "$IMGFMT",
196
+ "file": "node0",
197
+ "size": 0
198
+ }
199
+}
200
+{ "execute": "quit" }
201
+EOF
202
+
203
+_img_info | _filter_img_info
204
+
205
+echo
206
+echo "=== Maximum size ==="
207
+echo
208
+
209
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
210
+{ "execute": "qmp_capabilities" }
211
+{ "execute": "x-blockdev-create",
212
+ "arguments": {
213
+ "driver": "$IMGFMT",
214
+ "file": "node0",
215
+ "size": 70368744177664
216
+ }
217
+}
218
+{ "execute": "quit" }
219
+EOF
220
+
221
+_img_info | _filter_img_info
222
+
223
+echo
224
+echo "=== Invalid sizes ==="
225
+echo
226
+
227
+# TODO Negative image sizes aren't handled correctly, but this is a problem
228
+# with QAPI's implementation of the 'size' type and affects other commands as
229
+# well. Once this is fixed, we may want to add a test case here.
230
+
231
+# 1. 2^64 - 512
232
+# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
233
+# 3. 2^63 - 512 (generally valid, but with the image header the file will
234
+# exceed 63 bits)
235
+# 4. 2^46 + 1 (one byte more than maximum image size)
236
+
237
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
238
+{ "execute": "qmp_capabilities" }
239
+{ "execute": "x-blockdev-create",
240
+ "arguments": {
241
+ "driver": "$IMGFMT",
242
+ "file": "node0",
243
+ "size": 18446744073709551104
244
+ }
245
+}
246
+{ "execute": "x-blockdev-create",
247
+ "arguments": {
248
+ "driver": "$IMGFMT",
249
+ "file": "node0",
250
+ "size": 9223372036854775808
251
+ }
252
+}
253
+{ "execute": "x-blockdev-create",
254
+ "arguments": {
255
+ "driver": "$IMGFMT",
256
+ "file": "node0",
257
+ "size": 9223372036854775296
258
+ }
259
+}
260
+{ "execute": "x-blockdev-create",
261
+ "arguments": {
262
+ "driver": "$IMGFMT",
263
+ "file": "node0",
264
+ "size": 70368744177665
265
+ }
266
+}
267
+{ "execute": "quit" }
268
+EOF
269
+
270
+echo
271
+echo "=== Invalid block size ==="
272
+echo
273
+
274
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
275
+{ "execute": "qmp_capabilities" }
276
+{ "execute": "x-blockdev-create",
277
+ "arguments": {
278
+ "driver": "$IMGFMT",
279
+ "file": "node0",
280
+ "size": 67108864,
281
+ "block-size": 1234567
282
+ }
283
+}
284
+{ "execute": "x-blockdev-create",
285
+ "arguments": {
286
+ "driver": "$IMGFMT",
287
+ "file": "node0",
288
+ "size": 67108864,
289
+ "block-size": 128
290
+ }
291
+}
292
+{ "execute": "x-blockdev-create",
293
+ "arguments": {
294
+ "driver": "$IMGFMT",
295
+ "file": "node0",
296
+ "size": 67108864,
297
+ "block-size": 3145728
298
+ }
299
+}
300
+{ "execute": "x-blockdev-create",
301
+ "arguments": {
302
+ "driver": "$IMGFMT",
303
+ "file": "node0",
304
+ "size": 67108864,
305
+ "block-size": 536870912
306
+ }
307
+}
308
+{ "execute": "x-blockdev-create",
309
+ "arguments": {
310
+ "driver": "$IMGFMT",
311
+ "file": "node0",
312
+ "size": 67108864,
313
+ "block-size": 0
314
+ }
315
+}
316
+{ "execute": "quit" }
317
+EOF
318
+
319
+echo
320
+echo "=== Invalid log size ==="
321
+echo
322
+
323
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
324
+{ "execute": "qmp_capabilities" }
325
+{ "execute": "x-blockdev-create",
326
+ "arguments": {
327
+ "driver": "$IMGFMT",
328
+ "file": "node0",
329
+ "size": 67108864,
330
+ "log-size": 1234567
331
+ }
332
+}
333
+{ "execute": "x-blockdev-create",
334
+ "arguments": {
335
+ "driver": "$IMGFMT",
336
+ "file": "node0",
337
+ "size": 67108864,
338
+ "log-size": 128
339
+ }
340
+}
341
+{ "execute": "x-blockdev-create",
342
+ "arguments": {
343
+ "driver": "$IMGFMT",
344
+ "file": "node0",
345
+ "size": 67108864,
346
+ "log-size": 4294967296
347
+ }
348
+}
349
+{ "execute": "x-blockdev-create",
350
+ "arguments": {
351
+ "driver": "$IMGFMT",
352
+ "file": "node0",
353
+ "size": 67108864,
354
+ "log-size": 0
355
+ }
356
+}
357
+{ "execute": "quit" }
358
+EOF
359
+
360
+
130
+
361
+# success, all done
131
+# success, all done
362
+echo "*** done"
132
+echo "*** done"
363
+rm -f $seq.full
133
+rm -f $seq.full
364
+status=0
134
+status=0
365
diff --git a/tests/qemu-iotests/213.out b/tests/qemu-iotests/213.out
135
diff --git a/tests/qemu-iotests/tests/qcow2-encryption.out b/tests/qemu-iotests/tests/qcow2-encryption.out
366
new file mode 100644
136
new file mode 100644
367
index XXXXXXX..XXXXXXX
137
index XXXXXXX..XXXXXXX
368
--- /dev/null
138
--- /dev/null
369
+++ b/tests/qemu-iotests/213.out
139
+++ b/tests/qemu-iotests/tests/qcow2-encryption.out
370
@@ -XXX,XX +XXX,XX @@
140
@@ -XXX,XX +XXX,XX @@
371
+QA output created by 213
141
+QA output created by qcow2-encryption
372
+
142
+
373
+=== Successful image creation (defaults) ===
143
+=== Create an encrypted image ===
374
+
144
+
375
+Testing:
145
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
376
+QMP_VERSION
146
+Header extension:
377
+{"return": {}}
147
+magic 0x537be77 (Crypto header)
378
+{"return": {}}
148
+length 16
379
+{"return": {}}
149
+data <binary>
380
+{"return": {}}
150
+
381
+{"return": {}}
151
+Header extension:
382
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
152
+magic 0x6803f857 (Feature table)
153
+length 384
154
+data <binary>
383
+
155
+
384
+image: TEST_DIR/t.IMGFMT
156
+image: TEST_DIR/t.IMGFMT
385
+file format: IMGFMT
157
+file format: IMGFMT
386
+virtual size: 128M (134217728 bytes)
158
+virtual size: 64 MiB (67108864 bytes)
159
+encrypted: yes
160
+cluster_size: 65536
161
+No errors were found on the image.
387
+
162
+
388
+=== Successful image creation (explicit defaults) ===
163
+=== Remove the header extension ===
389
+
164
+
390
+Testing:
165
+Header extension:
391
+QMP_VERSION
166
+magic 0x6803f857 (Feature table)
392
+{"return": {}}
167
+length 384
393
+{"return": {}}
168
+data <binary>
394
+{"return": {}}
395
+{"return": {}}
396
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
397
+
169
+
398
+image: TEST_DIR/t.IMGFMT
170
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Missing CRYPTO header for crypt method 2
399
+file format: IMGFMT
171
+qemu-img: Could not open 'file.filename=TEST_DIR/t.qcow2,encrypt.key-secret=sec0': Missing CRYPTO header for crypt method 2
400
+virtual size: 64M (67108864 bytes)
401
+
402
+=== Successful image creation (with non-default options) ===
403
+
404
+Testing:
405
+QMP_VERSION
406
+{"return": {}}
407
+{"return": {}}
408
+{"return": {}}
409
+{"return": {}}
410
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
411
+
412
+image: TEST_DIR/t.IMGFMT
413
+file format: IMGFMT
414
+virtual size: 32M (33554432 bytes)
415
+
416
+=== Invalid BlockdevRef ===
417
+
418
+Testing:
419
+QMP_VERSION
420
+{"return": {}}
421
+{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
422
+{"return": {}}
423
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
424
+
425
+
426
+=== Zero size ===
427
+
428
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
429
+QMP_VERSION
430
+{"return": {}}
431
+{"return": {}}
432
+{"return": {}}
433
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
434
+
435
+image: TEST_DIR/t.IMGFMT
436
+file format: IMGFMT
437
+virtual size: 0 (0 bytes)
438
+
439
+=== Maximum size ===
440
+
441
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
442
+QMP_VERSION
443
+{"return": {}}
444
+{"return": {}}
445
+{"return": {}}
446
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
447
+
448
+image: TEST_DIR/t.IMGFMT
449
+file format: IMGFMT
450
+virtual size: 64T (70368744177664 bytes)
451
+
452
+=== Invalid sizes ===
453
+
454
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
455
+QMP_VERSION
456
+{"return": {}}
457
+{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
458
+{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
459
+{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
460
+{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
461
+{"return": {}}
462
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
463
+
464
+
465
+=== Invalid block size ===
466
+
467
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
468
+QMP_VERSION
469
+{"return": {}}
470
+{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
471
+{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
472
+{"error": {"class": "GenericError", "desc": "Block size must be a power of two"}}
473
+{"error": {"class": "GenericError", "desc": "Block size must not exceed 268435456"}}
474
+{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
475
+{"return": {}}
476
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
477
+
478
+
479
+=== Invalid log size ===
480
+
481
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
482
+QMP_VERSION
483
+{"return": {}}
484
+{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
485
+{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
486
+{"error": {"class": "GenericError", "desc": "Log size must be smaller than 4 GB"}}
487
+{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
488
+{"return": {}}
489
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
490
+
491
+*** done
172
+*** done
492
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
493
index XXXXXXX..XXXXXXX 100644
494
--- a/tests/qemu-iotests/group
495
+++ b/tests/qemu-iotests/group
496
@@ -XXX,XX +XXX,XX @@
497
210 rw auto
498
211 rw auto quick
499
212 rw auto quick
500
+213 rw auto quick
501
--
173
--
502
2.13.6
174
2.49.0
503
175
504
176
diff view generated by jsdifflib
1
From: Fabiano Rosas <farosas@linux.vnet.ibm.com>
1
Originally, all failed SG_IO requests called scsi_handle_rw_error() to
2
apply the configured error policy. However, commit f3126d65, which was
3
supposed to be a mere refactoring for scsi-disk.c, broke this and
4
accidentally completed the SCSI request without considering the error
5
policy any more if the error was signalled in the host_status field.
2
6
3
The protocol_name field is used when selecting a driver via protocol
7
Apart from the commit message not describing the change as intended,
4
syntax (i.e. <protocol_name>:<filename:options:...>). Drivers that are
8
errors indicated in host_status are also obviously backend errors and
5
only selected explicitly (e.g. driver=replication,mode=primary,...)
9
not something the guest must deal with independently of the error
6
should not have a protocol_name.
10
policy.
7
11
8
This patch removes the protocol_name field from the brdv_replication
12
This behaviour means that some recoverable errors (such as a path error
9
structure so that attempts to invoke this driver using protocol syntax
13
in multipath configurations) were reported to the guest anyway, which
10
will fail gracefully:
14
might not expect it and might consider its disk broken.
11
15
12
$ qemu-img info replication:foo
16
Make sure that we apply the error policy again for host_status errors,
13
qemu-img: Could not open 'replication:': Unknown protocol 'replication'
17
too. This addresses an existing FIXME comment and allows us to remove
18
some comments warning that callbacks weren't always called. With this
19
fix, they are called in all cases again.
14
20
15
Buglink: https://bugs.launchpad.net/qemu/+bug/1726733
21
The return value passed to the request callback doesn't have more free
16
Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
22
values that could be used to indicate host_status errors as well as SAM
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
23
status codes and negative errno. Store the value in the host_status
24
field of the SCSIRequest instead and use -ENODEV as the return value (if
25
a path hasn't been reachable for a while, blk_aio_ioctl() will return
26
-ENODEV instead of just setting host_status, so just reuse it here -
27
it's not necessarily entirely accurate, but it's as good as any errno).
28
29
Cc: qemu-stable@nongnu.org
30
Fixes: f3126d65b393 ('scsi: move host_status handling into SCSI drivers')
31
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
32
Message-ID: <20250407155949.44736-1-kwolf@redhat.com>
33
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
34
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
35
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
36
---
20
replication.h | 1 -
37
hw/scsi/scsi-disk.c | 39 +++++++++++++++++++++++++--------------
21
block/replication.c | 1 -
38
1 file changed, 25 insertions(+), 14 deletions(-)
22
2 files changed, 2 deletions(-)
23
39
24
diff --git a/replication.h b/replication.h
40
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
25
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
26
--- a/replication.h
42
--- a/hw/scsi/scsi-disk.c
27
+++ b/replication.h
43
+++ b/hw/scsi/scsi-disk.c
28
@@ -XXX,XX +XXX,XX @@ typedef struct ReplicationState ReplicationState;
44
@@ -XXX,XX +XXX,XX @@ struct SCSIDiskClass {
29
*
45
SCSIDeviceClass parent_class;
30
* BlockDriver bdrv_replication = {
46
/*
31
* .format_name = "replication",
47
* Callbacks receive ret == 0 for success. Errors are represented either as
32
- * .protocol_name = "replication",
48
- * negative errno values, or as positive SAM status codes.
33
* .instance_size = sizeof(BDRVReplicationState),
49
- *
34
*
50
- * Beware: For errors returned in host_status, the function may directly
35
* .bdrv_open = replication_open,
51
- * complete the request and never call the callback.
36
diff --git a/block/replication.c b/block/replication.c
52
+ * negative errno values, or as positive SAM status codes. For host_status
37
index XXXXXXX..XXXXXXX 100644
53
+ * errors, the function passes ret == -ENODEV and sets the host_status field
38
--- a/block/replication.c
54
+ * of the SCSIRequest.
39
+++ b/block/replication.c
55
*/
40
@@ -XXX,XX +XXX,XX @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
56
DMAIOFunc *dma_readv;
41
57
DMAIOFunc *dma_writev;
42
BlockDriver bdrv_replication = {
58
@@ -XXX,XX +XXX,XX @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
43
.format_name = "replication",
59
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
44
- .protocol_name = "replication",
60
SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
45
.instance_size = sizeof(BDRVReplicationState),
61
SCSISense sense = SENSE_CODE(NO_SENSE);
46
62
+ int16_t host_status;
47
.bdrv_open = replication_open,
63
int error;
64
bool req_has_sense = false;
65
BlockErrorAction action;
66
int status;
67
68
+ /*
69
+ * host_status should only be set for SG_IO requests that came back with a
70
+ * host_status error in scsi_block_sgio_complete(). This error path passes
71
+ * -ENODEV as the return value.
72
+ *
73
+ * Reset host_status in the request because we may still want to complete
74
+ * the request successfully with the 'stop' or 'ignore' error policy.
75
+ */
76
+ host_status = r->req.host_status;
77
+ if (host_status != -1) {
78
+ assert(ret == -ENODEV);
79
+ r->req.host_status = -1;
80
+ }
81
+
82
if (ret < 0) {
83
status = scsi_sense_from_errno(-ret, &sense);
84
error = -ret;
85
@@ -XXX,XX +XXX,XX @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
86
if (acct_failed) {
87
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
88
}
89
+ if (host_status != -1) {
90
+ scsi_req_complete_failed(&r->req, host_status);
91
+ return true;
92
+ }
93
if (req_has_sense) {
94
sdc->update_sense(&r->req);
95
} else if (status == CHECK_CONDITION) {
96
@@ -XXX,XX +XXX,XX @@ done:
97
scsi_req_unref(&r->req);
98
}
99
100
-/* May not be called in all error cases, don't rely on cleanup here */
101
static void scsi_dma_complete(void *opaque, int ret)
102
{
103
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
104
@@ -XXX,XX +XXX,XX @@ done:
105
scsi_req_unref(&r->req);
106
}
107
108
-/* May not be called in all error cases, don't rely on cleanup here */
109
static void scsi_read_complete(void *opaque, int ret)
110
{
111
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
112
@@ -XXX,XX +XXX,XX @@ done:
113
scsi_req_unref(&r->req);
114
}
115
116
-/* May not be called in all error cases, don't rely on cleanup here */
117
static void scsi_write_complete(void * opaque, int ret)
118
{
119
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
120
@@ -XXX,XX +XXX,XX @@ static void scsi_block_sgio_complete(void *opaque, int ret)
121
sg_io_hdr_t *io_hdr = &req->io_header;
122
123
if (ret == 0) {
124
- /* FIXME This skips calling req->cb() and any cleanup in it */
125
if (io_hdr->host_status != SCSI_HOST_OK) {
126
- scsi_req_complete_failed(&r->req, io_hdr->host_status);
127
- scsi_req_unref(&r->req);
128
- return;
129
- }
130
-
131
- if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
132
+ r->req.host_status = io_hdr->host_status;
133
+ ret = -ENODEV;
134
+ } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
135
ret = BUSY;
136
} else {
137
ret = io_hdr->status;
48
--
138
--
49
2.13.6
139
2.49.0
50
51
diff view generated by jsdifflib
Deleted patch
1
From: Fabiano Rosas <farosas@linux.vnet.ibm.com>
2
1
3
The throttle driver is not a protocol so it should implement bdrv_open
4
instead of bdrv_file_open and not provide a protocol_name.
5
6
Attempts to invoke this driver using protocol syntax
7
(i.e. throttle:<filename:options:...>) will now fail gracefully:
8
9
$ qemu-img info throttle:foo
10
qemu-img: Could not open 'throttle:foo': Unknown protocol 'throttle'
11
12
Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Alberto Garcia <berto@igalia.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block/throttle.c | 3 +--
18
1 file changed, 1 insertion(+), 2 deletions(-)
19
20
diff --git a/block/throttle.c b/block/throttle.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/throttle.c
23
+++ b/block/throttle.c
24
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs)
25
26
static BlockDriver bdrv_throttle = {
27
.format_name = "throttle",
28
- .protocol_name = "throttle",
29
.instance_size = sizeof(ThrottleGroupMember),
30
31
- .bdrv_file_open = throttle_open,
32
+ .bdrv_open = throttle_open,
33
.bdrv_close = throttle_close,
34
.bdrv_co_flush = throttle_co_flush,
35
36
--
37
2.13.6
38
39
diff view generated by jsdifflib
Deleted patch
1
From: Fabiano Rosas <farosas@linux.vnet.ibm.com>
2
1
3
The blkreplay driver is not a protocol so it should implement bdrv_open
4
instead of bdrv_file_open and not provide a protocol_name.
5
6
Attempts to invoke this driver using protocol syntax
7
(i.e. blkreplay:<filename:options:...>) will now fail gracefully:
8
9
$ qemu-img info blkreplay:foo
10
qemu-img: Could not open 'blkreplay:foo': Unknown protocol 'blkreplay'
11
12
Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
13
Reviewed-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block/blkreplay.c | 3 +--
18
1 file changed, 1 insertion(+), 2 deletions(-)
19
20
diff --git a/block/blkreplay.c b/block/blkreplay.c
21
index XXXXXXX..XXXXXXX 100755
22
--- a/block/blkreplay.c
23
+++ b/block/blkreplay.c
24
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
25
26
static BlockDriver bdrv_blkreplay = {
27
.format_name = "blkreplay",
28
- .protocol_name = "blkreplay",
29
.instance_size = 0,
30
31
- .bdrv_file_open = blkreplay_open,
32
+ .bdrv_open = blkreplay_open,
33
.bdrv_close = blkreplay_close,
34
.bdrv_child_perm = bdrv_filter_default_perms,
35
.bdrv_getlength = blkreplay_getlength,
36
--
37
2.13.6
38
39
diff view generated by jsdifflib
Deleted patch
1
From: Fabiano Rosas <farosas@linux.vnet.ibm.com>
2
1
3
Clarify that:
4
5
- for protocols the brdv_file_open function is used instead
6
of bdrv_open;
7
8
- when protocol_name is set, a driver should expect
9
to be given only a filename and no other options.
10
11
Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
include/block/block_int.h | 8 ++++++++
15
1 file changed, 8 insertions(+)
16
17
diff --git a/include/block/block_int.h b/include/block/block_int.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/block/block_int.h
20
+++ b/include/block/block_int.h
21
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
22
23
int (*bdrv_open)(BlockDriverState *bs, QDict *options, int flags,
24
Error **errp);
25
+
26
+ /* Protocol drivers should implement this instead of bdrv_open */
27
int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags,
28
Error **errp);
29
void (*bdrv_close)(BlockDriverState *bs);
30
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
31
*/
32
int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs);
33
34
+ /*
35
+ * Drivers setting this field must be able to work with just a plain
36
+ * filename with '<protocol_name>:' as a prefix, and no other options.
37
+ * Options may be extracted from the filename by implementing
38
+ * bdrv_parse_filename.
39
+ */
40
const char *protocol_name;
41
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset,
42
PreallocMode prealloc, Error **errp);
43
--
44
2.13.6
45
46
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
When we try to allocate new clusters we first look for available ones
4
starting from s->free_cluster_index and once we find them we increase
5
their reference counts. Before we get to call update_refcount() to do
6
this last step s->free_cluster_index is already pointing to the next
7
cluster after the ones we are trying to allocate.
8
9
During update_refcount() it may happen however that we also need to
10
allocate a new refcount block in order to store the refcounts of these
11
new clusters (and to complicate things further that may also require
12
us to grow the refcount table). After all this we don't know if the
13
clusters that we originally tried to allocate are still available, so
14
we return -EAGAIN to ask the caller to restart the search for free
15
clusters.
16
17
This is what can happen in a common scenario:
18
19
1) We want to allocate a new cluster and we see that cluster N is
20
free.
21
22
2) We try to increase N's refcount but all refcount blocks are full,
23
so we allocate a new one at N+1 (where s->free_cluster_index was
24
pointing at).
25
26
3) Once we're done we return -EAGAIN to look again for a free
27
cluster, but now s->free_cluster_index points at N+2, so that's
28
the one we allocate. Cluster N remains unallocated and we have a
29
hole in the qcow2 file.
30
31
This can be reproduced easily:
32
33
qemu-img create -f qcow2 -o cluster_size=512 hd.qcow2 1M
34
qemu-io -c 'write 0 124k' hd.qcow2
35
36
After this the image has 132608 bytes (256 clusters), and the refcount
37
block is full. If we write 512 more bytes it should allocate two new
38
clusters: the data cluster itself and a new refcount block.
39
40
qemu-io -c 'write 124k 512' hd.qcow2
41
42
However the image has now three new clusters (259 in total), and the
43
first one of them is empty (and unallocated):
44
45
dd if=hd.qcow2 bs=512c skip=256 count=1 | hexdump -C
46
47
If we write larger amounts of data in the last step instead of the 512
48
bytes used in this example we can create larger holes in the qcow2
49
file.
50
51
What this patch does is reset s->free_cluster_index to its previous
52
value when alloc_refcount_block() returns -EAGAIN. This way the caller
53
will try to allocate again the original clusters if they are still
54
free.
55
56
The output of iotest 026 also needs to be updated because now that
57
images have no holes some tests fail at a different point and the
58
number of leaked clusters is different.
59
60
Signed-off-by: Alberto Garcia <berto@igalia.com>
61
Reviewed-by: Eric Blake <eblake@redhat.com>
62
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
63
---
64
block/qcow2-refcount.c | 7 +++++++
65
tests/qemu-iotests/026.out | 6 +++---
66
tests/qemu-iotests/121 | 20 ++++++++++++++++++++
67
tests/qemu-iotests/121.out | 10 ++++++++++
68
4 files changed, 40 insertions(+), 3 deletions(-)
69
70
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/block/qcow2-refcount.c
73
+++ b/block/qcow2-refcount.c
74
@@ -XXX,XX +XXX,XX @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
75
qcow2_cache_put(s->refcount_block_cache, &refcount_block);
76
}
77
ret = alloc_refcount_block(bs, cluster_index, &refcount_block);
78
+ /* If the caller needs to restart the search for free clusters,
79
+ * try the same ones first to see if they're still free. */
80
+ if (ret == -EAGAIN) {
81
+ if (s->free_cluster_index > (start >> s->cluster_bits)) {
82
+ s->free_cluster_index = (start >> s->cluster_bits);
83
+ }
84
+ }
85
if (ret < 0) {
86
goto fail;
87
}
88
diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out
89
index XXXXXXX..XXXXXXX 100644
90
--- a/tests/qemu-iotests/026.out
91
+++ b/tests/qemu-iotests/026.out
92
@@ -XXX,XX +XXX,XX @@ Failed to flush the L2 table cache: No space left on device
93
Failed to flush the refcount block cache: No space left on device
94
write failed: No space left on device
95
96
-11 leaked clusters were found on the image.
97
+10 leaked clusters were found on the image.
98
This means waste of disk space, but no harm to data.
99
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
100
101
@@ -XXX,XX +XXX,XX @@ Failed to flush the L2 table cache: No space left on device
102
Failed to flush the refcount block cache: No space left on device
103
write failed: No space left on device
104
105
-11 leaked clusters were found on the image.
106
+10 leaked clusters were found on the image.
107
This means waste of disk space, but no harm to data.
108
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
109
110
@@ -XXX,XX +XXX,XX @@ Failed to flush the L2 table cache: No space left on device
111
Failed to flush the refcount block cache: No space left on device
112
write failed: No space left on device
113
114
-11 leaked clusters were found on the image.
115
+10 leaked clusters were found on the image.
116
This means waste of disk space, but no harm to data.
117
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
118
119
diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121
120
index XXXXXXX..XXXXXXX 100755
121
--- a/tests/qemu-iotests/121
122
+++ b/tests/qemu-iotests/121
123
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'write 63M 130K' "$TEST_IMG" | _filter_qemu_io
124
125
_check_test_img
126
127
+echo
128
+echo '=== Allocating a new refcount block must not leave holes in the image ==='
129
+echo
130
+
131
+IMGOPTS='cluster_size=512,refcount_bits=16' _make_test_img 1M
132
+
133
+# This results in an image with 256 used clusters: the qcow2 header,
134
+# the refcount table, one refcount block, the L1 table, four L2 tables
135
+# and 248 data clusters
136
+$QEMU_IO -c 'write 0 124k' "$TEST_IMG" | _filter_qemu_io
137
+
138
+# 256 clusters of 512 bytes each give us a 128K image
139
+stat -c "size=%s (expected 131072)" $TEST_IMG
140
+
141
+# All 256 entries of the refcount block are used, so writing a new
142
+# data cluster also allocates a new refcount block
143
+$QEMU_IO -c 'write 124k 512' "$TEST_IMG" | _filter_qemu_io
144
+
145
+# Two more clusters, the image size should be 129K now
146
+stat -c "size=%s (expected 132096)" $TEST_IMG
147
148
# success, all done
149
echo
150
diff --git a/tests/qemu-iotests/121.out b/tests/qemu-iotests/121.out
151
index XXXXXXX..XXXXXXX 100644
152
--- a/tests/qemu-iotests/121.out
153
+++ b/tests/qemu-iotests/121.out
154
@@ -XXX,XX +XXX,XX @@ wrote 133120/133120 bytes at offset 66060288
155
130 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
156
No errors were found on the image.
157
158
+=== Allocating a new refcount block must not leave holes in the image ===
159
+
160
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
161
+wrote 126976/126976 bytes at offset 0
162
+124 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
163
+size=131072 (expected 131072)
164
+wrote 512/512 bytes at offset 126976
165
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
166
+size=132096 (expected 132096)
167
+
168
*** done
169
--
170
2.13.6
171
172
diff view generated by jsdifflib
Deleted patch
1
What static=on really does is what we call metadata preallocation for
2
other block drivers. While we can still change the QMP interface, make
3
it more consistent by using 'preallocation' for VDI, too.
4
1
5
This doesn't implement any new functionality, so the only supported
6
preallocation modes are 'off' and 'metadata' for now.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
---
11
qapi/block-core.json | 7 +++----
12
block/vdi.c | 24 ++++++++++++++++++++++--
13
2 files changed, 25 insertions(+), 6 deletions(-)
14
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
16
index XXXXXXX..XXXXXXX 100644
17
--- a/qapi/block-core.json
18
+++ b/qapi/block-core.json
19
@@ -XXX,XX +XXX,XX @@
20
#
21
# @file Node to create the image format on
22
# @size Size of the virtual disk in bytes
23
-# @static Whether to create a statically (true) or
24
-# dynamically (false) allocated image
25
-# (default: false, i.e. dynamic)
26
+# @preallocation Preallocation mode for the new image (allowed values: off,
27
+# metadata; default: off)
28
#
29
# Since: 2.12
30
##
31
{ 'struct': 'BlockdevCreateOptionsVdi',
32
'data': { 'file': 'BlockdevRef',
33
'size': 'size',
34
- '*static': 'bool' } }
35
+ '*preallocation': 'PreallocMode' } }
36
37
##
38
# @BlockdevVhdxSubformat:
39
diff --git a/block/vdi.c b/block/vdi.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block/vdi.c
42
+++ b/block/vdi.c
43
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
44
int ret = 0;
45
uint64_t bytes = 0;
46
uint32_t blocks;
47
- uint32_t image_type = VDI_TYPE_DYNAMIC;
48
+ uint32_t image_type;
49
VdiHeader header;
50
size_t i;
51
size_t bmap_size;
52
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
53
54
/* Validate options and set default values */
55
bytes = vdi_opts->size;
56
- if (vdi_opts->q_static) {
57
+
58
+ if (!vdi_opts->has_preallocation) {
59
+ vdi_opts->preallocation = PREALLOC_MODE_OFF;
60
+ }
61
+ switch (vdi_opts->preallocation) {
62
+ case PREALLOC_MODE_OFF:
63
+ image_type = VDI_TYPE_DYNAMIC;
64
+ break;
65
+ case PREALLOC_MODE_METADATA:
66
image_type = VDI_TYPE_STATIC;
67
+ break;
68
+ default:
69
+ error_setg(errp, "Preallocation mode not supported for vdi");
70
+ return -EINVAL;
71
}
72
+
73
#ifndef CONFIG_VDI_STATIC_IMAGE
74
if (image_type == VDI_TYPE_STATIC) {
75
ret = -ENOTSUP;
76
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
77
BlockdevCreateOptions *create_options = NULL;
78
BlockDriverState *bs_file = NULL;
79
uint64_t block_size = DEFAULT_CLUSTER_SIZE;
80
+ bool is_static = false;
81
Visitor *v;
82
Error *local_err = NULL;
83
int ret;
84
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
85
goto done;
86
}
87
#endif
88
+ if (qemu_opt_get_bool_del(opts, BLOCK_OPT_STATIC, false)) {
89
+ is_static = true;
90
+ }
91
92
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vdi_create_opts, true);
93
94
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
95
96
qdict_put_str(qdict, "driver", "vdi");
97
qdict_put_str(qdict, "file", bs_file->node_name);
98
+ if (is_static) {
99
+ qdict_put_str(qdict, "preallocation", "metadata");
100
+ }
101
102
/* Get the QAPI object */
103
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
104
--
105
2.13.6
106
107
diff view generated by jsdifflib
Deleted patch
1
Use qemu_uuid_unparse() instead of uuid_unparse() to make vdi.c compile
2
again when CONFIG_VDI_DEBUG is set. In order to prevent future bitrot,
3
replace '#ifdef CONFIG_VDI_DEBUG' by 'if (VDI_DEBUG)' so that the
4
compiler always sees the code.
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
---
9
block/vdi.c | 22 ++++++++++------------
10
1 file changed, 10 insertions(+), 12 deletions(-)
11
12
diff --git a/block/vdi.c b/block/vdi.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block/vdi.c
15
+++ b/block/vdi.c
16
@@ -XXX,XX +XXX,XX @@ static void vdi_header_to_le(VdiHeader *header)
17
qemu_uuid_bswap(&header->uuid_parent);
18
}
19
20
-#if defined(CONFIG_VDI_DEBUG)
21
static void vdi_header_print(VdiHeader *header)
22
{
23
char uuid[37];
24
@@ -XXX,XX +XXX,XX @@ static void vdi_header_print(VdiHeader *header)
25
logout("block extra 0x%04x\n", header->block_extra);
26
logout("blocks tot. 0x%04x\n", header->blocks_in_image);
27
logout("blocks all. 0x%04x\n", header->blocks_allocated);
28
- uuid_unparse(header->uuid_image, uuid);
29
+ qemu_uuid_unparse(&header->uuid_image, uuid);
30
logout("uuid image %s\n", uuid);
31
- uuid_unparse(header->uuid_last_snap, uuid);
32
+ qemu_uuid_unparse(&header->uuid_last_snap, uuid);
33
logout("uuid snap %s\n", uuid);
34
- uuid_unparse(header->uuid_link, uuid);
35
+ qemu_uuid_unparse(&header->uuid_link, uuid);
36
logout("uuid link %s\n", uuid);
37
- uuid_unparse(header->uuid_parent, uuid);
38
+ qemu_uuid_unparse(&header->uuid_parent, uuid);
39
logout("uuid parent %s\n", uuid);
40
}
41
-#endif
42
43
static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res,
44
BdrvCheckMode fix)
45
@@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
46
}
47
48
vdi_header_to_cpu(&header);
49
-#if defined(CONFIG_VDI_DEBUG)
50
- vdi_header_print(&header);
51
-#endif
52
+ if (VDI_DEBUG) {
53
+ vdi_header_print(&header);
54
+ }
55
56
if (header.disk_size > VDI_DISK_SIZE_MAX) {
57
error_setg(errp, "Unsupported VDI image size (size is 0x%" PRIx64
58
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
59
qemu_uuid_generate(&header.uuid_image);
60
qemu_uuid_generate(&header.uuid_last_snap);
61
/* There is no need to set header.uuid_link or header.uuid_parent here. */
62
-#if defined(CONFIG_VDI_DEBUG)
63
- vdi_header_print(&header);
64
-#endif
65
+ if (VDI_DEBUG) {
66
+ vdi_header_print(&header);
67
+ }
68
vdi_header_to_le(&header);
69
ret = blk_pwrite(blk, offset, &header, sizeof(header), 0);
70
if (ret < 0) {
71
--
72
2.13.6
73
74
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
---
4
tests/qemu-iotests/211 | 246 +++++++++++++++++++++++++++++++++++++++++++++
5
tests/qemu-iotests/211.out | 97 ++++++++++++++++++
6
tests/qemu-iotests/group | 1 +
7
3 files changed, 344 insertions(+)
8
create mode 100755 tests/qemu-iotests/211
9
create mode 100644 tests/qemu-iotests/211.out
10
1
11
diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211
12
new file mode 100755
13
index XXXXXXX..XXXXXXX
14
--- /dev/null
15
+++ b/tests/qemu-iotests/211
16
@@ -XXX,XX +XXX,XX @@
17
+#!/bin/bash
18
+#
19
+# Test VDI and file image creation
20
+#
21
+# Copyright (C) 2018 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
+here=`pwd`
44
+status=1    # failure is the default!
45
+
46
+# get standard environment, filters and checks
47
+. ./common.rc
48
+. ./common.filter
49
+
50
+_supported_fmt vdi
51
+_supported_proto file
52
+_supported_os Linux
53
+
54
+function do_run_qemu()
55
+{
56
+ echo Testing: "$@"
57
+ $QEMU -nographic -qmp stdio -serial none "$@"
58
+ echo
59
+}
60
+
61
+function run_qemu()
62
+{
63
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
64
+ | _filter_qemu | _filter_imgfmt \
65
+ | _filter_actual_image_size
66
+}
67
+
68
+echo
69
+echo "=== Successful image creation (defaults) ==="
70
+echo
71
+
72
+size=$((128 * 1024 * 1024))
73
+
74
+run_qemu <<EOF
75
+{ "execute": "qmp_capabilities" }
76
+{ "execute": "x-blockdev-create",
77
+ "arguments": {
78
+ "driver": "file",
79
+ "filename": "$TEST_IMG",
80
+ "size": 0
81
+ }
82
+}
83
+{ "execute": "blockdev-add",
84
+ "arguments": {
85
+ "driver": "file",
86
+ "node-name": "imgfile",
87
+ "filename": "$TEST_IMG"
88
+ }
89
+}
90
+{ "execute": "x-blockdev-create",
91
+ "arguments": {
92
+ "driver": "$IMGFMT",
93
+ "file": "imgfile",
94
+ "size": $size
95
+ }
96
+}
97
+{ "execute": "quit" }
98
+EOF
99
+
100
+_img_info --format-specific | _filter_img_info --format-specific
101
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
102
+
103
+echo
104
+echo "=== Successful image creation (explicit defaults) ==="
105
+echo
106
+
107
+# Choose a different size to show that we got a new image
108
+size=$((64 * 1024 * 1024))
109
+
110
+run_qemu <<EOF
111
+{ "execute": "qmp_capabilities" }
112
+{ "execute": "x-blockdev-create",
113
+ "arguments": {
114
+ "driver": "file",
115
+ "filename": "$TEST_IMG",
116
+ "size": 0
117
+ }
118
+}
119
+{ "execute": "x-blockdev-create",
120
+ "arguments": {
121
+ "driver": "$IMGFMT",
122
+ "file": {
123
+ "driver": "file",
124
+ "filename": "$TEST_IMG"
125
+ },
126
+ "size": $size,
127
+ "preallocation": "off"
128
+ }
129
+}
130
+{ "execute": "quit" }
131
+EOF
132
+
133
+_img_info --format-specific | _filter_img_info --format-specific
134
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
135
+
136
+echo
137
+echo "=== Successful image creation (with non-default options) ==="
138
+echo
139
+
140
+# Choose a different size to show that we got a new image
141
+size=$((32 * 1024 * 1024))
142
+
143
+run_qemu <<EOF
144
+{ "execute": "qmp_capabilities" }
145
+{ "execute": "x-blockdev-create",
146
+ "arguments": {
147
+ "driver": "file",
148
+ "filename": "$TEST_IMG",
149
+ "size": 0
150
+ }
151
+}
152
+{ "execute": "x-blockdev-create",
153
+ "arguments": {
154
+ "driver": "$IMGFMT",
155
+ "file": {
156
+ "driver": "file",
157
+ "filename": "$TEST_IMG"
158
+ },
159
+ "size": $size,
160
+ "preallocation": "metadata"
161
+ }
162
+}
163
+{ "execute": "quit" }
164
+EOF
165
+
166
+_img_info --format-specific | _filter_img_info --format-specific
167
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
168
+
169
+echo
170
+echo "=== Invalid BlockdevRef ==="
171
+echo
172
+
173
+run_qemu <<EOF
174
+{ "execute": "qmp_capabilities" }
175
+{ "execute": "x-blockdev-create",
176
+ "arguments": {
177
+ "driver": "$IMGFMT",
178
+ "file": "this doesn't exist",
179
+ "size": $size
180
+ }
181
+}
182
+{ "execute": "quit" }
183
+EOF
184
+
185
+echo
186
+echo "=== Zero size ==="
187
+echo
188
+
189
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
190
+{ "execute": "qmp_capabilities" }
191
+{ "execute": "x-blockdev-create",
192
+ "arguments": {
193
+ "driver": "$IMGFMT",
194
+ "file": "node0",
195
+ "size": 0
196
+ }
197
+}
198
+{ "execute": "quit" }
199
+EOF
200
+
201
+_img_info | _filter_img_info
202
+
203
+echo
204
+echo "=== Maximum size ==="
205
+echo
206
+
207
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
208
+{ "execute": "qmp_capabilities" }
209
+{ "execute": "x-blockdev-create",
210
+ "arguments": {
211
+ "driver": "$IMGFMT",
212
+ "file": "node0",
213
+ "size": 562949819203584
214
+ }
215
+}
216
+{ "execute": "quit" }
217
+EOF
218
+
219
+_img_info | _filter_img_info
220
+
221
+echo
222
+echo "=== Invalid sizes ==="
223
+echo
224
+
225
+# TODO Negative image sizes aren't handled correctly, but this is a problem
226
+# with QAPI's implementation of the 'size' type and affects other commands as
227
+# well. Once this is fixed, we may want to add a test case here.
228
+
229
+# 1. 2^64 - 512
230
+# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
231
+# 3. 0x1fffff8000001 (one byte more than maximum image size for VDI)
232
+
233
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
234
+{ "execute": "qmp_capabilities" }
235
+{ "execute": "x-blockdev-create",
236
+ "arguments": {
237
+ "driver": "$IMGFMT",
238
+ "file": "node0",
239
+ "size": 18446744073709551104
240
+ }
241
+}
242
+{ "execute": "x-blockdev-create",
243
+ "arguments": {
244
+ "driver": "$IMGFMT",
245
+ "file": "node0",
246
+ "size": 9223372036854775808
247
+ }
248
+}
249
+{ "execute": "x-blockdev-create",
250
+ "arguments": {
251
+ "driver": "$IMGFMT",
252
+ "file": "node0",
253
+ "size": 562949819203585
254
+ }
255
+}
256
+{ "execute": "quit" }
257
+EOF
258
+
259
+# success, all done
260
+echo "*** done"
261
+rm -f $seq.full
262
+status=0
263
diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out
264
new file mode 100644
265
index XXXXXXX..XXXXXXX
266
--- /dev/null
267
+++ b/tests/qemu-iotests/211.out
268
@@ -XXX,XX +XXX,XX @@
269
+QA output created by 211
270
+
271
+=== Successful image creation (defaults) ===
272
+
273
+Testing:
274
+QMP_VERSION
275
+{"return": {}}
276
+{"return": {}}
277
+{"return": {}}
278
+{"return": {}}
279
+{"return": {}}
280
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
281
+
282
+image: TEST_DIR/t.IMGFMT
283
+file format: IMGFMT
284
+virtual size: 128M (134217728 bytes)
285
+[{ "start": 0, "length": 134217728, "depth": 0, "zero": true, "data": false}]
286
+
287
+=== Successful image creation (explicit defaults) ===
288
+
289
+Testing:
290
+QMP_VERSION
291
+{"return": {}}
292
+{"return": {}}
293
+{"return": {}}
294
+{"return": {}}
295
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
296
+
297
+image: TEST_DIR/t.IMGFMT
298
+file format: IMGFMT
299
+virtual size: 64M (67108864 bytes)
300
+[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}]
301
+
302
+=== Successful image creation (with non-default options) ===
303
+
304
+Testing:
305
+QMP_VERSION
306
+{"return": {}}
307
+{"return": {}}
308
+{"return": {}}
309
+{"return": {}}
310
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
311
+
312
+image: TEST_DIR/t.IMGFMT
313
+file format: IMGFMT
314
+virtual size: 32M (33554432 bytes)
315
+[{ "start": 0, "length": 3072, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
316
+{ "start": 3072, "length": 33551360, "depth": 0, "zero": true, "data": true, "offset": OFFSET}]
317
+
318
+=== Invalid BlockdevRef ===
319
+
320
+Testing:
321
+QMP_VERSION
322
+{"return": {}}
323
+{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
324
+{"return": {}}
325
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
326
+
327
+
328
+=== Zero size ===
329
+
330
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
331
+QMP_VERSION
332
+{"return": {}}
333
+{"return": {}}
334
+{"return": {}}
335
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
336
+
337
+image: TEST_DIR/t.IMGFMT
338
+file format: IMGFMT
339
+virtual size: 0 (0 bytes)
340
+
341
+=== Maximum size ===
342
+
343
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
344
+QMP_VERSION
345
+{"return": {}}
346
+{"return": {}}
347
+{"return": {}}
348
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
349
+
350
+image: TEST_DIR/t.IMGFMT
351
+file format: IMGFMT
352
+virtual size: 512T (562949819203584 bytes)
353
+
354
+=== Invalid sizes ===
355
+
356
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
357
+QMP_VERSION
358
+{"return": {}}
359
+{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000)"}}
360
+{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000)"}}
361
+{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000)"}}
362
+{"return": {}}
363
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
364
+
365
+*** done
366
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
367
index XXXXXXX..XXXXXXX 100644
368
--- a/tests/qemu-iotests/group
369
+++ b/tests/qemu-iotests/group
370
@@ -XXX,XX +XXX,XX @@
371
208 rw auto quick
372
209 rw auto quick
373
210 rw auto
374
+211 rw auto quick
375
--
376
2.13.6
377
378
diff view generated by jsdifflib
Deleted patch
1
We want to test resizing even for luks. The only change that is needed
2
is to explicitly zero out new space for luks because it's undefined.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
7
---
8
tests/qemu-iotests/025 | 9 ++++++++-
9
1 file changed, 8 insertions(+), 1 deletion(-)
10
11
diff --git a/tests/qemu-iotests/025 b/tests/qemu-iotests/025
12
index XXXXXXX..XXXXXXX 100755
13
--- a/tests/qemu-iotests/025
14
+++ b/tests/qemu-iotests/025
15
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
16
. ./common.filter
17
. ./common.pattern
18
19
-_supported_fmt raw qcow2 qed
20
+_supported_fmt raw qcow2 qed luks
21
_supported_proto file sheepdog rbd nfs
22
_supported_os Linux
23
24
@@ -XXX,XX +XXX,XX @@ length
25
EOF
26
_check_test_img
27
28
+# bdrv_truncate() doesn't zero the new space, so we need to do that explicitly.
29
+# We still want to test automatic zeroing for other formats even though
30
+# bdrv_truncate() doesn't guarantee it.
31
+if [ "$IMGFMT" == "luks" ]; then
32
+ $QEMU_IO -c "write -z $small_size $((big_size - small_size))" "$TEST_IMG" > /dev/null
33
+fi
34
+
35
echo
36
echo "=== Verifying image size after reopen"
37
$QEMU_IO -c "length" "$TEST_IMG"
38
--
39
2.13.6
40
41
diff view generated by jsdifflib
Deleted patch
1
Commit e39e959e fixed an invalid assertion in the .bdrv_length
2
implementation, but left a similar assertion in place for
3
.bdrv_truncate. Instead of crashing when the user requests a too large
4
image size, fail gracefully.
5
1
6
A file size of exactly INT64_MAX caused failure before, but is actually
7
legal.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
12
---
13
block/crypto.c | 6 +++++-
14
1 file changed, 5 insertions(+), 1 deletion(-)
15
16
diff --git a/block/crypto.c b/block/crypto.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/crypto.c
19
+++ b/block/crypto.c
20
@@ -XXX,XX +XXX,XX @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
21
BlockCrypto *crypto = bs->opaque;
22
uint64_t payload_offset =
23
qcrypto_block_get_payload_offset(crypto->block);
24
- assert(payload_offset < (INT64_MAX - offset));
25
+
26
+ if (payload_offset > INT64_MAX - offset) {
27
+ error_setg(errp, "The requested file size is too large");
28
+ return -EFBIG;
29
+ }
30
31
offset += payload_offset;
32
33
--
34
2.13.6
35
36
diff view generated by jsdifflib
Deleted patch
1
This tests that the .bdrv_truncate implementation for luks doesn't crash
2
for invalid image sizes.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
---
7
tests/qemu-iotests/210 | 37 +++++++++++++++++++++++++++++++++++++
8
tests/qemu-iotests/210.out | 16 ++++++++++++++++
9
2 files changed, 53 insertions(+)
10
11
diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210
12
index XXXXXXX..XXXXXXX 100755
13
--- a/tests/qemu-iotests/210
14
+++ b/tests/qemu-iotests/210
15
@@ -XXX,XX +XXX,XX @@ run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
16
{ "execute": "quit" }
17
EOF
18
19
+echo
20
+echo "=== Resize image with invalid sizes ==="
21
+echo
22
+
23
+run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
24
+ -blockdev driver=luks,file=node0,key-secret=keysec0,node-name=node1 \
25
+ -object secret,id=keysec0,data="foo" <<EOF
26
+{ "execute": "qmp_capabilities" }
27
+{ "execute": "block_resize",
28
+ "arguments": {
29
+ "node-name": "node1",
30
+ "size": 9223372036854775296
31
+ }
32
+}
33
+{ "execute": "block_resize",
34
+ "arguments": {
35
+ "node-name": "node1",
36
+ "size": 9223372036854775808
37
+ }
38
+}
39
+{ "execute": "block_resize",
40
+ "arguments": {
41
+ "node-name": "node1",
42
+ "size": 18446744073709551104
43
+ }
44
+}
45
+{ "execute": "block_resize",
46
+ "arguments": {
47
+ "node-name": "node1",
48
+ "size": -9223372036854775808
49
+ }
50
+}
51
+{ "execute": "quit" }
52
+EOF
53
+
54
+_img_info | _filter_img_info
55
+
56
# success, all done
57
echo "*** done"
58
rm -f $seq.full
59
diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out
60
index XXXXXXX..XXXXXXX 100644
61
--- a/tests/qemu-iotests/210.out
62
+++ b/tests/qemu-iotests/210.out
63
@@ -XXX,XX +XXX,XX @@ QMP_VERSION
64
{"return": {}}
65
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
66
67
+
68
+=== Resize image with invalid sizes ===
69
+
70
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 -blockdev driver=IMGFMT,file=node0,key-secret=keysec0,node-name=node1 -object secret,id=keysec0,data=foo
71
+QMP_VERSION
72
+{"return": {}}
73
+{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
74
+{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
75
+{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
76
+{"error": {"class": "GenericError", "desc": "Parameter 'size' expects a >0 size"}}
77
+{"return": {}}
78
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
79
+
80
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
81
+file format: IMGFMT
82
+virtual size: 0 (0 bytes)
83
*** done
84
--
85
2.13.6
86
87
diff view generated by jsdifflib
Deleted patch
1
It's unclear what the real maximum cluster size is for the Parallels
2
format, but let's at least make sure that we don't get integer
3
overflows in our .bdrv_co_create implementation.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
block/parallels.c | 5 +++++
9
1 file changed, 5 insertions(+)
10
11
diff --git a/block/parallels.c b/block/parallels.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/parallels.c
14
+++ b/block/parallels.c
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts,
16
cl_size = DEFAULT_CLUSTER_SIZE;
17
}
18
19
+ /* XXX What is the real limit here? This is an insanely large maximum. */
20
+ if (cl_size >= INT64_MAX / MAX_PARALLELS_IMAGE_FACTOR) {
21
+ error_setg(errp, "Cluster size is too large");
22
+ return -EINVAL;
23
+ }
24
if (total_size >= MAX_PARALLELS_IMAGE_FACTOR * cl_size) {
25
error_setg(errp, "Image size is too large for this cluster size");
26
return -E2BIG;
27
--
28
2.13.6
29
30
diff view generated by jsdifflib
1
From: Vitalii Mordan <mordan@ispras.ru>
2
3
This patch addresses potential data races involving access to Job fields
4
in the test-bdrv-drain test.
5
6
Fixes: 7253220de4 ("test-bdrv-drain: Test drain vs. block jobs")
7
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2900
8
Signed-off-by: Vitalii Mordan <mordan@ispras.ru>
9
Message-ID: <20250402102119.3345626-1-mordan@ispras.ru>
10
[kwolf: Fixed up coding style and one missing atomic access]
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
---
13
---
3
tests/qemu-iotests/212 | 326 +++++++++++++++++++++++++++++++++++++++++++++
14
include/qemu/job.h | 3 +++
4
tests/qemu-iotests/212.out | 111 +++++++++++++++
15
job.c | 6 ++++++
5
tests/qemu-iotests/group | 1 +
16
tests/unit/test-bdrv-drain.c | 32 +++++++++++++++++++-------------
6
3 files changed, 438 insertions(+)
17
3 files changed, 28 insertions(+), 13 deletions(-)
7
create mode 100755 tests/qemu-iotests/212
8
create mode 100644 tests/qemu-iotests/212.out
9
18
10
diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212
19
diff --git a/include/qemu/job.h b/include/qemu/job.h
11
new file mode 100755
20
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX
21
--- a/include/qemu/job.h
13
--- /dev/null
22
+++ b/include/qemu/job.h
14
+++ b/tests/qemu-iotests/212
23
@@ -XXX,XX +XXX,XX @@ bool job_is_ready(Job *job);
15
@@ -XXX,XX +XXX,XX @@
24
/* Same as job_is_ready(), but called with job lock held. */
16
+#!/bin/bash
25
bool job_is_ready_locked(Job *job);
17
+#
26
18
+# Test parallels and file image creation
27
+/** Returns whether the job is paused. Called with job_mutex *not* held. */
19
+#
28
+bool job_is_paused(Job *job);
20
+# Copyright (C) 2018 Red Hat, Inc.
21
+#
22
+# This program is free software; you can redistribute it and/or modify
23
+# it under the terms of the GNU General Public License as published by
24
+# the Free Software Foundation; either version 2 of the License, or
25
+# (at your option) any later version.
26
+#
27
+# This program is distributed in the hope that it will be useful,
28
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
29
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30
+# GNU General Public License for more details.
31
+#
32
+# You should have received a copy of the GNU General Public License
33
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
34
+#
35
+
29
+
36
+# creator
30
/**
37
+owner=kwolf@redhat.com
31
* Request @job to pause at the next pause point. Must be paired with
38
+
32
* job_resume(). If the job is supposed to be resumed by user action, call
39
+seq=`basename $0`
33
diff --git a/job.c b/job.c
40
+echo "QA output created by $seq"
34
index XXXXXXX..XXXXXXX 100644
41
+
35
--- a/job.c
42
+here=`pwd`
36
+++ b/job.c
43
+status=1    # failure is the default!
37
@@ -XXX,XX +XXX,XX @@ bool job_is_cancelled_locked(Job *job)
44
+
38
return job->force_cancel;
45
+# get standard environment, filters and checks
39
}
46
+. ./common.rc
40
47
+. ./common.filter
41
+bool job_is_paused(Job *job)
48
+
49
+_supported_fmt parallels
50
+_supported_proto file
51
+_supported_os Linux
52
+
53
+function do_run_qemu()
54
+{
42
+{
55
+ echo Testing: "$@"
43
+ JOB_LOCK_GUARD();
56
+ $QEMU -nographic -qmp stdio -serial none "$@"
44
+ return job->paused;
57
+ echo
58
+}
45
+}
59
+
46
+
60
+function run_qemu()
47
bool job_is_cancelled(Job *job)
61
+{
48
{
62
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
49
JOB_LOCK_GUARD();
63
+ | _filter_qemu | _filter_imgfmt \
50
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
64
+ | _filter_actual_image_size
51
index XXXXXXX..XXXXXXX 100644
65
+}
52
--- a/tests/unit/test-bdrv-drain.c
53
+++ b/tests/unit/test-bdrv-drain.c
54
@@ -XXX,XX +XXX,XX @@ typedef struct TestBlockJob {
55
BlockDriverState *bs;
56
int run_ret;
57
int prepare_ret;
66
+
58
+
67
+echo
59
+ /* Accessed with atomics */
68
+echo "=== Successful image creation (defaults) ==="
60
bool running;
69
+echo
61
bool should_complete;
62
} TestBlockJob;
63
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn test_job_run(Job *job, Error **errp)
64
65
/* We are running the actual job code past the pause point in
66
* job_co_entry(). */
67
- s->running = true;
68
+ qatomic_set(&s->running, true);
69
70
job_transition_to_ready(&s->common.job);
71
- while (!s->should_complete) {
72
+ while (!qatomic_read(&s->should_complete)) {
73
/* Avoid job_sleep_ns() because it marks the job as !busy. We want to
74
* emulate some actual activity (probably some I/O) here so that drain
75
* has to wait for this activity to stop. */
76
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn test_job_run(Job *job, Error **errp)
77
static void test_job_complete(Job *job, Error **errp)
78
{
79
TestBlockJob *s = container_of(job, TestBlockJob, common.job);
80
- s->should_complete = true;
81
+ qatomic_set(&s->should_complete, true);
82
}
83
84
BlockJobDriver test_job_driver = {
85
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
86
/* job_co_entry() is run in the I/O thread, wait for the actual job
87
* code to start (we don't want to catch the job in the pause point in
88
* job_co_entry(). */
89
- while (!tjob->running) {
90
+ while (!qatomic_read(&tjob->running)) {
91
aio_poll(qemu_get_aio_context(), false);
92
}
93
}
94
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
95
WITH_JOB_LOCK_GUARD() {
96
g_assert_cmpint(job->job.pause_count, ==, 0);
97
g_assert_false(job->job.paused);
98
- g_assert_true(tjob->running);
99
+ g_assert_true(qatomic_read(&tjob->running));
100
g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */
101
}
102
103
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
104
*
105
* paused is reset in the I/O thread, wait for it
106
*/
107
- while (job->job.paused) {
108
+ while (job_is_paused(&job->job)) {
109
aio_poll(qemu_get_aio_context(), false);
110
}
111
}
112
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
113
*
114
* paused is reset in the I/O thread, wait for it
115
*/
116
- while (job->job.paused) {
117
+ while (job_is_paused(&job->job)) {
118
aio_poll(qemu_get_aio_context(), false);
119
}
120
}
121
@@ -XXX,XX +XXX,XX @@ static void test_set_aio_context(void)
122
123
typedef struct TestDropBackingBlockJob {
124
BlockJob common;
125
- bool should_complete;
126
bool *did_complete;
127
BlockDriverState *detach_also;
128
BlockDriverState *bs;
70
+
129
+
71
+size=$((128 * 1024 * 1024))
130
+ /* Accessed with atomics */
131
+ bool should_complete;
132
} TestDropBackingBlockJob;
133
134
static int coroutine_fn test_drop_backing_job_run(Job *job, Error **errp)
135
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn test_drop_backing_job_run(Job *job, Error **errp)
136
TestDropBackingBlockJob *s =
137
container_of(job, TestDropBackingBlockJob, common.job);
138
139
- while (!s->should_complete) {
140
+ while (!qatomic_read(&s->should_complete)) {
141
job_sleep_ns(job, 0);
142
}
143
144
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_commit_by_drained_end(void)
145
146
job_start(&job->common.job);
147
148
- job->should_complete = true;
149
+ qatomic_set(&job->should_complete, true);
150
bdrv_drained_begin(bs_child);
151
g_assert(!job_has_completed);
152
bdrv_drained_end(bs_child);
153
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_commit_by_drained_end(void)
154
155
typedef struct TestSimpleBlockJob {
156
BlockJob common;
157
- bool should_complete;
158
bool *did_complete;
72
+
159
+
73
+run_qemu <<EOF
160
+ /* Accessed with atomics */
74
+{ "execute": "qmp_capabilities" }
161
+ bool should_complete;
75
+{ "execute": "x-blockdev-create",
162
} TestSimpleBlockJob;
76
+ "arguments": {
163
77
+ "driver": "file",
164
static int coroutine_fn test_simple_job_run(Job *job, Error **errp)
78
+ "filename": "$TEST_IMG",
165
{
79
+ "size": 0
166
TestSimpleBlockJob *s = container_of(job, TestSimpleBlockJob, common.job);
80
+ }
167
81
+}
168
- while (!s->should_complete) {
82
+{ "execute": "blockdev-add",
169
+ while (!qatomic_read(&s->should_complete)) {
83
+ "arguments": {
170
job_sleep_ns(job, 0);
84
+ "driver": "file",
171
}
85
+ "node-name": "imgfile",
172
86
+ "filename": "$TEST_IMG"
173
@@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void)
87
+ }
174
job->did_complete = &job_has_completed;
88
+}
175
89
+{ "execute": "x-blockdev-create",
176
job_start(&job->common.job);
90
+ "arguments": {
177
- job->should_complete = true;
91
+ "driver": "$IMGFMT",
178
+ qatomic_set(&job->should_complete, true);
92
+ "file": "imgfile",
179
93
+ "size": $size
180
g_assert(!job_has_completed);
94
+ }
181
ret = bdrv_drop_intermediate(chain[1], chain[0], NULL, false);
95
+}
96
+{ "execute": "quit" }
97
+EOF
98
+
99
+_img_info --format-specific | _filter_img_info --format-specific
100
+
101
+echo
102
+echo "=== Successful image creation (explicit defaults) ==="
103
+echo
104
+
105
+# Choose a different size to show that we got a new image
106
+size=$((64 * 1024 * 1024))
107
+
108
+run_qemu <<EOF
109
+{ "execute": "qmp_capabilities" }
110
+{ "execute": "x-blockdev-create",
111
+ "arguments": {
112
+ "driver": "file",
113
+ "filename": "$TEST_IMG",
114
+ "size": 0
115
+ }
116
+}
117
+{ "execute": "x-blockdev-create",
118
+ "arguments": {
119
+ "driver": "$IMGFMT",
120
+ "file": {
121
+ "driver": "file",
122
+ "filename": "$TEST_IMG"
123
+ },
124
+ "size": $size,
125
+ "cluster-size": 1048576
126
+ }
127
+}
128
+{ "execute": "quit" }
129
+EOF
130
+
131
+_img_info --format-specific | _filter_img_info --format-specific
132
+
133
+echo
134
+echo "=== Successful image creation (with non-default options) ==="
135
+echo
136
+
137
+# Choose a different size to show that we got a new image
138
+size=$((32 * 1024 * 1024))
139
+
140
+run_qemu <<EOF
141
+{ "execute": "qmp_capabilities" }
142
+{ "execute": "x-blockdev-create",
143
+ "arguments": {
144
+ "driver": "file",
145
+ "filename": "$TEST_IMG",
146
+ "size": 0
147
+ }
148
+}
149
+{ "execute": "x-blockdev-create",
150
+ "arguments": {
151
+ "driver": "$IMGFMT",
152
+ "file": {
153
+ "driver": "file",
154
+ "filename": "$TEST_IMG"
155
+ },
156
+ "size": $size,
157
+ "cluster-size": 65536
158
+ }
159
+}
160
+{ "execute": "quit" }
161
+EOF
162
+
163
+_img_info --format-specific | _filter_img_info --format-specific
164
+
165
+echo
166
+echo "=== Invalid BlockdevRef ==="
167
+echo
168
+
169
+run_qemu <<EOF
170
+{ "execute": "qmp_capabilities" }
171
+{ "execute": "x-blockdev-create",
172
+ "arguments": {
173
+ "driver": "$IMGFMT",
174
+ "file": "this doesn't exist",
175
+ "size": $size
176
+ }
177
+}
178
+{ "execute": "quit" }
179
+EOF
180
+
181
+echo
182
+echo "=== Zero size ==="
183
+echo
184
+
185
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
186
+{ "execute": "qmp_capabilities" }
187
+{ "execute": "x-blockdev-create",
188
+ "arguments": {
189
+ "driver": "$IMGFMT",
190
+ "file": "node0",
191
+ "size": 0
192
+ }
193
+}
194
+{ "execute": "quit" }
195
+EOF
196
+
197
+_img_info | _filter_img_info
198
+
199
+echo
200
+echo "=== Maximum size ==="
201
+echo
202
+
203
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
204
+{ "execute": "qmp_capabilities" }
205
+{ "execute": "x-blockdev-create",
206
+ "arguments": {
207
+ "driver": "$IMGFMT",
208
+ "file": "node0",
209
+ "size": 4503599627369984
210
+ }
211
+}
212
+{ "execute": "quit" }
213
+EOF
214
+
215
+_img_info | _filter_img_info
216
+
217
+echo
218
+echo "=== Invalid sizes ==="
219
+echo
220
+
221
+# TODO Negative image sizes aren't handled correctly, but this is a problem
222
+# with QAPI's implementation of the 'size' type and affects other commands as
223
+# well. Once this is fixed, we may want to add a test case here.
224
+
225
+# 1. Misaligned image size
226
+# 2. 2^64 - 512
227
+# 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
228
+# 4. 2^63 - 512 (generally valid, but with the image header the file will
229
+# exceed 63 bits)
230
+# 5. 2^52 (512 bytes more than maximum image size)
231
+
232
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
233
+{ "execute": "qmp_capabilities" }
234
+{ "execute": "x-blockdev-create",
235
+ "arguments": {
236
+ "driver": "$IMGFMT",
237
+ "file": "node0",
238
+ "size": 1234
239
+ }
240
+}
241
+{ "execute": "x-blockdev-create",
242
+ "arguments": {
243
+ "driver": "$IMGFMT",
244
+ "file": "node0",
245
+ "size": 18446744073709551104
246
+ }
247
+}
248
+{ "execute": "x-blockdev-create",
249
+ "arguments": {
250
+ "driver": "$IMGFMT",
251
+ "file": "node0",
252
+ "size": 9223372036854775808
253
+ }
254
+}
255
+{ "execute": "x-blockdev-create",
256
+ "arguments": {
257
+ "driver": "$IMGFMT",
258
+ "file": "node0",
259
+ "size": 9223372036854775296
260
+ }
261
+}
262
+{ "execute": "x-blockdev-create",
263
+ "arguments": {
264
+ "driver": "$IMGFMT",
265
+ "file": "node0",
266
+ "size": 4503599627370497
267
+ }
268
+}
269
+{ "execute": "quit" }
270
+EOF
271
+
272
+echo
273
+echo "=== Invalid cluster size ==="
274
+echo
275
+
276
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
277
+{ "execute": "qmp_capabilities" }
278
+{ "execute": "x-blockdev-create",
279
+ "arguments": {
280
+ "driver": "$IMGFMT",
281
+ "file": "node0",
282
+ "size": 67108864,
283
+ "cluster-size": 1234
284
+ }
285
+}
286
+{ "execute": "x-blockdev-create",
287
+ "arguments": {
288
+ "driver": "$IMGFMT",
289
+ "file": "node0",
290
+ "size": 67108864,
291
+ "cluster-size": 128
292
+ }
293
+}
294
+{ "execute": "x-blockdev-create",
295
+ "arguments": {
296
+ "driver": "$IMGFMT",
297
+ "file": "node0",
298
+ "size": 67108864,
299
+ "cluster-size": 4294967296
300
+ }
301
+}
302
+{ "execute": "x-blockdev-create",
303
+ "arguments": {
304
+ "driver": "$IMGFMT",
305
+ "file": "node0",
306
+ "size": 67108864,
307
+ "cluster-size": 9223372036854775808
308
+ }
309
+}
310
+{ "execute": "x-blockdev-create",
311
+ "arguments": {
312
+ "driver": "$IMGFMT",
313
+ "file": "node0",
314
+ "size": 67108864,
315
+ "cluster-size": 18446744073709551104
316
+ }
317
+}
318
+{ "execute": "x-blockdev-create",
319
+ "arguments": {
320
+ "driver": "$IMGFMT",
321
+ "file": "node0",
322
+ "size": 67108864,
323
+ "cluster-size": 0
324
+ }
325
+}
326
+{ "execute": "x-blockdev-create",
327
+ "arguments": {
328
+ "driver": "$IMGFMT",
329
+ "file": "node0",
330
+ "size": 281474976710656,
331
+ "cluster-size": 512
332
+ }
333
+}
334
+{ "execute": "quit" }
335
+EOF
336
+
337
+
338
+# success, all done
339
+echo "*** done"
340
+rm -f $seq.full
341
+status=0
342
diff --git a/tests/qemu-iotests/212.out b/tests/qemu-iotests/212.out
343
new file mode 100644
344
index XXXXXXX..XXXXXXX
345
--- /dev/null
346
+++ b/tests/qemu-iotests/212.out
347
@@ -XXX,XX +XXX,XX @@
348
+QA output created by 212
349
+
350
+=== Successful image creation (defaults) ===
351
+
352
+Testing:
353
+QMP_VERSION
354
+{"return": {}}
355
+{"return": {}}
356
+{"return": {}}
357
+{"return": {}}
358
+{"return": {}}
359
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
360
+
361
+image: TEST_DIR/t.IMGFMT
362
+file format: IMGFMT
363
+virtual size: 128M (134217728 bytes)
364
+
365
+=== Successful image creation (explicit defaults) ===
366
+
367
+Testing:
368
+QMP_VERSION
369
+{"return": {}}
370
+{"return": {}}
371
+{"return": {}}
372
+{"return": {}}
373
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
374
+
375
+image: TEST_DIR/t.IMGFMT
376
+file format: IMGFMT
377
+virtual size: 64M (67108864 bytes)
378
+
379
+=== Successful image creation (with non-default options) ===
380
+
381
+Testing:
382
+QMP_VERSION
383
+{"return": {}}
384
+{"return": {}}
385
+{"return": {}}
386
+{"return": {}}
387
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
388
+
389
+image: TEST_DIR/t.IMGFMT
390
+file format: IMGFMT
391
+virtual size: 32M (33554432 bytes)
392
+
393
+=== Invalid BlockdevRef ===
394
+
395
+Testing:
396
+QMP_VERSION
397
+{"return": {}}
398
+{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
399
+{"return": {}}
400
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
401
+
402
+
403
+=== Zero size ===
404
+
405
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
406
+QMP_VERSION
407
+{"return": {}}
408
+{"return": {}}
409
+{"return": {}}
410
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
411
+
412
+image: TEST_DIR/t.IMGFMT
413
+file format: IMGFMT
414
+virtual size: 0 (0 bytes)
415
+
416
+=== Maximum size ===
417
+
418
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
419
+QMP_VERSION
420
+{"return": {}}
421
+{"return": {}}
422
+{"return": {}}
423
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
424
+
425
+image: TEST_DIR/t.IMGFMT
426
+file format: IMGFMT
427
+virtual size: 4096T (4503599627369984 bytes)
428
+
429
+=== Invalid sizes ===
430
+
431
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
432
+QMP_VERSION
433
+{"return": {}}
434
+{"error": {"class": "GenericError", "desc": "Image size must be a multiple of 512 bytes"}}
435
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
436
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
437
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
438
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
439
+{"return": {}}
440
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
441
+
442
+
443
+=== Invalid cluster size ===
444
+
445
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
446
+QMP_VERSION
447
+{"return": {}}
448
+{"error": {"class": "GenericError", "desc": "Cluster size must be a multiple of 512 bytes"}}
449
+{"error": {"class": "GenericError", "desc": "Cluster size must be a multiple of 512 bytes"}}
450
+{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
451
+{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
452
+{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
453
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
454
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
455
+{"return": {}}
456
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
457
+
458
+*** done
459
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
460
index XXXXXXX..XXXXXXX 100644
461
--- a/tests/qemu-iotests/group
462
+++ b/tests/qemu-iotests/group
463
@@ -XXX,XX +XXX,XX @@
464
209 rw auto quick
465
210 rw auto
466
211 rw auto quick
467
+212 rw auto quick
468
--
182
--
469
2.13.6
183
2.49.0
470
471
diff view generated by jsdifflib
Deleted patch
1
Images with a non-power-of-two block size are invalid and cannot be
2
opened. Reject such block sizes when creating an image.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
---
8
block/vhdx.c | 4 ++++
9
1 file changed, 4 insertions(+)
10
11
diff --git a/block/vhdx.c b/block/vhdx.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/vhdx.c
14
+++ b/block/vhdx.c
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
16
error_setg_errno(errp, EINVAL, "Block size must be a multiple of 1 MB");
17
return -EINVAL;
18
}
19
+ if (!is_power_of_2(block_size)) {
20
+ error_setg(errp, "Block size must be a power of two");
21
+ return -EINVAL;
22
+ }
23
if (block_size > VHDX_BLOCK_SIZE_MAX) {
24
error_setg_errno(errp, EINVAL, "Block size must not exceed %d",
25
VHDX_BLOCK_SIZE_MAX);
26
--
27
2.13.6
28
29
diff view generated by jsdifflib
Deleted patch
1
error_setg_errno() is meant for cases where we got an errno from the OS
2
that can add useful extra information to an error message. It's
3
pointless if we pass a constant errno, these cases should use plain
4
error_setg().
5
1
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Jeff Cody <jcody@redhat.com>
9
---
10
block/vhdx.c | 9 ++++-----
11
1 file changed, 4 insertions(+), 5 deletions(-)
12
13
diff --git a/block/vhdx.c b/block/vhdx.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/vhdx.c
16
+++ b/block/vhdx.c
17
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
18
/* Validate options and set default values */
19
image_size = vhdx_opts->size;
20
if (image_size > VHDX_MAX_IMAGE_SIZE) {
21
- error_setg_errno(errp, EINVAL, "Image size too large; max of 64TB");
22
+ error_setg(errp, "Image size too large; max of 64TB");
23
return -EINVAL;
24
}
25
26
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
27
log_size = vhdx_opts->log_size;
28
}
29
if (log_size < MiB || (log_size % MiB) != 0) {
30
- error_setg_errno(errp, EINVAL, "Log size must be a multiple of 1 MB");
31
+ error_setg(errp, "Log size must be a multiple of 1 MB");
32
return -EINVAL;
33
}
34
35
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
36
}
37
38
if (block_size < MiB || (block_size % MiB) != 0) {
39
- error_setg_errno(errp, EINVAL, "Block size must be a multiple of 1 MB");
40
+ error_setg(errp, "Block size must be a multiple of 1 MB");
41
return -EINVAL;
42
}
43
if (!is_power_of_2(block_size)) {
44
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
45
return -EINVAL;
46
}
47
if (block_size > VHDX_BLOCK_SIZE_MAX) {
48
- error_setg_errno(errp, EINVAL, "Block size must not exceed %d",
49
- VHDX_BLOCK_SIZE_MAX);
50
+ error_setg(errp, "Block size must not exceed %d", VHDX_BLOCK_SIZE_MAX);
51
return -EINVAL;
52
}
53
54
--
55
2.13.6
56
57
diff view generated by jsdifflib
Deleted patch
1
It's unclear what the real maximum is, but we use an uint32_t to store
2
the log size in vhdx_co_create(), so we should check that the given
3
value fits in 32 bits.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Jeff Cody <jcody@redhat.com>
8
---
9
block/vhdx.c | 4 ++++
10
1 file changed, 4 insertions(+)
11
12
diff --git a/block/vhdx.c b/block/vhdx.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block/vhdx.c
15
+++ b/block/vhdx.c
16
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
17
if (!vhdx_opts->has_log_size) {
18
log_size = DEFAULT_LOG_SIZE;
19
} else {
20
+ if (vhdx_opts->log_size > UINT32_MAX) {
21
+ error_setg(errp, "Log size must be smaller than 4 GB");
22
+ return -EINVAL;
23
+ }
24
log_size = vhdx_opts->log_size;
25
}
26
if (log_size < MiB || (log_size % MiB) != 0) {
27
--
28
2.13.6
29
30
diff view generated by jsdifflib