mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-07 01:33:56 -06:00
Block layer patches
- Make blockdev-reopen stable - Remove deprecated qemu-img backing file without format - rbd: Convert to coroutines and add write zeroes support - rbd: Updated MAINTAINERS - export/fuse: Allow other users access to the export - vhost-user: Fix backends without multiqueue support - Fix drive-backup transaction endless drained section -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmDoRdIRHGt3b2xmQHJl ZGhhdC5jb20ACgkQfwmycsiPL9bvgQ/+Ogq24n1UOQc8FEKRYfyhajNToQ9ofzWN iLiblSGx2QDq+CauD3qdu6z7DLlqEXeoM4NYM462oIPumptQj+9XZt7ftfh6FLWW 4yJEbjfnVKOba+vFdJ+E0DStwnPaxYdnrPGd53cwHZfbZh4ZmkpTM350mzHHiLTb KYKOgWd+UHZbkYeCVNYTGe30SRBiKeAecTpsVZ5HVhe7LstjByuy5stk8dytLpdV YqdKOToZfOp77XiHr8YcLLp1HHBGlr5hw73V4SDas0beCp7hqtnAqsTYyXBue4xO 4zfD4Gujr5JVOCb0crDTyOmOQY5E+y2dqFoOUF00D5AoN2vj4nfQ9ESkbqlE9BVh mgJ1izSokYlN2X8rIwGXNR5fbxRmxxfkAA4rScNRytj1KxDHyrDxrp/k8YFemxSQ qwgb/FBm0fcr69evPRzovKwZFhcyPremksluHQE4rZZ66qBQ2cGuDJPE7PWVTpPH 67JCrIVK/O6n5p+4ilFHmQQ3aP3ol0frMFcboYVRchJ2MhIDTsfFL3F/tTK8hy86 AmrrdQ1BQIAoKNOKnAmOSOUdExM55OcfPmX69+AhEk2GeWP6kgz5Pks4H3qCiKGf YoRk8F1V+N4q+C0mFFovB61bNQ6COIlBuzmD9EtmpDD/Ta3Wib+3ZnoGVIdPS+OI jyj+qJxd9z4= =kH+r -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches - Make blockdev-reopen stable - Remove deprecated qemu-img backing file without format - rbd: Convert to coroutines and add write zeroes support - rbd: Updated MAINTAINERS - export/fuse: Allow other users access to the export - vhost-user: Fix backends without multiqueue support - Fix drive-backup transaction endless drained section # gpg: Signature made Fri 09 Jul 2021 13:49:22 BST # 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: (28 commits) block: Make blockdev-reopen stable API iotests: Test reopening multiple devices at the same time block: Support multiple reopening with x-blockdev-reopen block: Acquire AioContexts during bdrv_reopen_multiple() block: Add bdrv_reopen_queue_free() qcow2: Fix dangling pointer after reopen for 'file' qemu-img: Improve error for rebase without backing format qemu-img: Require -F with -b backing image qcow2: Prohibit backing file changes in 'qemu-img amend' blockdev: fix drive-backup transaction endless drained section vhost-user: Fix backends without multiqueue support MAINTAINERS: add block/rbd.c reviewer block/rbd: fix type of task->complete iotests/fuse-allow-other: Test allow-other iotests/308: Test +w on read-only FUSE exports export/fuse: Let permissions be adjustable export/fuse: Give SET_ATTR_SIZE its own branch export/fuse: Add allow-other option export/fuse: Pass default_permissions for mount util/uri: do not check argument of uri_free() ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
42e1d798a6
42 changed files with 1367 additions and 560 deletions
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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": {}}
|
||||
|
|
|
@ -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', {})
|
||||
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
168
tests/qemu-iotests/tests/fuse-allow-other
Executable file
168
tests/qemu-iotests/tests/fuse-allow-other
Executable file
|
@ -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
|
88
tests/qemu-iotests/tests/fuse-allow-other.out
Normal file
88
tests/qemu-iotests/tests/fuse-allow-other.out
Normal file
|
@ -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
|
|
@ -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))
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue