aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-05-20 17:22:05 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-05-20 17:22:05 +0100
commit2259637b95bef3116cc262459271de08e038cc66 (patch)
treeb374012bc39ae4eac95b956c2303d0ab48260ed1 /tests
parent6d8e75d41c58892ccc5d4ad61c4da476684c1c83 (diff)
parentc423a6af592cf36b4f149c54e2966dd0016b7e96 (diff)
downloadqemu-2259637b95bef3116cc262459271de08e038cc66.zip
qemu-2259637b95bef3116cc262459271de08e038cc66.tar.gz
qemu-2259637b95bef3116cc262459271de08e038cc66.tar.bz2
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches: - block: AioContext management, part 1 - qmp: forbid qmp_cont in RUN_STATE_FINISH_MIGRATE - nvme: fix copy direction in DMA reads going to CMB - file-posix: Fix block status for unaligned raw images with O_DIRECT - file-posix: Fix xfs_write_zeroes() after EOF - Documentation and iotests improvements # gpg: Signature made Mon 20 May 2019 16:12:38 BST # gpg: using RSA key 7F09B272C88F2FD6 # 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: (24 commits) iotests: Make 245 faster and more reliable iotests.py: Fix VM.run_job iotests.py: Let assert_qmp() accept an array block: Improve "Block node is read-only" message qemu-img.texi: Describe human-readable info output qemu-img.texi: Be specific about JSON object types iotests: Test unaligned raw images with O_DIRECT block/file-posix: Unaligned O_DIRECT block-status test-block-iothread: Test AioContext propagation for block jobs blockjob: Remove AioContext notifiers blockjob: Propagate AioContext change to all job nodes block: Add blk_set_allow_aio_context_change() block: Implement .(can_)set_aio_ctx for BlockBackend test-block-iothread: Test AioContext propagation through the tree block: Propagate AioContext change to parents block: Move recursion to bdrv_set_aio_context() block: Make bdrv_attach/detach_aio_context() static block: Add bdrv_try_set_aio_context() nvme: fix copy direction in DMA reads going to CMB iotest: fix 169: do not run qmp_cont in RUN_STATE_FINISH_MIGRATE ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rwxr-xr-xtests/qemu-iotests/1697
-rwxr-xr-xtests/qemu-iotests/2214
-rw-r--r--tests/qemu-iotests/24522
-rw-r--r--tests/qemu-iotests/245.out12
-rwxr-xr-xtests/qemu-iotests/25384
-rw-r--r--tests/qemu-iotests/253.out14
-rw-r--r--tests/qemu-iotests/group1
-rw-r--r--tests/qemu-iotests/iotests.py20
-rw-r--r--tests/test-block-iothread.c202
9 files changed, 354 insertions, 12 deletions
diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/169
index 527aebd..7e06cc1 100755
--- a/tests/qemu-iotests/169
+++ b/tests/qemu-iotests/169
@@ -102,12 +102,17 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
event = self.vm_a.event_wait('MIGRATION')
if event['data']['status'] == 'completed':
break
+ while True:
+ result = self.vm_a.qmp('query-status')
+ if (result['return']['status'] == 'postmigrate'):
+ break
# test that bitmap is still here
removed = (not migrate_bitmaps) and persistent
self.check_bitmap(self.vm_a, False if removed else sha256)
- self.vm_a.qmp('cont')
+ result = self.vm_a.qmp('cont')
+ self.assert_qmp(result, 'return', {})
# test that bitmap is still here after invalidation
self.check_bitmap(self.vm_a, sha256)
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
index 25dd47b..0e9096f 100755
--- a/tests/qemu-iotests/221
+++ b/tests/qemu-iotests/221
@@ -1,6 +1,7 @@
#!/usr/bin/env bash
#
# Test qemu-img vs. unaligned images
+# (See also 253, which is the O_DIRECT version)
#
# Copyright (C) 2018-2019 Red Hat, Inc.
#
@@ -37,6 +38,9 @@ _supported_fmt raw
_supported_proto file
_supported_os Linux
+_default_cache_mode writeback
+_supported_cache_modes writeback writethrough unsafe
+
echo
echo "=== Check mapping of unaligned raw image ==="
echo
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
index a04c623..349b94a 100644
--- a/tests/qemu-iotests/245
+++ b/tests/qemu-iotests/245
@@ -862,7 +862,8 @@ class TestBlockdevReopen(iotests.QMPTestCase):
# hd2 <- hd0
result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
- device = 'hd0', base_node = 'hd2', speed = 512 * 1024)
+ device = 'hd0', base_node = 'hd2',
+ auto_finalize = False)
self.assert_qmp(result, 'return', {})
# We can't remove hd2 while the stream job is ongoing
@@ -873,7 +874,7 @@ class TestBlockdevReopen(iotests.QMPTestCase):
opts['backing'] = None
self.reopen(opts, {}, "Cannot change 'backing' link from 'hd0' to 'hd1'")
- self.wait_until_completed(drive = 'stream0')
+ self.vm.run_job('stream0', auto_finalize = False, auto_dismiss = True)
# Reopen the chain during a block-stream job (from hd2 to hd1)
def test_block_stream_4(self):
@@ -886,12 +887,16 @@ class TestBlockdevReopen(iotests.QMPTestCase):
# hd1 <- hd0
result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
- device = 'hd1', speed = 512 * 1024)
+ device = 'hd1', auto_finalize = False)
self.assert_qmp(result, 'return', {})
# We can't reopen with the original options because that would
# make hd1 read-only and block-stream requires it to be read-write
- self.reopen(opts, {}, "Can't set node 'hd1' to r/o with copy-on-read enabled")
+ # (Which error message appears depends on whether the stream job is
+ # already done with copying at this point.)
+ self.reopen(opts, {},
+ ["Can't set node 'hd1' to r/o with copy-on-read enabled",
+ "Cannot make block node read-only, there is a writer on it"])
# We can't remove hd2 while the stream job is ongoing
opts['backing']['backing'] = None
@@ -901,7 +906,7 @@ class TestBlockdevReopen(iotests.QMPTestCase):
opts['backing'] = None
self.reopen(opts)
- self.wait_until_completed(drive = 'stream0')
+ self.vm.run_job('stream0', auto_finalize = False, auto_dismiss = True)
# Reopen the chain during a block-commit job (from hd0 to hd2)
def test_block_commit_1(self):
@@ -913,7 +918,7 @@ class TestBlockdevReopen(iotests.QMPTestCase):
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
- device = 'hd0', speed = 1024 * 1024)
+ device = 'hd0')
self.assert_qmp(result, 'return', {})
# We can't remove hd2 while the commit job is ongoing
@@ -944,7 +949,8 @@ class TestBlockdevReopen(iotests.QMPTestCase):
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
- device = 'hd0', top_node = 'hd1', speed = 1024 * 1024)
+ device = 'hd0', top_node = 'hd1',
+ auto_finalize = False)
self.assert_qmp(result, 'return', {})
# We can't remove hd2 while the commit job is ongoing
@@ -956,7 +962,7 @@ class TestBlockdevReopen(iotests.QMPTestCase):
self.reopen(opts, {}, "Cannot change backing link if 'hd0' has an implicit backing file")
# hd2 <- hd0
- self.wait_until_completed(drive = 'commit0')
+ self.vm.run_job('commit0', auto_finalize = False, auto_dismiss = True)
self.assert_qmp(self.get_node('hd0'), 'ro', False)
self.assertEqual(self.get_node('hd1'), None)
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
index 71009c2..a19de52 100644
--- a/tests/qemu-iotests/245.out
+++ b/tests/qemu-iotests/245.out
@@ -3,3 +3,15 @@
Ran 18 tests
OK
+{"execute": "job-finalize", "arguments": {"id": "commit0"}}
+{"return": {}}
+{"data": {"id": "commit0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "commit0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"execute": "job-finalize", "arguments": {"id": "stream0"}}
+{"return": {}}
+{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"execute": "job-finalize", "arguments": {"id": "stream0"}}
+{"return": {}}
+{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
diff --git a/tests/qemu-iotests/253 b/tests/qemu-iotests/253
new file mode 100755
index 0000000..d88d5af
--- /dev/null
+++ b/tests/qemu-iotests/253
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+#
+# Test qemu-img vs. unaligned images; O_DIRECT version
+# (Originates from 221)
+#
+# Copyright (C) 2019 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_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt raw
+_supported_proto file
+_supported_os Linux
+
+_default_cache_mode none
+_supported_cache_modes none directsync
+
+echo
+echo "=== Check mapping of unaligned raw image ==="
+echo
+
+# We do not know how large a physical sector is, but it is certainly
+# going to be a factor of 1 MB
+size=$((1 * 1024 * 1024 - 1))
+
+# qemu-img create rounds size up to BDRV_SECTOR_SIZE
+_make_test_img $size
+$QEMU_IMG map --output=json --image-opts \
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
+ | _filter_qemu_img_map
+
+# so we resize it and check again
+truncate --size=$size "$TEST_IMG"
+$QEMU_IMG map --output=json --image-opts \
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
+ | _filter_qemu_img_map
+
+# qemu-io with O_DIRECT always writes whole physical sectors. Again,
+# we do not know how large a physical sector is, so we just start
+# writing from a 64 kB boundary, which should always be aligned.
+offset=$((1 * 1024 * 1024 - 64 * 1024))
+$QEMU_IO -c "w $offset $((size - offset))" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IMG map --output=json --image-opts \
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
+ | _filter_qemu_img_map
+
+# Resize it and check again -- contrary to 221, we may not get partial
+# sectors here, so there should be only two areas (one zero, one
+# data).
+truncate --size=$size "$TEST_IMG"
+$QEMU_IMG map --output=json --image-opts \
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
+ | _filter_qemu_img_map
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out
new file mode 100644
index 0000000..607c0ba
--- /dev/null
+++ b/tests/qemu-iotests/253.out
@@ -0,0 +1,14 @@
+QA output created by 253
+
+=== Check mapping of unaligned raw image ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+wrote 65535/65535 bytes at offset 983040
+63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
+[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 00e474a..52b7c16 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -250,3 +250,4 @@
248 rw auto quick
249 rw auto quick
252 rw auto backing quick
+253 rw auto quick
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index f811f69..7bde380 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -552,7 +552,7 @@ class VM(qtest.QEMUQtestMachine):
elif status == 'null':
return error
else:
- iotests.log(ev)
+ log(ev)
def node_info(self, node_name):
nodes = self.qmp('query-named-block-nodes')
@@ -596,9 +596,23 @@ class QMPTestCase(unittest.TestCase):
self.fail('path "%s" has value "%s"' % (path, str(result)))
def assert_qmp(self, d, path, value):
- '''Assert that the value for a specific path in a QMP dict matches'''
+ '''Assert that the value for a specific path in a QMP dict
+ matches. When given a list of values, assert that any of
+ them matches.'''
+
result = self.dictpath(d, path)
- self.assertEqual(result, value, 'values not equal "%s" and "%s"' % (str(result), str(value)))
+
+ # [] makes no sense as a list of valid values, so treat it as
+ # an actual single value.
+ if isinstance(value, list) and value != []:
+ for v in value:
+ if result == v:
+ return
+ self.fail('no match for "%s" in %s' % (str(result), str(value)))
+ else:
+ self.assertEqual(result, value,
+ 'values not equal "%s" and "%s"'
+ % (str(result), str(value)))
def assert_no_active_block_jobs(self):
result = self.vm.qmp('query-block-jobs')
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
index 036ed9a..59f6928 100644
--- a/tests/test-block-iothread.c
+++ b/tests/test-block-iothread.c
@@ -27,6 +27,7 @@
#include "block/blockjob_int.h"
#include "sysemu/block-backend.h"
#include "qapi/error.h"
+#include "qapi/qmp/qdict.h"
#include "iothread.h"
static int coroutine_fn bdrv_test_co_prwv(BlockDriverState *bs,
@@ -459,6 +460,204 @@ static void test_attach_blockjob(void)
blk_unref(blk);
}
+/*
+ * Test that changing the AioContext for one node in a tree (here through blk)
+ * changes all other nodes as well:
+ *
+ * blk
+ * |
+ * | bs_verify [blkverify]
+ * | / \
+ * | / \
+ * bs_a [bdrv_test] bs_b [bdrv_test]
+ *
+ */
+static void test_propagate_basic(void)
+{
+ IOThread *iothread = iothread_new();
+ AioContext *ctx = iothread_get_aio_context(iothread);
+ BlockBackend *blk;
+ BlockDriverState *bs_a, *bs_b, *bs_verify;
+ QDict *options;
+
+ /* Create bs_a and its BlockBackend */
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
+ bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
+ blk_insert_bs(blk, bs_a, &error_abort);
+
+ /* Create bs_b */
+ bs_b = bdrv_new_open_driver(&bdrv_test, "bs_b", BDRV_O_RDWR, &error_abort);
+
+ /* Create blkverify filter that references both bs_a and bs_b */
+ options = qdict_new();
+ qdict_put_str(options, "driver", "blkverify");
+ qdict_put_str(options, "test", "bs_a");
+ qdict_put_str(options, "raw", "bs_b");
+
+ bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
+
+ /* Switch the AioContext */
+ blk_set_aio_context(blk, ctx);
+ g_assert(blk_get_aio_context(blk) == ctx);
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
+
+ /* Switch the AioContext back */
+ ctx = qemu_get_aio_context();
+ blk_set_aio_context(blk, ctx);
+ g_assert(blk_get_aio_context(blk) == ctx);
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
+
+ bdrv_unref(bs_verify);
+ bdrv_unref(bs_b);
+ bdrv_unref(bs_a);
+ blk_unref(blk);
+}
+
+/*
+ * Test that diamonds in the graph don't lead to endless recursion:
+ *
+ * blk
+ * |
+ * bs_verify [blkverify]
+ * / \
+ * / \
+ * bs_b [raw] bs_c[raw]
+ * \ /
+ * \ /
+ * bs_a [bdrv_test]
+ */
+static void test_propagate_diamond(void)
+{
+ IOThread *iothread = iothread_new();
+ AioContext *ctx = iothread_get_aio_context(iothread);
+ BlockBackend *blk;
+ BlockDriverState *bs_a, *bs_b, *bs_c, *bs_verify;
+ QDict *options;
+
+ /* Create bs_a */
+ bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
+
+ /* Create bs_b and bc_c */
+ options = qdict_new();
+ qdict_put_str(options, "driver", "raw");
+ qdict_put_str(options, "file", "bs_a");
+ qdict_put_str(options, "node-name", "bs_b");
+ bs_b = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
+
+ options = qdict_new();
+ qdict_put_str(options, "driver", "raw");
+ qdict_put_str(options, "file", "bs_a");
+ qdict_put_str(options, "node-name", "bs_c");
+ bs_c = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
+
+ /* Create blkverify filter that references both bs_b and bs_c */
+ options = qdict_new();
+ qdict_put_str(options, "driver", "blkverify");
+ qdict_put_str(options, "test", "bs_b");
+ qdict_put_str(options, "raw", "bs_c");
+
+ bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
+ blk_insert_bs(blk, bs_verify, &error_abort);
+
+ /* Switch the AioContext */
+ blk_set_aio_context(blk, ctx);
+ g_assert(blk_get_aio_context(blk) == ctx);
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
+ g_assert(bdrv_get_aio_context(bs_c) == ctx);
+
+ /* Switch the AioContext back */
+ ctx = qemu_get_aio_context();
+ blk_set_aio_context(blk, ctx);
+ g_assert(blk_get_aio_context(blk) == ctx);
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
+ g_assert(bdrv_get_aio_context(bs_c) == ctx);
+
+ blk_unref(blk);
+ bdrv_unref(bs_verify);
+ bdrv_unref(bs_c);
+ bdrv_unref(bs_b);
+ bdrv_unref(bs_a);
+}
+
+static void test_propagate_mirror(void)
+{
+ IOThread *iothread = iothread_new();
+ AioContext *ctx = iothread_get_aio_context(iothread);
+ AioContext *main_ctx = qemu_get_aio_context();
+ BlockDriverState *src, *target;
+ BlockBackend *blk;
+ Job *job;
+ Error *local_err = NULL;
+
+ /* Create src and target*/
+ src = bdrv_new_open_driver(&bdrv_test, "src", BDRV_O_RDWR, &error_abort);
+ target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
+ &error_abort);
+
+ /* Start a mirror job */
+ mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0,
+ MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN,
+ BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
+ false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
+ &error_abort);
+ job = job_get("job0");
+
+ /* Change the AioContext of src */
+ bdrv_try_set_aio_context(src, ctx, &error_abort);
+ g_assert(bdrv_get_aio_context(src) == ctx);
+ g_assert(bdrv_get_aio_context(target) == ctx);
+ g_assert(job->aio_context == ctx);
+
+ /* Change the AioContext of target */
+ aio_context_acquire(ctx);
+ bdrv_try_set_aio_context(target, main_ctx, &error_abort);
+ aio_context_release(ctx);
+ g_assert(bdrv_get_aio_context(src) == main_ctx);
+ g_assert(bdrv_get_aio_context(target) == main_ctx);
+
+ /* With a BlockBackend on src, changing target must fail */
+ blk = blk_new(0, BLK_PERM_ALL);
+ blk_insert_bs(blk, src, &error_abort);
+
+ bdrv_try_set_aio_context(target, ctx, &local_err);
+ g_assert(local_err);
+ error_free(local_err);
+
+ g_assert(blk_get_aio_context(blk) == main_ctx);
+ g_assert(bdrv_get_aio_context(src) == main_ctx);
+ g_assert(bdrv_get_aio_context(target) == main_ctx);
+
+ /* ...unless we explicitly allow it */
+ aio_context_acquire(ctx);
+ blk_set_allow_aio_context_change(blk, true);
+ bdrv_try_set_aio_context(target, ctx, &error_abort);
+ aio_context_release(ctx);
+
+ g_assert(blk_get_aio_context(blk) == ctx);
+ g_assert(bdrv_get_aio_context(src) == ctx);
+ g_assert(bdrv_get_aio_context(target) == ctx);
+
+ job_cancel_sync_all();
+
+ aio_context_acquire(ctx);
+ blk_set_aio_context(blk, main_ctx);
+ bdrv_try_set_aio_context(target, main_ctx, &error_abort);
+ aio_context_release(ctx);
+
+ blk_unref(blk);
+ bdrv_unref(src);
+ bdrv_unref(target);
+}
+
int main(int argc, char **argv)
{
int i;
@@ -474,6 +673,9 @@ int main(int argc, char **argv)
}
g_test_add_func("/attach/blockjob", test_attach_blockjob);
+ g_test_add_func("/propagate/basic", test_propagate_basic);
+ g_test_add_func("/propagate/diamond", test_propagate_diamond);
+ g_test_add_func("/propagate/mirror", test_propagate_mirror);
return g_test_run();
}