mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-06 17:23:56 -06:00
Block layer patches:
- qemu-img create: Fail gracefully when backing file is an empty string - Fixes related to filter block nodes ("Deal with filters" series) - block/nvme: Various cleanups required to use multiple queues - block/nvme: Use NvmeBar structure from "block/nvme.h" - file-win32: Fix "locking" option - iotests: Allow running from different directory -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAl9Z7bcRHGt3b2xmQHJl ZGhhdC5jb20ACgkQfwmycsiPL9ZS6w//bos+A0RfRRF0YFWkIBLQWxqzKcGvMJ8W XWv3mFzd47UaDgRYwVnCC3CR6bLYEINISngZ3geA4jI1+w7AtYKDOO0HN32dUg+D ZrNMn02701CA6qkmpxJ+yjsrl9ltR3jYe0me4Wr39Pvdexa2pl/e+M4Vas6FhkYL ghAwNThypscGCrFjAlz3ru2Sc/K+sPWrGoqkzr+SWvsm9wy4vb8aLxr8Yy50x/zc CqALS9SQ/YA93BCVi9CzPkVyV3ioA0kg/y38WvLtAQ9GZ3m/ekMro3WvdYsRsFCN LGXsuwFig+U7Kd7lJrCS9TLnlTJstNGqPq9jEoV5cThPvGknFfMvVOzRmmP7tzqT YRcPRy39z44OoLKa3kyg3aF38BTxt+9gPqBnivKMr9j9EecMvPsXXHRvF+lP+LsP j753Ih561hX6FurcjX8pc9GOM2cQA0GjlyL77UTTAmLZyFXP/8e55oQbBuYTylc/ Xlvmc/T+yEGiEGTnK+FxgDAiUaxbCCM9cDVStJjTvsIq43dwXb48g1onDsGZ5eDf j9lmAD6TJxHNOB5ErNsDPODf4/D1wJ9t9WVF8UZp9ArfPHRdxMzT7Q4LvetaDmVl +hQC9cgTq8Qd8LwSqbKEYua4L6iGbmLAT7/N6htq5L1eVLg76/tLg/tKSwh/vKAY yzPmyHaVK84= =gaaW -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches: - qemu-img create: Fail gracefully when backing file is an empty string - Fixes related to filter block nodes ("Deal with filters" series) - block/nvme: Various cleanups required to use multiple queues - block/nvme: Use NvmeBar structure from "block/nvme.h" - file-win32: Fix "locking" option - iotests: Allow running from different directory # gpg: Signature made Thu 10 Sep 2020 10:11:19 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: (65 commits) block/qcow2-cluster: Add missing "fallthrough" annotation block/nvme: Pair doorbell registers block/nvme: Use generic NvmeBar structure block/nvme: Group controller registers in NVMeRegs structure file-win32: Fix "locking" option iotests: Allow running from different directory iotests: Test committing to overridden backing iotests: Add test for commit in sub directory iotests: Add filter mirror test cases iotests: Add filter commit test cases iotests: Let complete_and_wait() work with commit iotests: Test that qcow2's data-file is flushed block: Leave BDS.backing_{file,format} constant block: Inline bdrv_co_block_status_from_*() blockdev: Fix active commit choice block: Drop backing_bs() qemu-img: Use child access functions nbd: Use CAF when looking for dirty bitmap commit: Deal with filters backup: Deal with filters ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
2499453eb1
49 changed files with 1764 additions and 555 deletions
|
@ -31,6 +31,11 @@ _cleanup()
|
|||
_cleanup_test_img
|
||||
_rm_test_img "$TEST_IMG.base"
|
||||
_rm_test_img "$TEST_IMG.orig"
|
||||
|
||||
_rm_test_img "$TEST_DIR/subdir/t.$IMGFMT.base"
|
||||
_rm_test_img "$TEST_DIR/subdir/t.$IMGFMT.mid"
|
||||
_rm_test_img "$TEST_DIR/subdir/t.$IMGFMT"
|
||||
rmdir "$TEST_DIR/subdir" &> /dev/null
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
|
@ -139,6 +144,45 @@ $QEMU_IO -c 'writev 0 64k' "$TEST_IMG" | _filter_qemu_io
|
|||
$QEMU_IMG commit "$TEST_IMG"
|
||||
_cleanup
|
||||
|
||||
|
||||
echo
|
||||
echo 'Testing commit in sub-directory with relative filenames'
|
||||
echo
|
||||
|
||||
pushd "$TEST_DIR" > /dev/null
|
||||
|
||||
mkdir subdir
|
||||
|
||||
TEST_IMG="subdir/t.$IMGFMT.base" _make_test_img 1M
|
||||
TEST_IMG="subdir/t.$IMGFMT.mid" _make_test_img -b "t.$IMGFMT.base" -F $IMGFMT
|
||||
TEST_IMG="subdir/t.$IMGFMT" _make_test_img -b "t.$IMGFMT.mid" -F $IMGFMT
|
||||
|
||||
# Should work
|
||||
$QEMU_IMG commit -b "t.$IMGFMT.mid" "subdir/t.$IMGFMT"
|
||||
|
||||
# Might theoretically work, but does not in practice (we have to
|
||||
# decide between this and the above; and since we always represent
|
||||
# backing file names as relative to the overlay, we go for the above)
|
||||
$QEMU_IMG commit -b "subdir/t.$IMGFMT.mid" "subdir/t.$IMGFMT" 2>&1 | \
|
||||
_filter_imgfmt
|
||||
|
||||
# This should work as well
|
||||
$QEMU_IMG commit -b "$TEST_DIR/subdir/t.$IMGFMT.mid" "subdir/t.$IMGFMT"
|
||||
|
||||
popd > /dev/null
|
||||
|
||||
# Now let's try with just absolute filenames
|
||||
# (This will not work with external data files, though, because when
|
||||
# using relative paths for those, qemu will always resolve them
|
||||
# relative to its CWD. Therefore, it cannot find those data files now
|
||||
# that we left $TEST_DIR.)
|
||||
if _get_data_file '' > /dev/null; then
|
||||
echo 'Image committed.' # Skip test
|
||||
else
|
||||
$QEMU_IMG commit -b "$TEST_DIR/subdir/t.$IMGFMT.mid" \
|
||||
"$TEST_DIR/subdir/t.$IMGFMT"
|
||||
fi
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
|
|
|
@ -1083,4 +1083,14 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=json:{'driv
|
|||
wrote 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
qemu-img: Block job failed: No space left on device
|
||||
|
||||
Testing commit in sub-directory with relative filenames
|
||||
|
||||
Formatting 'subdir/t.IMGFMT.base', fmt=IMGFMT size=1048576
|
||||
Formatting 'subdir/t.IMGFMT.mid', fmt=IMGFMT size=1048576 backing_file=t.IMGFMT.base backing_fmt=IMGFMT
|
||||
Formatting 'subdir/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=t.IMGFMT.mid backing_fmt=IMGFMT
|
||||
Image committed.
|
||||
qemu-img: Did not find 'subdir/t.IMGFMT.mid' in the backing chain of 'subdir/t.IMGFMT'
|
||||
Image committed.
|
||||
Image committed.
|
||||
*** done
|
||||
|
|
|
@ -734,6 +734,244 @@ class TestErrorHandling(iotests.QMPTestCase):
|
|||
self.assertTrue(iotests.compare_images(mid_img, backing_img, fmt2='raw'),
|
||||
'target image does not match source after commit')
|
||||
|
||||
class TestCommitWithFilters(iotests.QMPTestCase):
|
||||
img0 = os.path.join(iotests.test_dir, '0.img')
|
||||
img1 = os.path.join(iotests.test_dir, '1.img')
|
||||
img2 = os.path.join(iotests.test_dir, '2.img')
|
||||
img3 = os.path.join(iotests.test_dir, '3.img')
|
||||
|
||||
def do_test_io(self, read_or_write):
|
||||
for index, pattern_file in enumerate(self.pattern_files):
|
||||
result = qemu_io('-f', iotests.imgfmt,
|
||||
'-c',
|
||||
f'{read_or_write} -P {index + 1} {index}M 1M',
|
||||
pattern_file)
|
||||
self.assertFalse('Pattern verification failed' in result)
|
||||
|
||||
def setUp(self):
|
||||
qemu_img('create', '-f', iotests.imgfmt, self.img0, '64M')
|
||||
qemu_img('create', '-f', iotests.imgfmt, self.img1, '64M')
|
||||
qemu_img('create', '-f', iotests.imgfmt, self.img2, '64M')
|
||||
qemu_img('create', '-f', iotests.imgfmt, self.img3, '64M')
|
||||
|
||||
# Distributions of the patterns in the files; this is checked
|
||||
# by tearDown() and should be changed by the test cases as is
|
||||
# necessary
|
||||
self.pattern_files = [self.img0, self.img1, self.img2, self.img3]
|
||||
|
||||
self.do_test_io('write')
|
||||
|
||||
self.vm = iotests.VM().add_device('virtio-scsi,id=vio-scsi')
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('blockdev-add', **{
|
||||
'node-name': 'top-filter',
|
||||
'driver': 'throttle',
|
||||
'throttle-group': 'tg',
|
||||
'file': {
|
||||
'node-name': 'cow-3',
|
||||
'driver': iotests.imgfmt,
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': self.img3
|
||||
},
|
||||
'backing': {
|
||||
'node-name': 'cow-2',
|
||||
'driver': iotests.imgfmt,
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': self.img2
|
||||
},
|
||||
'backing': {
|
||||
'node-name': 'cow-1',
|
||||
'driver': iotests.imgfmt,
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': self.img1
|
||||
},
|
||||
'backing': {
|
||||
'node-name': 'bottom-filter',
|
||||
'driver': 'throttle',
|
||||
'throttle-group': 'tg',
|
||||
'file': {
|
||||
'node-name': 'cow-0',
|
||||
'driver': iotests.imgfmt,
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': self.img0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
def tearDown(self):
|
||||
self.vm.shutdown()
|
||||
self.do_test_io('read')
|
||||
|
||||
os.remove(self.img3)
|
||||
os.remove(self.img2)
|
||||
os.remove(self.img1)
|
||||
os.remove(self.img0)
|
||||
|
||||
# Filters make for funny filenames, so we cannot just use
|
||||
# self.imgX to get them
|
||||
def get_filename(self, node):
|
||||
return self.vm.node_info(node)['image']['filename']
|
||||
|
||||
def test_filterless_commit(self):
|
||||
result = self.vm.qmp('block-commit',
|
||||
job_id='commit',
|
||||
device='top-filter',
|
||||
top_node='cow-2',
|
||||
base_node='cow-1')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.wait_until_completed(drive='commit')
|
||||
|
||||
self.assertIsNotNone(self.vm.node_info('cow-3'))
|
||||
self.assertIsNone(self.vm.node_info('cow-2'))
|
||||
self.assertIsNotNone(self.vm.node_info('cow-1'))
|
||||
|
||||
# 2 has been comitted into 1
|
||||
self.pattern_files[2] = self.img1
|
||||
|
||||
def test_commit_through_filter(self):
|
||||
result = self.vm.qmp('block-commit',
|
||||
job_id='commit',
|
||||
device='top-filter',
|
||||
top_node='cow-1',
|
||||
base_node='cow-0')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.wait_until_completed(drive='commit')
|
||||
|
||||
self.assertIsNotNone(self.vm.node_info('cow-2'))
|
||||
self.assertIsNone(self.vm.node_info('cow-1'))
|
||||
self.assertIsNone(self.vm.node_info('bottom-filter'))
|
||||
self.assertIsNotNone(self.vm.node_info('cow-0'))
|
||||
|
||||
# 1 has been comitted into 0
|
||||
self.pattern_files[1] = self.img0
|
||||
|
||||
def test_filtered_active_commit_with_filter(self):
|
||||
# Add a device, so the commit job finds a parent it can change
|
||||
# to point to the base node (so we can test that top-filter is
|
||||
# dropped from the graph)
|
||||
result = self.vm.qmp('device_add', id='drv0', driver='scsi-hd',
|
||||
bus='vio-scsi.0', drive='top-filter')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# Try to release our reference to top-filter; that should not
|
||||
# work because drv0 uses it
|
||||
result = self.vm.qmp('blockdev-del', node_name='top-filter')
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
self.assert_qmp(result, 'error/desc', 'Node top-filter is in use')
|
||||
|
||||
result = self.vm.qmp('block-commit',
|
||||
job_id='commit',
|
||||
device='top-filter',
|
||||
base_node='cow-2')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.complete_and_wait(drive='commit')
|
||||
|
||||
# Try to release our reference to top-filter again
|
||||
result = self.vm.qmp('blockdev-del', node_name='top-filter')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.assertIsNone(self.vm.node_info('top-filter'))
|
||||
self.assertIsNone(self.vm.node_info('cow-3'))
|
||||
self.assertIsNotNone(self.vm.node_info('cow-2'))
|
||||
|
||||
# Check that drv0 is now connected to cow-2
|
||||
blockdevs = self.vm.qmp('query-block')['return']
|
||||
drv0 = next(dev for dev in blockdevs if dev['qdev'] == 'drv0')
|
||||
self.assertEqual(drv0['inserted']['node-name'], 'cow-2')
|
||||
|
||||
# 3 has been comitted into 2
|
||||
self.pattern_files[3] = self.img2
|
||||
|
||||
def test_filtered_active_commit_without_filter(self):
|
||||
result = self.vm.qmp('block-commit',
|
||||
job_id='commit',
|
||||
device='top-filter',
|
||||
top_node='cow-3',
|
||||
base_node='cow-2')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.complete_and_wait(drive='commit')
|
||||
|
||||
self.assertIsNotNone(self.vm.node_info('top-filter'))
|
||||
self.assertIsNone(self.vm.node_info('cow-3'))
|
||||
self.assertIsNotNone(self.vm.node_info('cow-2'))
|
||||
|
||||
# 3 has been comitted into 2
|
||||
self.pattern_files[3] = self.img2
|
||||
|
||||
class TestCommitWithOverriddenBacking(iotests.QMPTestCase):
|
||||
img_base_a = os.path.join(iotests.test_dir, 'base_a.img')
|
||||
img_base_b = os.path.join(iotests.test_dir, 'base_b.img')
|
||||
img_top = os.path.join(iotests.test_dir, 'top.img')
|
||||
|
||||
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)
|
||||
|
||||
self.vm = iotests.VM()
|
||||
self.vm.launch()
|
||||
|
||||
# Use base_b instead of base_a as the backing of top
|
||||
result = self.vm.qmp('blockdev-add', **{
|
||||
'node-name': 'top',
|
||||
'driver': iotests.imgfmt,
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': self.img_top
|
||||
},
|
||||
'backing': {
|
||||
'node-name': 'base',
|
||||
'driver': iotests.imgfmt,
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': self.img_base_b
|
||||
}
|
||||
}
|
||||
})
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
def tearDown(self):
|
||||
self.vm.shutdown()
|
||||
os.remove(self.img_top)
|
||||
os.remove(self.img_base_a)
|
||||
os.remove(self.img_base_b)
|
||||
|
||||
def test_commit_to_a(self):
|
||||
# Try committing to base_a (which should fail, as top's
|
||||
# backing image is base_b instead)
|
||||
result = self.vm.qmp('block-commit',
|
||||
job_id='commit',
|
||||
device='top',
|
||||
base=self.img_base_a)
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
|
||||
def test_commit_to_b(self):
|
||||
# Try committing to base_b (which should work, since that is
|
||||
# actually top's backing image)
|
||||
result = self.vm.qmp('block-commit',
|
||||
job_id='commit',
|
||||
device='top',
|
||||
base=self.img_base_b)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.vm.event_wait('BLOCK_JOB_READY')
|
||||
self.vm.qmp('block-job-complete', device='commit')
|
||||
self.vm.event_wait('BLOCK_JOB_COMPLETED')
|
||||
|
||||
if __name__ == '__main__':
|
||||
iotests.main(supported_fmts=['qcow2', 'qed'],
|
||||
supported_protocols=['file'])
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
...........................................................
|
||||
.................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 59 tests
|
||||
Ran 65 tests
|
||||
|
||||
OK
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
import time
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import iotests
|
||||
from iotests import qemu_img, qemu_io
|
||||
from iotests import qemu_img, qemu_img_pipe, qemu_io
|
||||
|
||||
backing_img = os.path.join(iotests.test_dir, 'backing.img')
|
||||
target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img')
|
||||
|
@ -1288,6 +1289,149 @@ class TestReplaces(iotests.QMPTestCase):
|
|||
|
||||
self.vm.assert_block_path('filter0', '/file', 'target')
|
||||
|
||||
# Tests for mirror with filters (and how the mirror filter behaves, as
|
||||
# an example for an implicit filter)
|
||||
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_io('-c', 'write -P 1 0 512k', backing_img)
|
||||
qemu_io('-c', 'write -P 2 512k 512k', test_img)
|
||||
|
||||
self.vm = iotests.VM().add_device('virtio-scsi,id=vio-scsi')
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('blockdev-add', **{
|
||||
'node-name': 'target',
|
||||
'driver': iotests.imgfmt,
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': target_img
|
||||
},
|
||||
'backing': None
|
||||
})
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.filterless_chain = {
|
||||
'node-name': 'source',
|
||||
'driver': iotests.imgfmt,
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': test_img
|
||||
},
|
||||
'backing': {
|
||||
'node-name': 'backing',
|
||||
'driver': iotests.imgfmt,
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': backing_img
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def tearDown(self):
|
||||
self.vm.shutdown()
|
||||
|
||||
os.remove(test_img)
|
||||
os.remove(target_img)
|
||||
os.remove(backing_img)
|
||||
|
||||
def test_cor(self):
|
||||
result = self.vm.qmp('blockdev-add', **{
|
||||
'node-name': 'filter',
|
||||
'driver': 'copy-on-read',
|
||||
'file': self.filterless_chain
|
||||
})
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('blockdev-mirror',
|
||||
job_id='mirror',
|
||||
device='filter',
|
||||
target='target',
|
||||
sync='top')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.complete_and_wait('mirror')
|
||||
|
||||
self.vm.qmp('blockdev-del', node_name='target')
|
||||
|
||||
target_map = qemu_img_pipe('map', '--output=json', target_img)
|
||||
target_map = json.loads(target_map)
|
||||
|
||||
assert target_map[0]['start'] == 0
|
||||
assert target_map[0]['length'] == 512 * 1024
|
||||
assert target_map[0]['depth'] == 1
|
||||
|
||||
assert target_map[1]['start'] == 512 * 1024
|
||||
assert target_map[1]['length'] == 512 * 1024
|
||||
assert target_map[1]['depth'] == 0
|
||||
|
||||
def test_implicit_mirror_filter(self):
|
||||
result = self.vm.qmp('blockdev-add', **self.filterless_chain)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# We need this so we can query from above the mirror node
|
||||
result = self.vm.qmp('device_add',
|
||||
driver='scsi-hd',
|
||||
id='virtio',
|
||||
bus='vio-scsi.0',
|
||||
drive='source')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('blockdev-mirror',
|
||||
job_id='mirror',
|
||||
device='source',
|
||||
target='target',
|
||||
sync='top')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# The mirror filter is now an implicit node, so it should be
|
||||
# invisible when querying the backing chain
|
||||
blockdevs = self.vm.qmp('query-block')['return']
|
||||
device_info = next(dev for dev in blockdevs if dev['qdev'] == 'virtio')
|
||||
|
||||
assert device_info['inserted']['node-name'] == 'source'
|
||||
|
||||
image_info = device_info['inserted']['image']
|
||||
assert image_info['filename'] == test_img
|
||||
assert image_info['backing-image']['filename'] == backing_img
|
||||
|
||||
self.complete_and_wait('mirror')
|
||||
|
||||
def test_explicit_mirror_filter(self):
|
||||
# Same test as above, but this time we give the mirror filter
|
||||
# a node-name so it will not be invisible
|
||||
result = self.vm.qmp('blockdev-add', **self.filterless_chain)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# We need this so we can query from above the mirror node
|
||||
result = self.vm.qmp('device_add',
|
||||
driver='scsi-hd',
|
||||
id='virtio',
|
||||
bus='vio-scsi.0',
|
||||
drive='source')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('blockdev-mirror',
|
||||
job_id='mirror',
|
||||
device='source',
|
||||
target='target',
|
||||
sync='top',
|
||||
filter_node_name='mirror-filter')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# With a node-name given to it, the mirror filter should now
|
||||
# be visible
|
||||
blockdevs = self.vm.qmp('query-block')['return']
|
||||
device_info = next(dev for dev in blockdevs if dev['qdev'] == 'virtio')
|
||||
|
||||
assert device_info['inserted']['node-name'] == 'mirror-filter'
|
||||
|
||||
self.complete_and_wait('mirror')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
iotests.main(supported_fmts=['qcow2', 'qed'],
|
||||
supported_protocols=['file'],
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
........................................................................................................
|
||||
...........................................................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 104 tests
|
||||
Ran 107 tests
|
||||
|
||||
OK
|
||||
|
|
|
@ -119,6 +119,10 @@ test_qemu_img create -f $IMGFMT -o compat=1.1,lazy_refcounts=on "$TEST_IMG" 64M
|
|||
test_qemu_img create -f $IMGFMT -o compat=0.10,lazy_refcounts=off "$TEST_IMG" 64M
|
||||
test_qemu_img create -f $IMGFMT -o compat=0.10,lazy_refcounts=on "$TEST_IMG" 64M
|
||||
|
||||
echo "== Expect error when backing file name is empty string =="
|
||||
echo
|
||||
test_qemu_img create -f $IMGFMT -b '' $TEST_IMG 1M
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
|
|
|
@ -209,4 +209,9 @@ qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
|
|||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=on refcount_bits=16
|
||||
qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
|
||||
|
||||
== Expect error when backing file name is empty string ==
|
||||
|
||||
qemu-img create -f qcow2 -b TEST_DIR/t.qcow2 1M
|
||||
qemu-img: TEST_DIR/t.qcow2: Expected backing file name, got empty string
|
||||
|
||||
*** done
|
||||
|
|
|
@ -464,7 +464,7 @@ No conflict:
|
|||
image: null-co://
|
||||
file format: null-co
|
||||
virtual size: 1 GiB (1073741824 bytes)
|
||||
disk size: unavailable
|
||||
disk size: 0 B
|
||||
|
||||
Conflict:
|
||||
qemu-img: --force-share/-U conflicts with image options
|
||||
|
|
|
@ -45,8 +45,7 @@ do_run_qemu()
|
|||
run_qemu()
|
||||
{
|
||||
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
|
||||
| _filter_qemu_io | _filter_generated_node_ids \
|
||||
| _filter_actual_image_size
|
||||
| _filter_qemu_io | _filter_generated_node_ids
|
||||
}
|
||||
|
||||
test_throttle=$($QEMU_IMG --help|grep throttle)
|
||||
|
|
|
@ -27,14 +27,21 @@ Testing:
|
|||
"iops_rd": 0,
|
||||
"detect_zeroes": "off",
|
||||
"image": {
|
||||
"backing-image": {
|
||||
"virtual-size": 1073741824,
|
||||
"filename": "null-co://",
|
||||
"format": "null-co",
|
||||
"actual-size": 0
|
||||
},
|
||||
"virtual-size": 1073741824,
|
||||
"filename": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"null-co\"}}",
|
||||
"format": "throttle"
|
||||
"format": "throttle",
|
||||
"actual-size": 0
|
||||
},
|
||||
"iops_wr": 0,
|
||||
"ro": false,
|
||||
"node-name": "throttle0",
|
||||
"backing_file_depth": 0,
|
||||
"backing_file_depth": 1,
|
||||
"drv": "throttle",
|
||||
"iops": 0,
|
||||
"bps_wr": 0,
|
||||
|
@ -56,7 +63,8 @@ Testing:
|
|||
"image": {
|
||||
"virtual-size": 1073741824,
|
||||
"filename": "null-co://",
|
||||
"format": "null-co"
|
||||
"format": "null-co",
|
||||
"actual-size": 0
|
||||
},
|
||||
"iops_wr": 0,
|
||||
"ro": false,
|
||||
|
|
|
@ -59,5 +59,6 @@ Offset Length File
|
|||
0x900000 0x2400000 TEST_DIR/t.IMGFMT
|
||||
0x3c00000 0x1100000 TEST_DIR/t.IMGFMT
|
||||
0x6a00000 0x400000 TEST_DIR/t.IMGFMT
|
||||
0x6e00000 0x1200000 TEST_DIR/t.IMGFMT.base
|
||||
No errors were found on the image.
|
||||
*** done
|
||||
|
|
|
@ -36,7 +36,7 @@ def log_node_info(node):
|
|||
|
||||
log('bs->filename: ' + node['image']['filename'],
|
||||
filters=[filter_testfiles, filter_imgfmt])
|
||||
log('bs->backing_file: ' + node['backing_file'],
|
||||
log('bs->backing_file: ' + node['image']['full-backing-filename'],
|
||||
filters=[filter_testfiles, filter_imgfmt])
|
||||
|
||||
if 'backing-image' in node['image']:
|
||||
|
@ -73,8 +73,8 @@ with iotests.FilePath('base.img') as base_img_path, \
|
|||
},
|
||||
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
|
||||
|
||||
# Filename should be plain, and the backing filename should not
|
||||
# contain the "file:" prefix
|
||||
# Filename should be plain, and the backing node filename should
|
||||
# not contain the "file:" prefix
|
||||
log_node_info(vm.node_info('node0'))
|
||||
|
||||
vm.qmp_log('blockdev-del', node_name='node0')
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{"return": {}}
|
||||
|
||||
bs->filename: TEST_DIR/PID-top.img
|
||||
bs->backing_file: TEST_DIR/PID-base.img
|
||||
bs->backing_file: file:TEST_DIR/PID-base.img
|
||||
bs->backing->bs->filename: TEST_DIR/PID-base.img
|
||||
|
||||
{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
|
||||
|
@ -41,7 +41,7 @@ bs->backing->bs->filename: TEST_DIR/PID-base.img
|
|||
{"return": {}}
|
||||
|
||||
bs->filename: TEST_DIR/PID-top.img
|
||||
bs->backing_file: TEST_DIR/PID-base.img
|
||||
bs->backing_file: file:TEST_DIR/PID-base.img
|
||||
bs->backing->bs->filename: TEST_DIR/PID-base.img
|
||||
|
||||
{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
|
||||
|
@ -55,7 +55,7 @@ bs->backing->bs->filename: TEST_DIR/PID-base.img
|
|||
{"return": {}}
|
||||
|
||||
bs->filename: json:{"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
|
||||
bs->backing_file: null-co://
|
||||
bs->backing_file: TEST_DIR/PID-base.img
|
||||
bs->backing->bs->filename: null-co://
|
||||
|
||||
{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
|
||||
|
|
|
@ -217,6 +217,55 @@ $QEMU_IMG amend -f $IMGFMT -o "data_file=blkdebug::$TEST_IMG.data" "$TEST_IMG"
|
|||
$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
|
||||
$QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
|
||||
|
||||
echo
|
||||
echo "=== Flushing should flush the data file ==="
|
||||
echo
|
||||
|
||||
# We are going to flush a qcow2 file with a blkdebug node inserted
|
||||
# between the qcow2 node and its data file node. The blkdebug node
|
||||
# will return an error for all flushes and so we if the data file is
|
||||
# flushed, we will see qemu-io return an error.
|
||||
|
||||
# We need to write something or the flush will not do anything; we
|
||||
# also need -t writeback so the write is not done as a FUA write
|
||||
# (which would then fail thanks to the implicit flush)
|
||||
$QEMU_IO -c 'write 0 512' -c flush \
|
||||
-t writeback \
|
||||
"json:{
|
||||
'driver': 'qcow2',
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': '$TEST_IMG'
|
||||
},
|
||||
'data-file': {
|
||||
'driver': 'blkdebug',
|
||||
'inject-error': [{
|
||||
'event': 'none',
|
||||
'iotype': 'flush'
|
||||
}],
|
||||
'image': {
|
||||
'driver': 'file',
|
||||
'filename': '$TEST_IMG.data'
|
||||
}
|
||||
}
|
||||
}" \
|
||||
| _filter_qemu_io
|
||||
|
||||
result=${PIPESTATUS[0]}
|
||||
echo
|
||||
|
||||
case $result in
|
||||
0)
|
||||
echo "ERROR: qemu-io succeeded, so the data file was not flushed"
|
||||
;;
|
||||
1)
|
||||
echo "Success: qemu-io failed, so the data file was flushed"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: qemu-io returned unknown exit code $result"
|
||||
;;
|
||||
esac
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
|
|
|
@ -131,4 +131,11 @@ Offset Length Mapped to File
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
|
||||
Images are identical.
|
||||
Images are identical.
|
||||
|
||||
=== Flushing should flush the data file ===
|
||||
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
Success: qemu-io failed, so the data file was flushed
|
||||
*** done
|
||||
|
|
|
@ -725,7 +725,9 @@ class TestBlockdevReopen(iotests.QMPTestCase):
|
|||
|
||||
# Detach hd2 from hd0.
|
||||
self.reopen(opts, {'backing': None})
|
||||
self.reopen(opts, {}, "backing is missing for 'hd0'")
|
||||
|
||||
# Without a backing file, we can omit 'backing' again
|
||||
self.reopen(opts)
|
||||
|
||||
# Remove both hd0 and hd2
|
||||
result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
|
||||
|
|
|
@ -32,7 +32,7 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
|
|||
"actual-size": SIZE,
|
||||
"dirty-flag": false
|
||||
},
|
||||
"backing-filename-format": "file",
|
||||
"backing-filename-format": "IMGFMT",
|
||||
"virtual-size": 67108864,
|
||||
"filename": "TEST_DIR/t.IMGFMT.mid",
|
||||
"cluster-size": 65536,
|
||||
|
@ -112,7 +112,7 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
|
|||
"actual-size": SIZE,
|
||||
"dirty-flag": false
|
||||
},
|
||||
"backing-filename-format": "file",
|
||||
"backing-filename-format": "IMGFMT",
|
||||
"virtual-size": 67108864,
|
||||
"filename": "TEST_DIR/t.IMGFMT.mid",
|
||||
"cluster-size": 65536,
|
||||
|
|
|
@ -44,7 +44,7 @@ then
|
|||
_init_error "failed to obtain source tree name from check symlink"
|
||||
fi
|
||||
source_iotests=$(cd "$source_iotests"; pwd) || _init_error "failed to enter source tree"
|
||||
build_iotests=$PWD
|
||||
build_iotests=$(readlink -f $(dirname "$0"))
|
||||
else
|
||||
# called from the source tree
|
||||
source_iotests=$PWD
|
||||
|
|
|
@ -972,8 +972,12 @@ class QMPTestCase(unittest.TestCase):
|
|||
|
||||
def wait_ready(self, drive='drive0'):
|
||||
"""Wait until a BLOCK_JOB_READY event, and return the event."""
|
||||
f = {'data': {'type': 'mirror', 'device': drive}}
|
||||
return self.vm.event_wait(name='BLOCK_JOB_READY', match=f)
|
||||
return self.vm.events_wait([
|
||||
('BLOCK_JOB_READY',
|
||||
{'data': {'type': 'mirror', 'device': drive}}),
|
||||
('BLOCK_JOB_READY',
|
||||
{'data': {'type': 'commit', 'device': drive}})
|
||||
])
|
||||
|
||||
def wait_ready_and_cancel(self, drive='drive0'):
|
||||
self.wait_ready(drive=drive)
|
||||
|
@ -992,7 +996,7 @@ class QMPTestCase(unittest.TestCase):
|
|||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
event = self.wait_until_completed(drive=drive, error=completion_error)
|
||||
self.assert_qmp(event, 'data/type', 'mirror')
|
||||
self.assertTrue(event['data']['type'] in ['mirror', 'commit'])
|
||||
|
||||
def pause_wait(self, job_id='job0'):
|
||||
with Timeout(3, "Timeout waiting for job to pause"):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue