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:
Peter Maydell 2020-09-11 14:47:49 +01:00
commit 2499453eb1
49 changed files with 1764 additions and 555 deletions

View file

@ -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

View file

@ -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

View file

@ -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'])

View file

@ -1,5 +1,5 @@
...........................................................
.................................................................
----------------------------------------------------------------------
Ran 59 tests
Ran 65 tests
OK

View file

@ -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'],

View file

@ -1,5 +1,5 @@
........................................................................................................
...........................................................................................................
----------------------------------------------------------------------
Ran 104 tests
Ran 107 tests
OK

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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,

View file

@ -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

View file

@ -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')

View file

@ -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"}}

View file

@ -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

View file

@ -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

View file

@ -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')

View file

@ -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,

View file

@ -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

View file

@ -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"):