1 | The following changes since commit 60205b71421cbc529ca60b12c79e0eeace007319: | 1 | The following changes since commit dfaecc04c46d298e9ee81bd0ca96d8754f1c27ed: |
---|---|---|---|
2 | 2 | ||
3 | Merge tag 'pull-aspeed-20220801' of https://github.com/legoater/qemu into staging (2022-08-01 13:55:11 -0700) | 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 21b1d974595b3986c68fe80a1f7e9b87886d4bae: | 9 | for you to fetch changes up to f8222bfba3409a3ce09c191941127a8cf2c7e623: |
10 | 10 | ||
11 | main loop: add missing documentation links to GS/IO macros (2022-08-02 12:02:17 +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 | - libvduse: Coverity fixes | 16 | - scsi-disk: Apply error policy for host_status errors again |
17 | - hd-geometry: Fix ignored bios-chs-trans setting | 17 | - qcow2: Fix qemu-img info crash with missing crypto header |
18 | - io_uring: Fix compiler warning (missing #include) | 18 | - qemu-img bench: Fix division by zero for zero-sized images |
19 | - main loop: add missing documentation links to GS/IO macros | 19 | - test-bdrv-drain: Fix data races |
20 | - qemu-iotests: Discard stderr when probing devices | ||
21 | 20 | ||
22 | ---------------------------------------------------------------- | 21 | ---------------------------------------------------------------- |
23 | Cole Robinson (1): | 22 | Denis Rastyogin (1): |
24 | qemu-iotests: Discard stderr when probing devices | 23 | qemu-img: fix division by zero in bench_cb() for zero-sized images |
25 | 24 | ||
26 | Emanuele Giuseppe Esposito (1): | 25 | Kevin Wolf (2): |
27 | main loop: add missing documentation links to GS/IO macros | 26 | qcow2: Don't crash qemu-img info with missing crypto header |
27 | scsi-disk: Apply error policy for host_status errors again | ||
28 | 28 | ||
29 | Jinhao Fan (1): | 29 | Vitalii Mordan (1): |
30 | block/io_uring: add missing include file | 30 | test-bdrv-drain: Fix data races |
31 | 31 | ||
32 | Lev Kujawski (1): | 32 | include/qemu/job.h | 3 ++ |
33 | hw/block/hd-geometry: Do not override specified bios-chs-trans | 33 | block/qcow2.c | 4 +- |
34 | 34 | hw/scsi/scsi-disk.c | 39 +++++++++----- | |
35 | Xie Yongji (3): | 35 | job.c | 6 +++ |
36 | libvduse: Fix the incorrect function name | 36 | qemu-img.c | 6 ++- |
37 | libvduse: Replace strcpy() with strncpy() | 37 | tests/unit/test-bdrv-drain.c | 32 +++++++----- |
38 | libvduse: Pass positive value to strerror() | 38 | tests/qemu-iotests/tests/qcow2-encryption | 75 +++++++++++++++++++++++++++ |
39 | 39 | tests/qemu-iotests/tests/qcow2-encryption.out | 32 ++++++++++++ | |
40 | include/qemu/main-loop.h | 18 +++++++++++++++--- | 40 | 8 files changed, 167 insertions(+), 30 deletions(-) |
41 | block/io_uring.c | 1 + | 41 | create mode 100755 tests/qemu-iotests/tests/qcow2-encryption |
42 | hw/block/hd-geometry.c | 7 ++++++- | 42 | create mode 100644 tests/qemu-iotests/tests/qcow2-encryption.out |
43 | subprojects/libvduse/libvduse.c | 13 +++++++------ | ||
44 | tests/qemu-iotests/common.rc | 4 ++-- | ||
45 | 5 files changed, 31 insertions(+), 12 deletions(-) | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | From: Denis Rastyogin <gerben@altlinux.org> |
---|---|---|---|
2 | 2 | ||
3 | If we go directly to GLOBAL_STATE_CODE, IO_CODE or IO_OR_GS_CODE | 3 | This error was discovered by fuzzing qemu-img. |
4 | definition, we just find that they "mark and check that the function | ||
5 | is part of the {category} API". | ||
6 | However, ther is no definition on what {category} API is, they are | ||
7 | in include/block/block-*.h | ||
8 | Therefore, add a comment that refers to such documentation. | ||
9 | 4 | ||
10 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 5 | This commit fixes a division by zero error in the bench_cb() function |
11 | Message-Id: <20220609122206.1016936-1-eesposit@redhat.com> | 6 | that occurs when using the bench command with a zero-sized image. |
12 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 7 | |
8 | The issue arises because b->image_size can be zero, leading to a | ||
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. | ||
12 | |||
13 | Signed-off-by: Denis Rastyogin <gerben@altlinux.org> | ||
14 | Message-ID: <20250318101933.255617-1-gerben@altlinux.org> | ||
15 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 17 | --- |
15 | include/qemu/main-loop.h | 18 +++++++++++++++--- | 18 | qemu-img.c | 6 +++++- |
16 | 1 file changed, 15 insertions(+), 3 deletions(-) | 19 | 1 file changed, 5 insertions(+), 1 deletion(-) |
17 | 20 | ||
18 | diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h | 21 | diff --git a/qemu-img.c b/qemu-img.c |
19 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/include/qemu/main-loop.h | 23 | --- a/qemu-img.c |
21 | +++ b/include/qemu/main-loop.h | 24 | +++ b/qemu-img.c |
22 | @@ -XXX,XX +XXX,XX @@ bool qemu_mutex_iothread_locked(void); | 25 | @@ -XXX,XX +XXX,XX @@ static void bench_cb(void *opaque, int ret) |
23 | */ | 26 | */ |
24 | bool qemu_in_main_thread(void); | 27 | b->in_flight++; |
25 | 28 | b->offset += b->step; | |
26 | -/* Mark and check that the function is part of the global state API. */ | 29 | - b->offset %= b->image_size; |
27 | +/* | 30 | + if (b->image_size == 0) { |
28 | + * Mark and check that the function is part of the Global State API. | 31 | + b->offset = 0; |
29 | + * Please refer to include/block/block-global-state.h for more | 32 | + } else { |
30 | + * information about GS API. | 33 | + b->offset %= b->image_size; |
31 | + */ | 34 | + } |
32 | #ifdef CONFIG_COCOA | 35 | if (b->write) { |
33 | /* | 36 | acb = blk_aio_pwritev(b->blk, offset, b->qiov, 0, bench_cb, b); |
34 | * When using the Cocoa UI, addRemovableDevicesMenuItems() is called from | 37 | } else { |
35 | @@ -XXX,XX +XXX,XX @@ bool qemu_in_main_thread(void); | ||
36 | } while (0) | ||
37 | #endif /* CONFIG_COCOA */ | ||
38 | |||
39 | -/* Mark and check that the function is part of the I/O API. */ | ||
40 | +/* | ||
41 | + * Mark and check that the function is part of the I/O API. | ||
42 | + * Please refer to include/block/block-io.h for more | ||
43 | + * information about IO API. | ||
44 | + */ | ||
45 | #define IO_CODE() \ | ||
46 | do { \ | ||
47 | /* nop */ \ | ||
48 | } while (0) | ||
49 | |||
50 | -/* Mark and check that the function is part of the "I/O OR GS" API. */ | ||
51 | +/* | ||
52 | + * Mark and check that the function is part of the "I/O OR GS" API. | ||
53 | + * Please refer to include/block/block-io.h for more | ||
54 | + * information about "IO or GS" API. | ||
55 | + */ | ||
56 | #define IO_OR_GS_CODE() \ | ||
57 | do { \ | ||
58 | /* nop */ \ | ||
59 | -- | 38 | -- |
60 | 2.35.3 | 39 | 2.49.0 | diff view generated by jsdifflib |
1 | From: Jinhao Fan <fanjinhao21s@ict.ac.cn> | 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. | ||
2 | 5 | ||
3 | The commit "Use io_uring_register_ring_fd() to skip fd operations" uses | 6 | It doesn't make sense to open an invalid image, so remove the exception |
4 | warn_report but did not include the header file "qemu/error-report.h". | 7 | for BDRV_O_NO_IO. This catches the problem early and any code that makes |
5 | This causes "error: implicit declaration of function ‘warn_report’". | 8 | the same assumption is safe now. |
6 | Include this header file. | ||
7 | 9 | ||
8 | Fixes: e2848bc574 ("Use io_uring_register_ring_fd() to skip fd operations") | 10 | At the same time, in the name of defensive programming, we shouldn't |
9 | Signed-off-by: Jinhao Fan <fanjinhao21s@ict.ac.cn> | 11 | make the assumption in the first place. Let qcow2_refresh_limits() check |
10 | Message-Id: <20220721065645.577404-1-fanjinhao21s@ict.ac.cn> | 12 | s->crypto rather than bs->encrypted. If s->crypto is NULL, it also can't |
11 | Reviewed-by: Stefano Garzarella <sgarzare@redhat.com> | 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> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 23 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 24 | --- |
14 | block/io_uring.c | 1 + | 25 | block/qcow2.c | 4 +- |
15 | 1 file changed, 1 insertion(+) | 26 | tests/qemu-iotests/tests/qcow2-encryption | 75 +++++++++++++++++++ |
27 | tests/qemu-iotests/tests/qcow2-encryption.out | 32 ++++++++ | ||
28 | 3 files changed, 109 insertions(+), 2 deletions(-) | ||
29 | create mode 100755 tests/qemu-iotests/tests/qcow2-encryption | ||
30 | create mode 100644 tests/qemu-iotests/tests/qcow2-encryption.out | ||
16 | 31 | ||
17 | diff --git a/block/io_uring.c b/block/io_uring.c | 32 | diff --git a/block/qcow2.c b/block/qcow2.c |
18 | index XXXXXXX..XXXXXXX 100644 | 33 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block/io_uring.c | 34 | --- a/block/qcow2.c |
20 | +++ b/block/io_uring.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 | ||
55 | new file mode 100755 | ||
56 | index XXXXXXX..XXXXXXX | ||
57 | --- /dev/null | ||
58 | +++ b/tests/qemu-iotests/tests/qcow2-encryption | ||
21 | @@ -XXX,XX +XXX,XX @@ | 59 | @@ -XXX,XX +XXX,XX @@ |
22 | #include "qemu/osdep.h" | 60 | +#!/usr/bin/env bash |
23 | #include <liburing.h> | 61 | +# group: rw quick |
24 | #include "block/aio.h" | 62 | +# |
25 | +#include "qemu/error-report.h" | 63 | +# Test case for encryption support in qcow2 |
26 | #include "qemu/queue.h" | 64 | +# |
27 | #include "block/block.h" | 65 | +# Copyright (C) 2025 Red Hat, Inc. |
28 | #include "block/raw-aio.h" | 66 | +# |
67 | +# This program is free software; you can redistribute it and/or modify | ||
68 | +# it under the terms of the GNU General Public License as published by | ||
69 | +# the Free Software Foundation; either version 2 of the License, or | ||
70 | +# (at your option) any later version. | ||
71 | +# | ||
72 | +# This program is distributed in the hope that it will be useful, | ||
73 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
74 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
75 | +# GNU General Public License for more details. | ||
76 | +# | ||
77 | +# You should have received a copy of the GNU General Public License | ||
78 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
79 | +# | ||
80 | + | ||
81 | +# creator | ||
82 | +owner=kwolf@redhat.com | ||
83 | + | ||
84 | +seq="$(basename $0)" | ||
85 | +echo "QA output created by $seq" | ||
86 | + | ||
87 | +status=1 # failure is the default! | ||
88 | + | ||
89 | +_cleanup() | ||
90 | +{ | ||
91 | + _cleanup_test_img | ||
92 | +} | ||
93 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
94 | + | ||
95 | +# get standard environment, filters and checks | ||
96 | +. ../common.rc | ||
97 | +. ../common.filter | ||
98 | + | ||
99 | +# This tests qcow2-specific low-level functionality | ||
100 | +_supported_fmt qcow2 | ||
101 | +_supported_proto file | ||
102 | +_require_working_luks | ||
103 | + | ||
104 | +IMG_SIZE=64M | ||
105 | + | ||
106 | +echo | ||
107 | +echo "=== Create an encrypted image ===" | ||
108 | +echo | ||
109 | + | ||
110 | +_make_test_img --object secret,id=sec0,data=123456 -o encrypt.format=luks,encrypt.key-secret=sec0 $IMG_SIZE | ||
111 | +$PYTHON ../qcow2.py "$TEST_IMG" dump-header-exts | ||
112 | +_img_info | ||
113 | +$QEMU_IMG check \ | ||
114 | + --object secret,id=sec0,data=123456 \ | ||
115 | + --image-opts file.filename="$TEST_IMG",encrypt.key-secret=sec0 \ | ||
116 | + | _filter_qemu_img_check | ||
117 | + | ||
118 | +echo | ||
119 | +echo "=== Remove the header extension ===" | ||
120 | +echo | ||
121 | + | ||
122 | +$PYTHON ../qcow2.py "$TEST_IMG" del-header-ext 0x0537be77 | ||
123 | +$PYTHON ../qcow2.py "$TEST_IMG" dump-header-exts | ||
124 | +_img_info | ||
125 | +$QEMU_IMG check \ | ||
126 | + --object secret,id=sec0,data=123456 \ | ||
127 | + --image-opts file.filename="$TEST_IMG",encrypt.key-secret=sec0 2>&1 \ | ||
128 | + | _filter_qemu_img_check \ | ||
129 | + | _filter_testdir | ||
130 | + | ||
131 | +# success, all done | ||
132 | +echo "*** done" | ||
133 | +rm -f $seq.full | ||
134 | +status=0 | ||
135 | diff --git a/tests/qemu-iotests/tests/qcow2-encryption.out b/tests/qemu-iotests/tests/qcow2-encryption.out | ||
136 | new file mode 100644 | ||
137 | index XXXXXXX..XXXXXXX | ||
138 | --- /dev/null | ||
139 | +++ b/tests/qemu-iotests/tests/qcow2-encryption.out | ||
140 | @@ -XXX,XX +XXX,XX @@ | ||
141 | +QA output created by qcow2-encryption | ||
142 | + | ||
143 | +=== Create an encrypted image === | ||
144 | + | ||
145 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
146 | +Header extension: | ||
147 | +magic 0x537be77 (Crypto header) | ||
148 | +length 16 | ||
149 | +data <binary> | ||
150 | + | ||
151 | +Header extension: | ||
152 | +magic 0x6803f857 (Feature table) | ||
153 | +length 384 | ||
154 | +data <binary> | ||
155 | + | ||
156 | +image: TEST_DIR/t.IMGFMT | ||
157 | +file format: IMGFMT | ||
158 | +virtual size: 64 MiB (67108864 bytes) | ||
159 | +encrypted: yes | ||
160 | +cluster_size: 65536 | ||
161 | +No errors were found on the image. | ||
162 | + | ||
163 | +=== Remove the header extension === | ||
164 | + | ||
165 | +Header extension: | ||
166 | +magic 0x6803f857 (Feature table) | ||
167 | +length 384 | ||
168 | +data <binary> | ||
169 | + | ||
170 | +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Missing CRYPTO header for crypt method 2 | ||
171 | +qemu-img: Could not open 'file.filename=TEST_DIR/t.qcow2,encrypt.key-secret=sec0': Missing CRYPTO header for crypt method 2 | ||
172 | +*** done | ||
29 | -- | 173 | -- |
30 | 2.35.3 | 174 | 2.49.0 |
31 | 175 | ||
32 | 176 | diff view generated by jsdifflib |
1 | From: Xie Yongji <xieyongji@bytedance.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 | In vduse_name_is_valid(), we actually check whether | 7 | Apart from the commit message not describing the change as intended, |
4 | the name is invalid or not. So let's change the | 8 | errors indicated in host_status are also obviously backend errors and |
5 | function name to vduse_name_is_invalid() to match | 9 | not something the guest must deal with independently of the error |
6 | the behavior. | 10 | policy. |
7 | 11 | ||
8 | Signed-off-by: Xie Yongji <xieyongji@bytedance.com> | 12 | This behaviour means that some recoverable errors (such as a path error |
9 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | 13 | in multipath configurations) were reported to the guest anyway, which |
10 | Message-Id: <20220706095624.328-2-xieyongji@bytedance.com> | 14 | might not expect it and might consider its disk broken. |
15 | |||
16 | Make sure that we apply the error policy again for host_status errors, | ||
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. | ||
20 | |||
21 | The return value passed to the request callback doesn't have more free | ||
22 | values that could be used to indicate host_status errors as well as SAM | ||
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> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 35 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 36 | --- |
13 | subprojects/libvduse/libvduse.c | 6 +++--- | 37 | hw/scsi/scsi-disk.c | 39 +++++++++++++++++++++++++-------------- |
14 | 1 file changed, 3 insertions(+), 3 deletions(-) | 38 | 1 file changed, 25 insertions(+), 14 deletions(-) |
15 | 39 | ||
16 | diff --git a/subprojects/libvduse/libvduse.c b/subprojects/libvduse/libvduse.c | 40 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c |
17 | index XXXXXXX..XXXXXXX 100644 | 41 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/subprojects/libvduse/libvduse.c | 42 | --- a/hw/scsi/scsi-disk.c |
19 | +++ b/subprojects/libvduse/libvduse.c | 43 | +++ b/hw/scsi/scsi-disk.c |
20 | @@ -XXX,XX +XXX,XX @@ static int vduse_dev_init(VduseDev *dev, const char *name, | 44 | @@ -XXX,XX +XXX,XX @@ struct SCSIDiskClass { |
21 | return 0; | 45 | SCSIDeviceClass parent_class; |
46 | /* | ||
47 | * Callbacks receive ret == 0 for success. Errors are represented either as | ||
48 | - * negative errno values, or as positive SAM status codes. | ||
49 | - * | ||
50 | - * Beware: For errors returned in host_status, the function may directly | ||
51 | - * complete the request and never call the callback. | ||
52 | + * negative errno values, or as positive SAM status codes. For host_status | ||
53 | + * errors, the function passes ret == -ENODEV and sets the host_status field | ||
54 | + * of the SCSIRequest. | ||
55 | */ | ||
56 | DMAIOFunc *dma_readv; | ||
57 | DMAIOFunc *dma_writev; | ||
58 | @@ -XXX,XX +XXX,XX @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed) | ||
59 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||
60 | SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); | ||
61 | SCSISense sense = SENSE_CODE(NO_SENSE); | ||
62 | + int16_t host_status; | ||
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); | ||
22 | } | 98 | } |
23 | 99 | ||
24 | -static inline bool vduse_name_is_valid(const char *name) | 100 | -/* May not be called in all error cases, don't rely on cleanup here */ |
25 | +static inline bool vduse_name_is_invalid(const char *name) | 101 | static void scsi_dma_complete(void *opaque, int ret) |
26 | { | 102 | { |
27 | return strlen(name) >= VDUSE_NAME_MAX || strstr(name, ".."); | 103 | SCSIDiskReq *r = (SCSIDiskReq *)opaque; |
104 | @@ -XXX,XX +XXX,XX @@ done: | ||
105 | scsi_req_unref(&r->req); | ||
28 | } | 106 | } |
29 | @@ -XXX,XX +XXX,XX @@ VduseDev *vduse_dev_create_by_name(const char *name, uint16_t num_queues, | 107 | |
30 | VduseDev *dev; | 108 | -/* May not be called in all error cases, don't rely on cleanup here */ |
31 | int ret; | 109 | static void scsi_read_complete(void *opaque, int ret) |
32 | 110 | { | |
33 | - if (!name || vduse_name_is_valid(name) || !ops || | 111 | SCSIDiskReq *r = (SCSIDiskReq *)opaque; |
34 | + if (!name || vduse_name_is_invalid(name) || !ops || | 112 | @@ -XXX,XX +XXX,XX @@ done: |
35 | !ops->enable_queue || !ops->disable_queue) { | 113 | scsi_req_unref(&r->req); |
36 | fprintf(stderr, "Invalid parameter for vduse\n"); | 114 | } |
37 | return NULL; | 115 | |
38 | @@ -XXX,XX +XXX,XX @@ VduseDev *vduse_dev_create(const char *name, uint32_t device_id, | 116 | -/* May not be called in all error cases, don't rely on cleanup here */ |
39 | struct vduse_dev_config *dev_config; | 117 | static void scsi_write_complete(void * opaque, int ret) |
40 | size_t size = offsetof(struct vduse_dev_config, config); | 118 | { |
41 | 119 | SCSIDiskReq *r = (SCSIDiskReq *)opaque; | |
42 | - if (!name || vduse_name_is_valid(name) || | 120 | @@ -XXX,XX +XXX,XX @@ static void scsi_block_sgio_complete(void *opaque, int ret) |
43 | + if (!name || vduse_name_is_invalid(name) || | 121 | sg_io_hdr_t *io_hdr = &req->io_header; |
44 | !has_feature(features, VIRTIO_F_VERSION_1) || !config || | 122 | |
45 | !config_size || !ops || !ops->enable_queue || !ops->disable_queue) { | 123 | if (ret == 0) { |
46 | fprintf(stderr, "Invalid parameter for vduse\n"); | 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; | ||
47 | -- | 138 | -- |
48 | 2.35.3 | 139 | 2.49.0 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Xie Yongji <xieyongji@bytedance.com> | ||
2 | 1 | ||
3 | Coverity reported a string overflow issue since we copied | ||
4 | "name" to "dev_config->name" without checking the length. | ||
5 | This should be a false positive since we already checked | ||
6 | the length of "name" in vduse_name_is_invalid(). But anyway, | ||
7 | let's replace strcpy() with strncpy() (as a general library, | ||
8 | we'd like to minimize dependencies on other libraries, so we | ||
9 | didn't use g_strlcpy() here) to fix the coverity complaint. | ||
10 | |||
11 | Fixes: Coverity CID 1490224 | ||
12 | Signed-off-by: Xie Yongji <xieyongji@bytedance.com> | ||
13 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | ||
14 | Message-Id: <20220706095624.328-3-xieyongji@bytedance.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | --- | ||
17 | subprojects/libvduse/libvduse.c | 3 ++- | ||
18 | 1 file changed, 2 insertions(+), 1 deletion(-) | ||
19 | |||
20 | diff --git a/subprojects/libvduse/libvduse.c b/subprojects/libvduse/libvduse.c | ||
21 | index XXXXXXX..XXXXXXX 100644 | ||
22 | --- a/subprojects/libvduse/libvduse.c | ||
23 | +++ b/subprojects/libvduse/libvduse.c | ||
24 | @@ -XXX,XX +XXX,XX @@ VduseDev *vduse_dev_create(const char *name, uint32_t device_id, | ||
25 | goto err_dev; | ||
26 | } | ||
27 | |||
28 | - strcpy(dev_config->name, name); | ||
29 | + strncpy(dev_config->name, name, VDUSE_NAME_MAX); | ||
30 | + dev_config->name[VDUSE_NAME_MAX - 1] = '\0'; | ||
31 | dev_config->device_id = device_id; | ||
32 | dev_config->vendor_id = vendor_id; | ||
33 | dev_config->features = features; | ||
34 | -- | ||
35 | 2.35.3 | diff view generated by jsdifflib |
1 | From: Xie Yongji <xieyongji@bytedance.com> | 1 | From: Vitalii Mordan <mordan@ispras.ru> |
---|---|---|---|
2 | 2 | ||
3 | The value passed to strerror() should be positive. | 3 | This patch addresses potential data races involving access to Job fields |
4 | So let's fix it. | 4 | in the test-bdrv-drain test. |
5 | 5 | ||
6 | Fixes: Coverity CID 1490226, 1490223 | 6 | Fixes: 7253220de4 ("test-bdrv-drain: Test drain vs. block jobs") |
7 | Signed-off-by: Xie Yongji <xieyongji@bytedance.com> | 7 | Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2900 |
8 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 8 | Signed-off-by: Vitalii Mordan <mordan@ispras.ru> |
9 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | 9 | Message-ID: <20250402102119.3345626-1-mordan@ispras.ru> |
10 | Message-Id: <20220706095624.328-4-xieyongji@bytedance.com> | 10 | [kwolf: Fixed up coding style and one missing atomic access] |
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 13 | --- |
13 | subprojects/libvduse/libvduse.c | 4 ++-- | 14 | include/qemu/job.h | 3 +++ |
14 | 1 file changed, 2 insertions(+), 2 deletions(-) | 15 | job.c | 6 ++++++ |
16 | tests/unit/test-bdrv-drain.c | 32 +++++++++++++++++++------------- | ||
17 | 3 files changed, 28 insertions(+), 13 deletions(-) | ||
15 | 18 | ||
16 | diff --git a/subprojects/libvduse/libvduse.c b/subprojects/libvduse/libvduse.c | 19 | diff --git a/include/qemu/job.h b/include/qemu/job.h |
17 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/subprojects/libvduse/libvduse.c | 21 | --- a/include/qemu/job.h |
19 | +++ b/subprojects/libvduse/libvduse.c | 22 | +++ b/include/qemu/job.h |
20 | @@ -XXX,XX +XXX,XX @@ VduseDev *vduse_dev_create_by_name(const char *name, uint16_t num_queues, | 23 | @@ -XXX,XX +XXX,XX @@ bool job_is_ready(Job *job); |
21 | ret = vduse_dev_init(dev, name, num_queues, ops, priv); | 24 | /* Same as job_is_ready(), but called with job lock held. */ |
22 | if (ret < 0) { | 25 | bool job_is_ready_locked(Job *job); |
23 | fprintf(stderr, "Failed to init vduse device %s: %s\n", | 26 | |
24 | - name, strerror(ret)); | 27 | +/** Returns whether the job is paused. Called with job_mutex *not* held. */ |
25 | + name, strerror(-ret)); | 28 | +bool job_is_paused(Job *job); |
26 | free(dev); | 29 | + |
27 | return NULL; | 30 | /** |
31 | * Request @job to pause at the next pause point. Must be paired with | ||
32 | * job_resume(). If the job is supposed to be resumed by user action, call | ||
33 | diff --git a/job.c b/job.c | ||
34 | index XXXXXXX..XXXXXXX 100644 | ||
35 | --- a/job.c | ||
36 | +++ b/job.c | ||
37 | @@ -XXX,XX +XXX,XX @@ bool job_is_cancelled_locked(Job *job) | ||
38 | return job->force_cancel; | ||
39 | } | ||
40 | |||
41 | +bool job_is_paused(Job *job) | ||
42 | +{ | ||
43 | + JOB_LOCK_GUARD(); | ||
44 | + return job->paused; | ||
45 | +} | ||
46 | + | ||
47 | bool job_is_cancelled(Job *job) | ||
48 | { | ||
49 | JOB_LOCK_GUARD(); | ||
50 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
51 | index XXXXXXX..XXXXXXX 100644 | ||
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; | ||
58 | + | ||
59 | + /* Accessed with atomics */ | ||
60 | bool running; | ||
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 | } | ||
28 | } | 93 | } |
29 | @@ -XXX,XX +XXX,XX @@ VduseDev *vduse_dev_create(const char *name, uint32_t device_id, | 94 | @@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, |
30 | ret = vduse_dev_init(dev, name, num_queues, ops, priv); | 95 | WITH_JOB_LOCK_GUARD() { |
31 | if (ret < 0) { | 96 | g_assert_cmpint(job->job.pause_count, ==, 0); |
32 | fprintf(stderr, "Failed to init vduse device %s: %s\n", | 97 | g_assert_false(job->job.paused); |
33 | - name, strerror(ret)); | 98 | - g_assert_true(tjob->running); |
34 | + name, strerror(-ret)); | 99 | + g_assert_true(qatomic_read(&tjob->running)); |
35 | goto err; | 100 | g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ |
36 | } | 101 | } |
37 | 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; | ||
129 | + | ||
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; | ||
159 | + | ||
160 | + /* Accessed with atomics */ | ||
161 | + bool should_complete; | ||
162 | } TestSimpleBlockJob; | ||
163 | |||
164 | static int coroutine_fn test_simple_job_run(Job *job, Error **errp) | ||
165 | { | ||
166 | TestSimpleBlockJob *s = container_of(job, TestSimpleBlockJob, common.job); | ||
167 | |||
168 | - while (!s->should_complete) { | ||
169 | + while (!qatomic_read(&s->should_complete)) { | ||
170 | job_sleep_ns(job, 0); | ||
171 | } | ||
172 | |||
173 | @@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void) | ||
174 | job->did_complete = &job_has_completed; | ||
175 | |||
176 | job_start(&job->common.job); | ||
177 | - job->should_complete = true; | ||
178 | + qatomic_set(&job->should_complete, true); | ||
179 | |||
180 | g_assert(!job_has_completed); | ||
181 | ret = bdrv_drop_intermediate(chain[1], chain[0], NULL, false); | ||
38 | -- | 182 | -- |
39 | 2.35.3 | 183 | 2.49.0 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Lev Kujawski <lkujaw@member.fsf.org> | ||
2 | 1 | ||
3 | For small disk images (<4 GiB), QEMU and SeaBIOS default to the | ||
4 | LARGE/ECHS disk translation method, but it is not uncommon for other | ||
5 | BIOS software to use LBA in these cases as well. Some operating | ||
6 | system boot loaders (e.g., NT 4) do not handle LARGE translations | ||
7 | outside of fixed configurations. See, e.g., Q154052: | ||
8 | |||
9 | "When starting an x86 based computer, Ntdetect.com retrieves and | ||
10 | stores Interrupt 13 information. . . If the disk controller is using a | ||
11 | 32 sector/64 head translation scheme, this boundary will be 1 GB. If | ||
12 | the controller uses 63 sector/255 head translation [AUTHOR: i.e., | ||
13 | LBA], the limit will be 4 GB." | ||
14 | |||
15 | To accommodate these situations, hd_geometry_guess() now follows the | ||
16 | disk translation specified by the user even when the ATA disk geometry | ||
17 | is guessed. | ||
18 | |||
19 | hd_geometry_guess(): | ||
20 | * Only set the disk translation when translation is AUTO. | ||
21 | * Show the soon-to-be active translation (*ptrans) in the trace rather | ||
22 | than what was guessed. | ||
23 | |||
24 | Resolves: https://gitlab.com/qemu-project/qemu/-/issues/56 | ||
25 | Buglink: https://bugs.launchpad.net/qemu/+bug/1745312 | ||
26 | |||
27 | Signed-off-by: Lev Kujawski <lkujaw@member.fsf.org> | ||
28 | Message-Id: <20220707204045.999544-1-lkujaw@member.fsf.org> | ||
29 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
30 | --- | ||
31 | hw/block/hd-geometry.c | 7 ++++++- | ||
32 | 1 file changed, 6 insertions(+), 1 deletion(-) | ||
33 | |||
34 | diff --git a/hw/block/hd-geometry.c b/hw/block/hd-geometry.c | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/hw/block/hd-geometry.c | ||
37 | +++ b/hw/block/hd-geometry.c | ||
38 | @@ -XXX,XX +XXX,XX @@ void hd_geometry_guess(BlockBackend *blk, | ||
39 | translation = BIOS_ATA_TRANSLATION_NONE; | ||
40 | } | ||
41 | if (ptrans) { | ||
42 | - *ptrans = translation; | ||
43 | + if (*ptrans == BIOS_ATA_TRANSLATION_AUTO) { | ||
44 | + *ptrans = translation; | ||
45 | + } else { | ||
46 | + /* Defer to the translation specified by the user. */ | ||
47 | + translation = *ptrans; | ||
48 | + } | ||
49 | } | ||
50 | trace_hd_geometry_guess(blk, *pcyls, *pheads, *psecs, translation); | ||
51 | } | ||
52 | -- | ||
53 | 2.35.3 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Cole Robinson <crobinso@redhat.com> | ||
2 | 1 | ||
3 | qemu-iotests fails in the following setup: | ||
4 | |||
5 | ./configure --enable-modules --enable-smartcard \ | ||
6 | --target-list=x86_64-softmmu,s390x-softmmu | ||
7 | make | ||
8 | cd build | ||
9 | QEMU_PROG=`pwd`/s390x-softmmu/qemu-system-s390x \ | ||
10 | ../tests/check-block.sh qcow2 | ||
11 | ... | ||
12 | --- /home/crobinso/src/qemu/tests/qemu-iotests/127.out | ||
13 | +++ /home/crobinso/src/qemu/build/tests/qemu-iotests/scratch/127.out.bad | ||
14 | @@ -1,4 +1,18 @@ | ||
15 | QA output created by 127 | ||
16 | +Failed to open module: /home/crobinso/src/qemu/build/hw-usb-smartcard.so: undefined symbol: ccid_card_ccid_attach | ||
17 | ... | ||
18 | --- /home/crobinso/src/qemu/tests/qemu-iotests/267.out | ||
19 | +++ /home/crobinso/src/qemu/build/tests/qemu-iotests/scratch/267.out.bad | ||
20 | @@ -1,4 +1,11 @@ | ||
21 | QA output created by 267 | ||
22 | +Failed to open module: /home/crobinso/src/qemu/build/hw-usb-smartcard.so: undefined symbol: ccid_card_ccid_attach | ||
23 | |||
24 | The stderr spew is its own known issue, but seems like iotests should | ||
25 | be discarding stderr in this case. | ||
26 | |||
27 | Signed-off-by: Cole Robinson <crobinso@redhat.com> | ||
28 | Reviewed-by: Thomas Huth <thuth@redhat.com> | ||
29 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
30 | --- | ||
31 | tests/qemu-iotests/common.rc | 4 ++-- | ||
32 | 1 file changed, 2 insertions(+), 2 deletions(-) | ||
33 | |||
34 | diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/tests/qemu-iotests/common.rc | ||
37 | +++ b/tests/qemu-iotests/common.rc | ||
38 | @@ -XXX,XX +XXX,XX @@ _require_large_file() | ||
39 | # | ||
40 | _require_devices() | ||
41 | { | ||
42 | - available=$($QEMU -M none -device help | \ | ||
43 | + available=$($QEMU -M none -device help 2> /dev/null | \ | ||
44 | grep ^name | sed -e 's/^name "//' -e 's/".*$//') | ||
45 | for device | ||
46 | do | ||
47 | @@ -XXX,XX +XXX,XX @@ _require_devices() | ||
48 | |||
49 | _require_one_device_of() | ||
50 | { | ||
51 | - available=$($QEMU -M none -device help | \ | ||
52 | + available=$($QEMU -M none -device help 2> /dev/null | \ | ||
53 | grep ^name | sed -e 's/^name "//' -e 's/".*$//') | ||
54 | for device | ||
55 | do | ||
56 | -- | ||
57 | 2.35.3 | diff view generated by jsdifflib |