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 |