diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2022-01-14 15:56:30 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2022-01-14 15:56:30 +0000 |
commit | 1cd2ad11d37c48f284f557954e1df675b126264c (patch) | |
tree | 09d75bcd7b586c4aa78cef09364e4020a573a8d4 /tests | |
parent | 0b3f07ebf2954d28debd7493fef551152e08875b (diff) | |
parent | e5e748739562268ef4063ee77bf53ad7040b25c7 (diff) | |
download | qemu-1cd2ad11d37c48f284f557954e1df675b126264c.zip qemu-1cd2ad11d37c48f284f557954e1df675b126264c.tar.gz qemu-1cd2ad11d37c48f284f557954e1df675b126264c.tar.bz2 |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches
- qemu-storage-daemon: Add vhost-user-blk help
- block-backend: Fix use-after-free for BDS pointers after aio_poll()
- qemu-img: Fix sparseness of output image with unaligned ranges
- vvfat: Fix crashes in read-write mode
- Fix device deletion events with -device JSON syntax
- Code cleanups
# gpg: Signature made Fri 14 Jan 2022 13:50:16 GMT
# gpg: using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6
# gpg: issuer "kwolf@redhat.com"
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6
* remotes/kevin/tags/for-upstream:
iotests/testrunner.py: refactor test_field_width
block: drop BLK_PERM_GRAPH_MOD
qemu-img: make is_allocated_sectors() more efficient
iotests: Test qemu-img convert of zeroed data cluster
vvfat: Fix vvfat_write() for writes before the root directory
vvfat: Fix size of temporary qcow file
iotests/308: Fix for CAP_DAC_OVERRIDE
iotests/stream-error-on-reset: New test
block-backend: prevent dangling BDS pointers across aio_poll()
qapi/block: Restrict vhost-user-blk to CONFIG_VHOST_USER_BLK_SERVER
qemu-storage-daemon: Add vhost-user-blk help
docs: Correct 'vhost-user-blk' spelling
softmmu: fix device deletion events with -device JSON syntax
include/sysemu/blockdev.h: remove drive_get_max_devs
include/sysemu/blockdev.h: remove drive_mark_claimed_by_board and inline drive_def
block_int: make bdrv_backing_overridden static
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rwxr-xr-x | tests/qemu-iotests/122 | 1 | ||||
-rw-r--r-- | tests/qemu-iotests/122.out | 2 | ||||
-rw-r--r-- | tests/qemu-iotests/273.out | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/308 | 25 | ||||
-rw-r--r-- | tests/qemu-iotests/308.out | 2 | ||||
-rw-r--r-- | tests/qemu-iotests/testrunner.py | 21 | ||||
-rwxr-xr-x | tests/qemu-iotests/tests/stream-error-on-reset | 140 | ||||
-rw-r--r-- | tests/qemu-iotests/tests/stream-error-on-reset.out | 5 | ||||
-rw-r--r-- | tests/qtest/device-plug-test.c | 19 |
9 files changed, 201 insertions, 18 deletions
diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 index efb260d..be0f6b7 100755 --- a/tests/qemu-iotests/122 +++ b/tests/qemu-iotests/122 @@ -251,6 +251,7 @@ $QEMU_IO -c "write -P 0 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_test $QEMU_IO -c "write 0 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir $QEMU_IO -c "write 8k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir $QEMU_IO -c "write 17k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "write -P 0 65k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir for min_sparse in 4k 8k; do echo diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out index 8fbdac2..e18766e 100644 --- a/tests/qemu-iotests/122.out +++ b/tests/qemu-iotests/122.out @@ -192,6 +192,8 @@ wrote 1024/1024 bytes at offset 8192 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 1024/1024 bytes at offset 17408 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1024/1024 bytes at offset 66560 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) convert -S 4k [{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, diff --git a/tests/qemu-iotests/273.out b/tests/qemu-iotests/273.out index 4e840b6..6a74a81 100644 --- a/tests/qemu-iotests/273.out +++ b/tests/qemu-iotests/273.out @@ -204,7 +204,6 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev "name": "file", "parent": 5, "shared-perm": [ - "graph-mod", "write-unchanged", "consistent-read" ], @@ -219,7 +218,6 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev "name": "backing", "parent": 5, "shared-perm": [ - "graph-mod", "resize", "write-unchanged", "write", @@ -233,7 +231,6 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev "name": "file", "parent": 3, "shared-perm": [ - "graph-mod", "write-unchanged", "consistent-read" ], @@ -246,7 +243,6 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev "name": "backing", "parent": 3, "shared-perm": [ - "graph-mod", "resize", "write-unchanged", "write", diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308 index 2e3f8f4..bde4aac 100755 --- a/tests/qemu-iotests/308 +++ b/tests/qemu-iotests/308 @@ -230,8 +230,29 @@ echo '=== Writable export ===' fuse_export_add 'export-mp' "'mountpoint': '$EXT_MP', 'writable': true" # Check that writing to the read-only export fails -$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TEST_IMG" 2>&1 \ - | _filter_qemu_io | _filter_testdir | _filter_imgfmt +output=$($QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TEST_IMG" 2>&1 \ + | _filter_qemu_io | _filter_testdir | _filter_imgfmt) + +# Expected reference output: Opening the file fails because it has no +# write permission +reference="Could not open 'TEST_DIR/t.IMGFMT': Permission denied" + +if echo "$output" | grep -q "$reference"; then + echo "Writing to read-only export failed: OK" +elif echo "$output" | grep -q "write failed: Permission denied"; then + # With CAP_DAC_OVERRIDE (e.g. when running this test as root), the export + # can be opened regardless of its file permissions, but writing will then + # fail. This is not the result for which we want to test, so count this as + # a SKIP. + _casenotrun "Opening RO export as R/W succeeded, perhaps because of" \ + "CAP_DAC_OVERRIDE" + + # Still, write this to the reference output to make the test pass + echo "Writing to read-only export failed: OK" +else + echo "Writing to read-only export failed: ERROR" + echo "$output" +fi # But here it should work $QEMU_IO -f raw -c 'write -P 42 1M 64k' "$EXT_MP" | _filter_qemu_io diff --git a/tests/qemu-iotests/308.out b/tests/qemu-iotests/308.out index fc47bb1..e4467a1 100644 --- a/tests/qemu-iotests/308.out +++ b/tests/qemu-iotests/308.out @@ -95,7 +95,7 @@ virtual size: 0 B (0 bytes) 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse', 'writable': true } } {"return": {}} -qemu-io: can't open device TEST_DIR/t.IMGFMT: Could not open 'TEST_DIR/t.IMGFMT': Permission denied +Writing to read-only export failed: OK wrote 65536/65536 bytes at offset 1048576 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 65536/65536 bytes at offset 1048576 diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py index 0feaa39..15788f9 100644 --- a/tests/qemu-iotests/testrunner.py +++ b/tests/qemu-iotests/testrunner.py @@ -174,19 +174,17 @@ class TestRunner(ContextManager['TestRunner']): def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: self._stack.close() - def test_print_one_line(self, test: str, starttime: str, + def test_print_one_line(self, test: str, + test_field_width: int, + starttime: str, endtime: Optional[str] = None, status: str = '...', lasttime: Optional[float] = None, thistime: Optional[float] = None, description: str = '', - test_field_width: Optional[int] = None, end: str = '\n') -> None: """ Print short test info before/after test run """ test = os.path.basename(test) - if test_field_width is None: - test_field_width = 8 - if self.makecheck and status != '...': if status and status != 'pass': status = f' [{status}]' @@ -328,7 +326,7 @@ class TestRunner(ContextManager['TestRunner']): casenotrun=casenotrun) def run_test(self, test: str, - test_field_width: Optional[int] = None, + test_field_width: int, mp: bool = False) -> TestResult: """ Run one test and print short status @@ -347,20 +345,21 @@ class TestRunner(ContextManager['TestRunner']): if not self.makecheck: self.test_print_one_line(test=test, + test_field_width=test_field_width, status = 'started' if mp else '...', starttime=start, lasttime=last_el, - end = '\n' if mp else '\r', - test_field_width=test_field_width) + end = '\n' if mp else '\r') res = self.do_run_test(test, mp) end = datetime.datetime.now().strftime('%H:%M:%S') - self.test_print_one_line(test=test, status=res.status, + self.test_print_one_line(test=test, + test_field_width=test_field_width, + status=res.status, starttime=start, endtime=end, lasttime=last_el, thistime=res.elapsed, - description=res.description, - test_field_width=test_field_width) + description=res.description) if res.casenotrun: print(res.casenotrun) diff --git a/tests/qemu-iotests/tests/stream-error-on-reset b/tests/qemu-iotests/tests/stream-error-on-reset new file mode 100755 index 0000000..7eaedb2 --- /dev/null +++ b/tests/qemu-iotests/tests/stream-error-on-reset @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +# group: rw quick +# +# Test what happens when a stream job completes in a blk_drain(). +# +# Copyright (C) 2022 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import os +import iotests +from iotests import imgfmt, qemu_img_create, qemu_io_silent, QMPTestCase + + +image_size = 1 * 1024 * 1024 +data_size = 64 * 1024 +base = os.path.join(iotests.test_dir, 'base.img') +top = os.path.join(iotests.test_dir, 'top.img') + + +# We want to test completing a stream job in a blk_drain(). +# +# The blk_drain() we are going to use is a virtio-scsi device resetting, +# which we can trigger by resetting the system. +# +# In order to have the block job complete on drain, we (1) throttle its +# base image so we can start the drain after it has begun, but before it +# completes, and (2) make it encounter an I/O error on the ensuing write. +# (If it completes regularly, the completion happens after the drain for +# some reason.) + +class TestStreamErrorOnReset(QMPTestCase): + def setUp(self) -> None: + """ + Create two images: + - base image {base} with {data_size} bytes allocated + - top image {top} without any data allocated + + And the following VM configuration: + - base image throttled to {data_size} + - top image with a blkdebug configuration so the first write access + to it will result in an error + - top image is attached to a virtio-scsi device + """ + assert qemu_img_create('-f', imgfmt, base, str(image_size)) == 0 + assert qemu_io_silent('-c', f'write 0 {data_size}', base) == 0 + assert qemu_img_create('-f', imgfmt, top, str(image_size)) == 0 + + self.vm = iotests.VM() + self.vm.add_args('-accel', 'tcg') # Make throttling work properly + self.vm.add_object(self.vm.qmp_to_opts({ + 'qom-type': 'throttle-group', + 'id': 'thrgr', + 'x-bps-total': str(data_size) + })) + self.vm.add_blockdev(self.vm.qmp_to_opts({ + 'driver': imgfmt, + 'node-name': 'base', + 'file': { + 'driver': 'throttle', + 'throttle-group': 'thrgr', + 'file': { + 'driver': 'file', + 'filename': base + } + } + })) + self.vm.add_blockdev(self.vm.qmp_to_opts({ + 'driver': imgfmt, + 'node-name': 'top', + 'file': { + 'driver': 'blkdebug', + 'node-name': 'top-blkdebug', + 'inject-error': [{ + 'event': 'pwritev', + 'immediately': 'true', + 'once': 'true' + }], + 'image': { + 'driver': 'file', + 'filename': top + } + }, + 'backing': 'base' + })) + self.vm.add_device(self.vm.qmp_to_opts({ + 'driver': 'virtio-scsi', + 'id': 'vscsi' + })) + self.vm.add_device(self.vm.qmp_to_opts({ + 'driver': 'scsi-hd', + 'bus': 'vscsi.0', + 'drive': 'top' + })) + self.vm.launch() + + def tearDown(self) -> None: + self.vm.shutdown() + os.remove(top) + os.remove(base) + + def test_stream_error_on_reset(self) -> None: + # Launch a stream job, which will take at least a second to + # complete, because the base image is throttled (so we can + # get in between it having started and it having completed) + res = self.vm.qmp('block-stream', job_id='stream', device='top') + self.assert_qmp(res, 'return', {}) + + while True: + ev = self.vm.event_wait('JOB_STATUS_CHANGE') + if ev['data']['status'] == 'running': + # Once the stream job is running, reset the system, which + # forces the virtio-scsi device to be reset, thus draining + # the stream job, and making it complete. Completing + # inside of that drain should not result in a segfault. + res = self.vm.qmp('system_reset') + self.assert_qmp(res, 'return', {}) + elif ev['data']['status'] == 'null': + # The test is done once the job is gone + break + + +if __name__ == '__main__': + # Passes with any format with backing file support, but qed and + # qcow1 do not seem to exercise the used-to-be problematic code + # path, so there is no point in having them in this list + iotests.main(supported_fmts=['qcow2', 'vmdk'], + supported_protocols=['file']) diff --git a/tests/qemu-iotests/tests/stream-error-on-reset.out b/tests/qemu-iotests/tests/stream-error-on-reset.out new file mode 100644 index 0000000..ae1213e --- /dev/null +++ b/tests/qemu-iotests/tests/stream-error-on-reset.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK diff --git a/tests/qtest/device-plug-test.c b/tests/qtest/device-plug-test.c index 559d477..ad79bd4 100644 --- a/tests/qtest/device-plug-test.c +++ b/tests/qtest/device-plug-test.c @@ -77,6 +77,23 @@ static void test_pci_unplug_request(void) qtest_quit(qtest); } +static void test_pci_unplug_json_request(void) +{ + QTestState *qtest = qtest_initf( + "-device '{\"driver\": \"virtio-mouse-pci\", \"id\": \"dev0\"}'"); + + /* + * Request device removal. As the guest is not running, the request won't + * be processed. However during system reset, the removal will be + * handled, removing the device. + */ + device_del(qtest, "dev0"); + system_reset(qtest); + wait_device_deleted_event(qtest, "dev0"); + + qtest_quit(qtest); +} + static void test_ccw_unplug(void) { QTestState *qtest = qtest_initf("-device virtio-balloon-ccw,id=dev0"); @@ -145,6 +162,8 @@ int main(int argc, char **argv) */ qtest_add_func("/device-plug/pci-unplug-request", test_pci_unplug_request); + qtest_add_func("/device-plug/pci-unplug-json-request", + test_pci_unplug_json_request); if (!strcmp(arch, "s390x")) { qtest_add_func("/device-plug/ccw-unplug", |