diff options
Diffstat (limited to 'tests')
-rwxr-xr-x | tests/qemu-iotests/040 | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/041 | 6 | ||||
-rwxr-xr-x | tests/qemu-iotests/061 | 3 | ||||
-rw-r--r-- | tests/qemu-iotests/061.out | 3 | ||||
-rw-r--r-- | tests/qemu-iotests/082.out | 6 | ||||
-rwxr-xr-x | tests/qemu-iotests/114 | 18 | ||||
-rw-r--r-- | tests/qemu-iotests/114.out | 11 | ||||
-rwxr-xr-x | tests/qemu-iotests/155 | 9 | ||||
-rwxr-xr-x | tests/qemu-iotests/165 | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/245 | 78 | ||||
-rw-r--r-- | tests/qemu-iotests/245.out | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/248 | 4 | ||||
-rw-r--r-- | tests/qemu-iotests/248.out | 2 | ||||
-rwxr-xr-x | tests/qemu-iotests/296 | 11 | ||||
-rwxr-xr-x | tests/qemu-iotests/298 | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/301 | 4 | ||||
-rw-r--r-- | tests/qemu-iotests/301.out | 16 | ||||
-rwxr-xr-x | tests/qemu-iotests/308 | 20 | ||||
-rw-r--r-- | tests/qemu-iotests/308.out | 6 | ||||
-rw-r--r-- | tests/qemu-iotests/common.rc | 6 | ||||
-rwxr-xr-x | tests/qemu-iotests/tests/fuse-allow-other | 168 | ||||
-rw-r--r-- | tests/qemu-iotests/tests/fuse-allow-other.out | 88 | ||||
-rwxr-xr-x | tests/qemu-iotests/tests/remove-bitmap-from-backing | 22 |
23 files changed, 414 insertions, 83 deletions
diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index ba7cb34..f3677de 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -920,8 +920,8 @@ class TestCommitWithOverriddenBacking(iotests.QMPTestCase): def setUp(self): qemu_img('create', '-f', iotests.imgfmt, self.img_base_a, '1M') qemu_img('create', '-f', iotests.imgfmt, self.img_base_b, '1M') - qemu_img('create', '-f', iotests.imgfmt, '-b', self.img_base_a, \ - self.img_top) + qemu_img('create', '-f', iotests.imgfmt, '-b', self.img_base_a, + '-F', iotests.imgfmt, self.img_top) self.vm = iotests.VM() self.vm.launch() diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 5cc02b2..db9f5dc 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -1295,8 +1295,10 @@ class TestReplaces(iotests.QMPTestCase): class TestFilters(iotests.QMPTestCase): def setUp(self): qemu_img('create', '-f', iotests.imgfmt, backing_img, '1M') - qemu_img('create', '-f', iotests.imgfmt, '-b', backing_img, test_img) - qemu_img('create', '-f', iotests.imgfmt, '-b', backing_img, target_img) + qemu_img('create', '-f', iotests.imgfmt, '-b', backing_img, + '-F', iotests.imgfmt, test_img) + qemu_img('create', '-f', iotests.imgfmt, '-b', backing_img, + '-F', iotests.imgfmt, target_img) qemu_io('-c', 'write -P 1 0 512k', backing_img) qemu_io('-c', 'write -P 2 512k 512k', test_img) diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061 index e26d94a..9507c22 100755 --- a/tests/qemu-iotests/061 +++ b/tests/qemu-iotests/061 @@ -167,6 +167,9 @@ _make_test_img -o "compat=1.1" 64M TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M $QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io +$QEMU_IMG amend -o "backing_file=$TEST_IMG.base,backing_fmt=qcow2" \ + "$TEST_IMG" && echo "unexpected pass" +$QEMU_IMG rebase -u -b "$TEST_IMG.base" -F qcow2 "$TEST_IMG" $QEMU_IMG amend -o "backing_file=$TEST_IMG.base,backing_fmt=qcow2" "$TEST_IMG" $QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io _check_test_img diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index ee30da2..7ecbd4d 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -370,7 +370,8 @@ wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -qemu-img: warning: Deprecated use of amend to alter the backing file; use qemu-img rebase instead +qemu-img: Cannot amend the backing file +You can use 'qemu-img rebase' instead. read 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index b70c12c..077ed0f 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -808,12 +808,14 @@ Amend options for 'qcow2': size=<size> - Virtual disk size Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 -qemu-img: warning: Deprecated use of amend to alter the backing file; use qemu-img rebase instead +qemu-img: Cannot amend the backing file +You can use 'qemu-img rebase' instead. Testing: rebase -u -b -f qcow2 TEST_DIR/t.qcow2 Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 -qemu-img: warning: Deprecated use of amend to alter the backing file; use qemu-img rebase instead +qemu-img: Cannot amend the backing file +You can use 'qemu-img rebase' instead. Testing: rebase -u -b -f qcow2 TEST_DIR/t.qcow2 diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114 index 43cb0bc..de6fd32 100755 --- a/tests/qemu-iotests/114 +++ b/tests/qemu-iotests/114 @@ -44,16 +44,16 @@ _supported_os Linux # qcow2.py does not work too well with external data files _unsupported_imgopts data_file -# Intentionally specify backing file without backing format; demonstrate -# the difference in warning messages when backing file could be probed. -# Note that only a non-raw probe result will affect the resulting image. +# Older qemu-img could set up backing file without backing format; modern +# qemu can't but we can use qcow2.py to simulate older files. truncate -s $((64 * 1024 * 1024)) "$TEST_IMG.orig" -_make_test_img -b "$TEST_IMG.orig" 64M +_make_test_img -b "$TEST_IMG.orig" -F raw 64M +$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0xE2792ACA TEST_IMG="$TEST_IMG.base" _make_test_img 64M $QEMU_IMG convert -O qcow2 -B "$TEST_IMG.orig" "$TEST_IMG.orig" "$TEST_IMG" -_make_test_img -b "$TEST_IMG.base" 64M -_make_test_img -u -b "$TEST_IMG.base" 64M +_make_test_img -b "$TEST_IMG.base" -F $IMGFMT 64M +_make_test_img -u -b "$TEST_IMG.base" -F $IMGFMT 64M # Set an invalid backing file format $PYTHON qcow2.py "$TEST_IMG" add-header-ext 0xE2792ACA "foo" @@ -64,9 +64,9 @@ _img_info $QEMU_IO -c "open $TEST_IMG" -c "read 0 4k" 2>&1 | _filter_qemu_io | _filter_testdir $QEMU_IO -c "open -o backing.driver=$IMGFMT $TEST_IMG" -c "read 0 4k" | _filter_qemu_io -# Rebase the image, to show that omitting backing format triggers a warning, -# but probing now lets us use the backing file. -$QEMU_IMG rebase -u -b "$TEST_IMG.base" "$TEST_IMG" +# Rebase the image, to show that backing format is required. +($QEMU_IMG rebase -u -b "$TEST_IMG.base" "$TEST_IMG" 2>&1 && echo "unexpected pass") | _filter_testdir +$QEMU_IMG rebase -u -b "$TEST_IMG.base" -F $IMGFMT "$TEST_IMG" $QEMU_IO -c "open $TEST_IMG" -c "read 0 4k" 2>&1 | _filter_qemu_io | _filter_testdir # success, all done diff --git a/tests/qemu-iotests/114.out b/tests/qemu-iotests/114.out index 0a37d20..f51dd9d 100644 --- a/tests/qemu-iotests/114.out +++ b/tests/qemu-iotests/114.out @@ -1,12 +1,9 @@ QA output created by 114 -qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of raw) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.orig +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.orig backing_fmt=raw Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 -qemu-img: warning: Deprecated use of backing file without explicit backing format -qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of IMGFMT) +qemu-img: Use of backing file requires explicit backing format +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT -qemu-img: warning: Deprecated use of unopened backing file without explicit backing format, use of this image requires potentially unsafe format probing -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 64 MiB (67108864 bytes) @@ -17,7 +14,7 @@ qemu-io: can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknow no file open, try 'help open' read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -qemu-img: warning: Deprecated use of backing file without explicit backing format, use of this image requires potentially unsafe format probing +qemu-img: Could not change the backing file to 'TEST_DIR/t.qcow2.base': backing format must be specified read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155 index bafef9d..eadda52 100755 --- a/tests/qemu-iotests/155 +++ b/tests/qemu-iotests/155 @@ -261,9 +261,12 @@ class TestBlockdevMirrorReopen(MirrorBaseClass): result = self.vm.qmp('blockdev-add', node_name="backing", driver="null-co") self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('x-blockdev-reopen', node_name="target", - driver=iotests.imgfmt, file="target-file", - backing="backing") + result = self.vm.qmp('blockdev-reopen', options=[{ + 'node-name': "target", + 'driver': iotests.imgfmt, + 'file': "target-file", + 'backing': "backing" + }]) self.assert_qmp(result, 'return', {}) class TestBlockdevMirrorReopenIothread(TestBlockdevMirrorReopen): diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165 index abc4ffa..ce49994 100755 --- a/tests/qemu-iotests/165 +++ b/tests/qemu-iotests/165 @@ -137,7 +137,7 @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase): assert sha256_1 == self.getSha256() # Reopen to RW - result = self.vm.qmp('x-blockdev-reopen', **{ + result = self.vm.qmp('blockdev-reopen', options=[{ 'node-name': 'node0', 'driver': iotests.imgfmt, 'file': { @@ -145,7 +145,7 @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase): 'filename': disk }, 'read-only': False - }) + }]) self.assert_qmp(result, 'return', {}) # Check that bitmap is reopened to RW and we can write to it. diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245 index 0295129..bf8261e 100755 --- a/tests/qemu-iotests/245 +++ b/tests/qemu-iotests/245 @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # group: rw # -# Test cases for the QMP 'x-blockdev-reopen' command +# Test cases for the QMP 'blockdev-reopen' command # # Copyright (C) 2018-2019 Igalia, S.L. # Author: Alberto Garcia <berto@igalia.com> @@ -85,8 +85,18 @@ class TestBlockdevReopen(iotests.QMPTestCase): "Expected output of %d qemu-io commands, found %d" % (found, self.total_io_cmds)) - # Run x-blockdev-reopen with 'opts' but applying 'newopts' - # on top of it. The original 'opts' dict is unmodified + # Run blockdev-reopen on a list of block devices + def reopenMultiple(self, opts, errmsg = None): + result = self.vm.qmp('blockdev-reopen', conv_keys=False, options=opts) + if errmsg: + self.assert_qmp(result, 'error/class', 'GenericError') + self.assert_qmp(result, 'error/desc', errmsg) + else: + self.assert_qmp(result, 'return', {}) + + # Run blockdev-reopen on a single block device (specified by + # 'opts') but applying 'newopts' on top of it. The original 'opts' + # dict is unmodified def reopen(self, opts, newopts = {}, errmsg = None): opts = copy.deepcopy(opts) @@ -101,12 +111,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): subdict = opts[prefix] subdict[key] = value - result = self.vm.qmp('x-blockdev-reopen', conv_keys = False, **opts) - if errmsg: - self.assert_qmp(result, 'error/class', 'GenericError') - self.assert_qmp(result, 'error/desc', errmsg) - else: - self.assert_qmp(result, 'return', {}) + self.reopenMultiple([ opts ], errmsg) # Run query-named-block-nodes and return the specified entry @@ -142,10 +147,10 @@ class TestBlockdevReopen(iotests.QMPTestCase): # We cannot change any of these self.reopen(opts, {'node-name': 'not-found'}, "Failed to find node with node-name='not-found'") self.reopen(opts, {'node-name': ''}, "Failed to find node with node-name=''") - self.reopen(opts, {'node-name': None}, "Invalid parameter type for 'node-name', expected: string") + self.reopen(opts, {'node-name': None}, "Invalid parameter type for 'options[0].node-name', expected: string") self.reopen(opts, {'driver': 'raw'}, "Cannot change the option 'driver'") self.reopen(opts, {'driver': ''}, "Invalid parameter ''") - self.reopen(opts, {'driver': None}, "Invalid parameter type for 'driver', expected: string") + self.reopen(opts, {'driver': None}, "Invalid parameter type for 'options[0].driver', expected: string") self.reopen(opts, {'file': 'not-found'}, "Cannot find device='' nor node-name='not-found'") self.reopen(opts, {'file': ''}, "Cannot find device='' nor node-name=''") self.reopen(opts, {'file': None}, "Invalid parameter type for 'file', expected: BlockdevRef") @@ -154,9 +159,9 @@ class TestBlockdevReopen(iotests.QMPTestCase): self.reopen(opts, {'file.filename': hd_path[1]}, "Cannot change the option 'filename'") self.reopen(opts, {'file.aio': 'native'}, "Cannot change the option 'aio'") self.reopen(opts, {'file.locking': 'off'}, "Cannot change the option 'locking'") - self.reopen(opts, {'file.filename': None}, "Invalid parameter type for 'file.filename', expected: string") + self.reopen(opts, {'file.filename': None}, "Invalid parameter type for 'options[0].file.filename', expected: string") - # node-name is optional in BlockdevOptions, but x-blockdev-reopen needs it + # node-name is optional in BlockdevOptions, but blockdev-reopen needs it del opts['node-name'] self.reopen(opts, {}, "node-name not specified") @@ -644,6 +649,53 @@ class TestBlockdevReopen(iotests.QMPTestCase): '-c', 'read -P 0x40 0x40008 1', '-c', 'read -P 0x80 0x40010 1', hd_path[0]) + # Swap the disk images of two active block devices + def test_swap_files(self): + # Add hd0 and hd2 (none of them with backing files) + opts0 = hd_opts(0) + result = self.vm.qmp('blockdev-add', conv_keys = False, **opts0) + self.assert_qmp(result, 'return', {}) + + opts2 = hd_opts(2) + result = self.vm.qmp('blockdev-add', conv_keys = False, **opts2) + self.assert_qmp(result, 'return', {}) + + # Write different data to both block devices + self.run_qemu_io("hd0", "write -P 0xa0 0 1k") + self.run_qemu_io("hd2", "write -P 0xa2 0 1k") + + # Check that the data reads correctly + self.run_qemu_io("hd0", "read -P 0xa0 0 1k") + self.run_qemu_io("hd2", "read -P 0xa2 0 1k") + + # It's not possible to make a block device use an image that + # is already being used by the other device. + self.reopen(opts0, {'file': 'hd2-file'}, + "Permission conflict on node 'hd2-file': permissions " + "'write, resize' are both required by node 'hd2' (uses " + "node 'hd2-file' as 'file' child) and unshared by node " + "'hd0' (uses node 'hd2-file' as 'file' child).") + self.reopen(opts2, {'file': 'hd0-file'}, + "Permission conflict on node 'hd0-file': permissions " + "'write, resize' are both required by node 'hd0' (uses " + "node 'hd0-file' as 'file' child) and unshared by node " + "'hd2' (uses node 'hd0-file' as 'file' child).") + + # But we can swap the images if we reopen both devices at the + # same time + opts0['file'] = 'hd2-file' + opts2['file'] = 'hd0-file' + self.reopenMultiple([opts0, opts2]) + self.run_qemu_io("hd0", "read -P 0xa2 0 1k") + self.run_qemu_io("hd2", "read -P 0xa0 0 1k") + + # And we can of course come back to the original state + opts0['file'] = 'hd0-file' + opts2['file'] = 'hd2-file' + self.reopenMultiple([opts0, opts2]) + self.run_qemu_io("hd0", "read -P 0xa0 0 1k") + self.run_qemu_io("hd2", "read -P 0xa2 0 1k") + # Misc reopen tests with different block drivers @iotests.skip_if_unsupported(['quorum', 'throttle']) def test_misc_drivers(self): diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out index daf1e51..4eced19 100644 --- a/tests/qemu-iotests/245.out +++ b/tests/qemu-iotests/245.out @@ -17,8 +17,8 @@ read 1/1 bytes at offset 262152 read 1/1 bytes at offset 262160 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -.............. +............... ---------------------------------------------------------------------- -Ran 24 tests +Ran 25 tests OK diff --git a/tests/qemu-iotests/248 b/tests/qemu-iotests/248 index 4daaed1..2ec2416 100755 --- a/tests/qemu-iotests/248 +++ b/tests/qemu-iotests/248 @@ -62,8 +62,8 @@ vm.event_wait('JOB_STATUS_CHANGE', timeout=3.0, vm.get_qmp_events() del blockdev_opts['file']['size'] -vm.qmp_log('x-blockdev-reopen', filters=[filter_qmp_testfiles], - **blockdev_opts) +vm.qmp_log('blockdev-reopen', filters=[filter_qmp_testfiles], + options = [ blockdev_opts ]) vm.qmp_log('block-job-resume', device='drive0') vm.event_wait('JOB_STATUS_CHANGE', timeout=1.0, diff --git a/tests/qemu-iotests/248.out b/tests/qemu-iotests/248.out index 369b25b..66e94cc 100644 --- a/tests/qemu-iotests/248.out +++ b/tests/qemu-iotests/248.out @@ -2,7 +2,7 @@ {"return": {}} {"execute": "blockdev-mirror", "arguments": {"device": "drive0", "on-target-error": "enospc", "sync": "full", "target": "target"}} {"return": {}} -{"execute": "x-blockdev-reopen", "arguments": {"driver": "qcow2", "file": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-target"}}, "node-name": "target"}} +{"execute": "blockdev-reopen", "arguments": {"options": [{"driver": "qcow2", "file": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-target"}}, "node-name": "target"}]}} {"return": {}} {"execute": "block-job-resume", "arguments": {"device": "drive0"}} {"return": {}} diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296 index 7c65e98..099a3ee 100755 --- a/tests/qemu-iotests/296 +++ b/tests/qemu-iotests/296 @@ -118,10 +118,9 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): def openImageQmp(self, vm, id, file, secret, readOnly = False, reOpen = False): - command = 'x-blockdev-reopen' if reOpen else 'blockdev-add' + command = 'blockdev-reopen' if reOpen else 'blockdev-add' - result = vm.qmp(command, ** - { + opts = { 'driver': iotests.imgfmt, 'node-name': id, 'read-only': readOnly, @@ -131,7 +130,11 @@ class EncryptionSetupTestCase(iotests.QMPTestCase): 'filename': test_img, } } - ) + + if reOpen: + result = vm.qmp(command, options=[opts]) + else: + result = vm.qmp(command, **opts) self.assert_qmp(result, 'return', {}) diff --git a/tests/qemu-iotests/298 b/tests/qemu-iotests/298 index d535946..fae7221 100755 --- a/tests/qemu-iotests/298 +++ b/tests/qemu-iotests/298 @@ -98,7 +98,7 @@ class TestPreallocateFilter(TestPreallocateBase): self.check_big() def test_reopen_opts(self): - result = self.vm.qmp('x-blockdev-reopen', **{ + result = self.vm.qmp('blockdev-reopen', options=[{ 'node-name': 'disk', 'driver': iotests.imgfmt, 'file': { @@ -112,7 +112,7 @@ class TestPreallocateFilter(TestPreallocateBase): 'filename': disk } } - }) + }]) self.assert_qmp(result, 'return', {}) self.vm.hmp_qemu_io('drive0', 'write 0 1M') diff --git a/tests/qemu-iotests/301 b/tests/qemu-iotests/301 index 9f943ca..220de10 100755 --- a/tests/qemu-iotests/301 +++ b/tests/qemu-iotests/301 @@ -3,7 +3,7 @@ # # Test qcow backing file warnings # -# Copyright (C) 2020 Red Hat, Inc. +# Copyright (C) 2020-2021 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 @@ -46,7 +46,6 @@ echo "== qcow backed by qcow ==" TEST_IMG="$TEST_IMG.base" _make_test_img $size _make_test_img -b "$TEST_IMG.base" $size -_img_info _make_test_img -b "$TEST_IMG.base" -F $IMGFMT $size _img_info @@ -71,7 +70,6 @@ echo "== qcow backed by raw ==" rm "$TEST_IMG.base" truncate --size=$size "$TEST_IMG.base" _make_test_img -b "$TEST_IMG.base" $size -_img_info _make_test_img -b "$TEST_IMG.base" -F raw $size _img_info diff --git a/tests/qemu-iotests/301.out b/tests/qemu-iotests/301.out index 9004dad..e280658 100644 --- a/tests/qemu-iotests/301.out +++ b/tests/qemu-iotests/301.out @@ -2,13 +2,7 @@ QA output created by 301 == qcow backed by qcow == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=33554432 -qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of IMGFMT) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT -image: TEST_DIR/t.IMGFMT -file format: IMGFMT -virtual size: 32 MiB (33554432 bytes) -cluster_size: 512 -backing file: TEST_DIR/t.IMGFMT.base +qemu-img: TEST_DIR/t.IMGFMT: Backing file specified without backing format Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT image: TEST_DIR/t.IMGFMT file format: IMGFMT @@ -36,13 +30,7 @@ cluster_size: 512 backing file: TEST_DIR/t.IMGFMT.base == qcow backed by raw == -qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of raw) -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base -image: TEST_DIR/t.IMGFMT -file format: IMGFMT -virtual size: 32 MiB (33554432 bytes) -cluster_size: 512 -backing file: TEST_DIR/t.IMGFMT.base +qemu-img: TEST_DIR/t.IMGFMT: Backing file specified without backing format Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw image: TEST_DIR/t.IMGFMT file format: IMGFMT diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308 index f122065..6b386bd 100755 --- a/tests/qemu-iotests/308 +++ b/tests/qemu-iotests/308 @@ -58,6 +58,9 @@ _supported_os Linux # We need /dev/urandom # $4: Node to export (defaults to 'node-format') fuse_export_add() { + # The grep -v is a filter for errors when /etc/fuse.conf does not contain + # user_allow_other. (The error is benign, but it is printed by fusermount + # on the first mount attempt, so our export code cannot hide it.) _send_qemu_cmd $QEMU_HANDLE \ "{'execute': 'block-export-add', 'arguments': { @@ -67,7 +70,8 @@ fuse_export_add() $2 } }" \ "${3:-return}" \ - | _filter_imgfmt + | _filter_imgfmt \ + | grep -v 'option allow_other only allowed if' } # $1: Export ID @@ -166,6 +170,17 @@ fuse_export_add 'export-mp' "'mountpoint': '$EXT_MP'" # Check that the export presents the same data as the original image $QEMU_IMG compare -f raw -F $IMGFMT -U "$EXT_MP" "$TEST_IMG" +# Some quick chmod tests +stat -c 'Permissions pre-chmod: %a' "$EXT_MP" + +# Verify that we cannot set +w +chmod u+w "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt +stat -c 'Permissions post-+w: %a' "$EXT_MP" + +# But that we can set, say, +x (if we are so inclined) +chmod u+x "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt +stat -c 'Permissions post-+x: %a' "$EXT_MP" + echo echo '=== Mount over existing file ===' @@ -215,7 +230,8 @@ 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" | _filter_qemu_io +$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TEST_IMG" 2>&1 \ + | _filter_qemu_io | _filter_testdir | _filter_imgfmt # 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 466e7e0..fc47bb1 100644 --- a/tests/qemu-iotests/308.out +++ b/tests/qemu-iotests/308.out @@ -50,6 +50,10 @@ wrote 67108864/67108864 bytes at offset 0 } } {"return": {}} Images are identical. +Permissions pre-chmod: 400 +chmod: changing permissions of 'TEST_DIR/t.IMGFMT.fuse': Read-only file system +Permissions post-+w: 400 +Permissions post-+x: 500 === Mount over existing file === {'execute': 'block-export-add', @@ -91,7 +95,7 @@ virtual size: 0 B (0 bytes) 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse', 'writable': true } } {"return": {}} -write failed: Permission denied +qemu-io: can't open device TEST_DIR/t.IMGFMT: Could not open 'TEST_DIR/t.IMGFMT': Permission denied 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/common.rc b/tests/qemu-iotests/common.rc index cbbf6d7..609d82d 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -512,9 +512,13 @@ _make_test_img() # Usually, users would export formatted nodes. But we present fuse as a # protocol-level driver here, so we have to leave the format to the # client. + # Switch off allow-other, because in general we do not need it for + # iotests. The default allow-other=auto has the downside of printing a + # fusermount error on its first attempt if allow_other is not + # permissible, which we would need to filter. QSD_NEED_PID=y $QSD \ --blockdev file,node-name=export-node,filename=$img_name,discard=unmap \ - --export fuse,id=fuse-export,node-name=export-node,mountpoint="$export_mp",writable=on,growable=on \ + --export fuse,id=fuse-export,node-name=export-node,mountpoint="$export_mp",writable=on,growable=on,allow-other=off \ & pidfile="$QEMU_TEST_DIR/qemu-storage-daemon.pid" diff --git a/tests/qemu-iotests/tests/fuse-allow-other b/tests/qemu-iotests/tests/fuse-allow-other new file mode 100755 index 0000000..19f494a --- /dev/null +++ b/tests/qemu-iotests/tests/fuse-allow-other @@ -0,0 +1,168 @@ +#!/usr/bin/env bash +# group: rw +# +# Test FUSE exports' allow-other option +# +# Copyright (C) 2021 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/>. +# + +seq=$(basename "$0") +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_qemu + _cleanup_test_img + rm -f "$EXT_MP" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ../common.rc +. ../common.filter +. ../common.qemu + +_supported_fmt generic + +_supported_proto file # We create the FUSE export manually + +sudo -n -u nobody true || \ + _notrun 'Password-less sudo as nobody required to test allow_other' + +# $1: Export ID +# $2: Options (beyond the node-name and ID) +# $3: Expected return value (defaults to 'return') +# $4: Node to export (defaults to 'node-format') +fuse_export_add() +{ + allow_other_not_supported='option allow_other only allowed if' + + output=$( + success_or_failure=yes _send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'block-export-add', + 'arguments': { + 'type': 'fuse', + 'id': '$1', + 'node-name': '${4:-node-format}', + $2 + } }" \ + "${3:-return}" \ + "$allow_other_not_supported" \ + | _filter_imgfmt + ) + + if echo "$output" | grep -q "$allow_other_not_supported"; then + # Shut down qemu gracefully so it can unmount the export + _send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'quit'}" \ + 'return' + + wait=yes _cleanup_qemu + + _notrun "allow_other not supported" + fi + + echo "$output" +} + +EXT_MP="$TEST_DIR/fuse-export" + +_make_test_img 64k +touch "$EXT_MP" + +echo +echo '=== Test permissions ===' + +# $1: allow-other value ('on'/'off'/'auto') +run_permission_test() +{ + _launch_qemu \ + -blockdev \ + "$IMGFMT,node-name=node-format,file.driver=file,file.filename=$TEST_IMG" + + _send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'qmp_capabilities'}" \ + 'return' + + fuse_export_add 'export' \ + "'mountpoint': '$EXT_MP', + 'allow-other': '$1'" + + # Should always work + echo '(Removing all permissions)' + chmod 000 "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt + stat -c 'Permissions post-chmod: %a' "$EXT_MP" + + # Should always work + echo '(Granting u+r)' + chmod u+r "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt + stat -c 'Permissions post-chmod: %a' "$EXT_MP" + + # Should only work with allow-other: Otherwise, no permissions can be + # granted to the group or others + echo '(Granting read permissions for everyone)' + chmod 444 "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt + stat -c 'Permissions post-chmod: %a' "$EXT_MP" + + echo 'Doing operations as nobody:' + # Change to TEST_DIR, so nobody will not have to attempt a lookup + pushd "$TEST_DIR" >/dev/null + + # This is already prevented by the permissions (without allow-other, FUSE + # exports always have o-r), but test it anyway + sudo -n -u nobody cat fuse-export >/dev/null + + # If the only problem were the lack of permissions, we should still be able + # to stat the export as nobody; it should not work without allow-other, + # though + sudo -n -u nobody \ + stat -c 'Permissions seen by nobody: %a' fuse-export 2>&1 \ + | _filter_imgfmt + + # To prove the point, revoke read permissions for others and try again + chmod o-r fuse-export 2>&1 | _filter_testdir | _filter_imgfmt + + # Should fail + sudo -n -u nobody cat fuse-export >/dev/null + # Should work with allow_other + sudo -n -u nobody \ + stat -c 'Permissions seen by nobody: %a' fuse-export 2>&1 \ + | _filter_imgfmt + + popd >/dev/null + + _send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'quit'}" \ + 'return' + + wait=yes _cleanup_qemu +} + +# 'auto' should behave exactly like 'on', because 'on' tests that +# allow_other works (otherwise, this test is skipped) +for ao in off on auto; do + echo + echo "--- allow-other=$ao ---" + + run_permission_test "$ao" +done + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/tests/fuse-allow-other.out b/tests/qemu-iotests/tests/fuse-allow-other.out new file mode 100644 index 0000000..543fa52 --- /dev/null +++ b/tests/qemu-iotests/tests/fuse-allow-other.out @@ -0,0 +1,88 @@ +QA output created by fuse-allow-other +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536 + +=== Test permissions === + +--- allow-other=off --- +{'execute': 'qmp_capabilities'} +{"return": {}} +{'execute': 'block-export-add', + 'arguments': { + 'type': 'fuse', + 'id': 'export', + 'node-name': 'node-format', + 'mountpoint': 'TEST_DIR/fuse-export', + 'allow-other': 'off' + } } +{"return": {}} +(Removing all permissions) +Permissions post-chmod: 0 +(Granting u+r) +Permissions post-chmod: 400 +(Granting read permissions for everyone) +chmod: changing permissions of 'TEST_DIR/fuse-export': Operation not permitted +Permissions post-chmod: 400 +Doing operations as nobody: +cat: fuse-export: Permission denied +stat: cannot statx 'fuse-export': Permission denied +cat: fuse-export: Permission denied +stat: cannot statx 'fuse-export': Permission denied +{'execute': 'quit'} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}} + +--- allow-other=on --- +{'execute': 'qmp_capabilities'} +{"return": {}} +{'execute': 'block-export-add', + 'arguments': { + 'type': 'fuse', + 'id': 'export', + 'node-name': 'node-format', + 'mountpoint': 'TEST_DIR/fuse-export', + 'allow-other': 'on' + } } +{"return": {}} +(Removing all permissions) +Permissions post-chmod: 0 +(Granting u+r) +Permissions post-chmod: 400 +(Granting read permissions for everyone) +Permissions post-chmod: 444 +Doing operations as nobody: +Permissions seen by nobody: 444 +cat: fuse-export: Permission denied +Permissions seen by nobody: 440 +{'execute': 'quit'} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}} + +--- allow-other=auto --- +{'execute': 'qmp_capabilities'} +{"return": {}} +{'execute': 'block-export-add', + 'arguments': { + 'type': 'fuse', + 'id': 'export', + 'node-name': 'node-format', + 'mountpoint': 'TEST_DIR/fuse-export', + 'allow-other': 'auto' + } } +{"return": {}} +(Removing all permissions) +Permissions post-chmod: 0 +(Granting u+r) +Permissions post-chmod: 400 +(Granting read permissions for everyone) +Permissions post-chmod: 444 +Doing operations as nobody: +Permissions seen by nobody: 444 +cat: fuse-export: Permission denied +Permissions seen by nobody: 440 +{'execute': 'quit'} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}} +*** done diff --git a/tests/qemu-iotests/tests/remove-bitmap-from-backing b/tests/qemu-iotests/tests/remove-bitmap-from-backing index 0ea4c36..8d48fc0 100755 --- a/tests/qemu-iotests/tests/remove-bitmap-from-backing +++ b/tests/qemu-iotests/tests/remove-bitmap-from-backing @@ -41,25 +41,27 @@ log('Trying to remove persistent bitmap from r-o base node, should fail:') vm.qmp_log('block-dirty-bitmap-remove', node='base', name='bitmap0') new_base_opts = { - 'node-name': 'base', - 'driver': 'qcow2', - 'file': { - 'driver': 'file', - 'filename': base - }, - 'read-only': False + 'options': [{ + 'node-name': 'base', + 'driver': 'qcow2', + 'file': { + 'driver': 'file', + 'filename': base + }, + 'read-only': False + }] } # Don't want to bother with filtering qmp_log for reopen command -result = vm.qmp('x-blockdev-reopen', **new_base_opts) +result = vm.qmp('blockdev-reopen', **new_base_opts) if result != {'return': {}}: log('Failed to reopen: ' + str(result)) log('Remove persistent bitmap from base node reopened to RW:') vm.qmp_log('block-dirty-bitmap-remove', node='base', name='bitmap0') -new_base_opts['read-only'] = True -result = vm.qmp('x-blockdev-reopen', **new_base_opts) +new_base_opts['options'][0]['read-only'] = True +result = vm.qmp('blockdev-reopen', **new_base_opts) if result != {'return': {}}: log('Failed to reopen: ' + str(result)) |