iotests: Test commit job start with concurrent I/O

This tests that concurrent requests are correctly drained before making
graph modifications instead of running into assertions in
bdrv_replace_node().

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
Kevin Wolf 2019-05-21 20:35:52 +02:00
parent f871abd60f
commit ac6fb43eae
4 changed files with 109 additions and 1 deletions

83
tests/qemu-iotests/255 Executable file
View File

@ -0,0 +1,83 @@
#!/usr/bin/env python
#
# Test commit job graph modifications while requests are active
#
# Copyright (C) 2019 Red Hat, Inc.
#
# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import iotests
from iotests import imgfmt
iotests.verify_image_format(supported_fmts=['qcow2'])
def blockdev_create(vm, options):
result = vm.qmp_log('blockdev-create',
filters=[iotests.filter_qmp_testfiles],
job_id='job0', options=options)
if 'return' in result:
assert result['return'] == {}
vm.run_job('job0')
iotests.log("")
with iotests.FilePath('t.qcow2') as disk_path, \
iotests.FilePath('t.qcow2.mid') as mid_path, \
iotests.FilePath('t.qcow2.base') as base_path, \
iotests.VM() as vm:
iotests.log("=== Create backing chain and start VM ===")
iotests.log("")
size = 128 * 1024 * 1024
size_str = str(size)
iotests.create_image(base_path, size)
iotests.qemu_img_log('create', '-f', iotests.imgfmt, mid_path, size_str)
iotests.qemu_img_log('create', '-f', iotests.imgfmt, disk_path, size_str)
# Create a backing chain like this:
# base <- [throttled: bps-read=4096] <- mid <- overlay
vm.add_object('throttle-group,x-bps-read=4096,id=throttle0')
vm.add_blockdev('file,filename=%s,node-name=base' % (base_path))
vm.add_blockdev('throttle,throttle-group=throttle0,file=base,node-name=throttled')
vm.add_blockdev('file,filename=%s,node-name=mid-file' % (mid_path))
vm.add_blockdev('qcow2,file=mid-file,node-name=mid,backing=throttled')
vm.add_drive_raw('if=none,id=overlay,driver=qcow2,file=%s,backing=mid' % (disk_path))
vm.launch()
iotests.log("=== Start background read requests ===")
iotests.log("")
def start_requests():
vm.hmp_qemu_io('overlay', 'aio_read 0 4k')
vm.hmp_qemu_io('overlay', 'aio_read 0 4k')
start_requests()
iotests.log("=== Run a commit job ===")
iotests.log("")
result = vm.qmp_log('block-commit', job_id='job0', auto_finalize=False,
device='overlay', top_node='mid')
vm.run_job('job0', auto_finalize=False, pre_finalize=start_requests,
auto_dismiss=True)
vm.shutdown()

View File

@ -0,0 +1,16 @@
=== Create backing chain and start VM ===
Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
=== Start background read requests ===
=== Run a commit job ===
{"execute": "block-commit", "arguments": {"auto-finalize": false, "device": "overlay", "job-id": "job0", "top-node": "mid"}}
{"return": {}}
{"execute": "job-finalize", "arguments": {"id": "job0"}}
{"return": {}}
{"data": {"id": "job0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}

View File

@ -265,3 +265,4 @@
252 rw auto backing quick
253 rw auto quick
254 rw auto backing quick
255 rw auto quick

View File

@ -126,6 +126,11 @@ def qemu_img_pipe(*args):
sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
return subp.communicate()[0]
def qemu_img_log(*args):
result = qemu_img_pipe(*args)
log(result, filters=[filter_testfiles])
return result
def img_info_log(filename, filter_path=None, imgopts=False, extra_args=[]):
args = [ 'info' ]
if imgopts:
@ -533,7 +538,8 @@ class VM(qtest.QEMUQtestMachine):
return result
# Returns None on success, and an error string on failure
def run_job(self, job, auto_finalize=True, auto_dismiss=False):
def run_job(self, job, auto_finalize=True, auto_dismiss=False,
pre_finalize=None):
error = None
while True:
for ev in self.get_qmp_events_filtered(wait=True):
@ -546,6 +552,8 @@ class VM(qtest.QEMUQtestMachine):
error = j['error']
log('Job failed: %s' % (j['error']))
elif status == 'pending' and not auto_finalize:
if pre_finalize:
pre_finalize()
self.qmp_log('job-finalize', id=job)
elif status == 'concluded' and not auto_dismiss:
self.qmp_log('job-dismiss', id=job)