From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, peter.maydell@linaro.org, qemu-devel@nongnu.org
Subject: [Qemu-devel] [PULL 03/13] tests: Add job commit by drained_end test
Date: Fri, 19 Jul 2019 15:43:35 +0200 [thread overview]
Message-ID: <20190719134345.23526-4-kwolf@redhat.com> (raw)
In-Reply-To: <20190719134345.23526-1-kwolf@redhat.com>
From: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
tests/test-bdrv-drain.c | 119 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 119 insertions(+)
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
index 12e2ecf517..3503ce3b69 100644
--- a/tests/test-bdrv-drain.c
+++ b/tests/test-bdrv-drain.c
@@ -1527,6 +1527,122 @@ static void test_set_aio_context(void)
iothread_join(b);
}
+
+typedef struct TestDropBackingBlockJob {
+ BlockJob common;
+ bool should_complete;
+ bool *did_complete;
+} TestDropBackingBlockJob;
+
+static int coroutine_fn test_drop_backing_job_run(Job *job, Error **errp)
+{
+ TestDropBackingBlockJob *s =
+ container_of(job, TestDropBackingBlockJob, common.job);
+
+ while (!s->should_complete) {
+ job_sleep_ns(job, 0);
+ }
+
+ return 0;
+}
+
+static void test_drop_backing_job_commit(Job *job)
+{
+ TestDropBackingBlockJob *s =
+ container_of(job, TestDropBackingBlockJob, common.job);
+
+ bdrv_set_backing_hd(blk_bs(s->common.blk), NULL, &error_abort);
+
+ *s->did_complete = true;
+}
+
+static const BlockJobDriver test_drop_backing_job_driver = {
+ .job_driver = {
+ .instance_size = sizeof(TestDropBackingBlockJob),
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .drain = block_job_drain,
+ .run = test_drop_backing_job_run,
+ .commit = test_drop_backing_job_commit,
+ }
+};
+
+/**
+ * Creates a child node with three parent nodes on it, and then runs a
+ * block job on the final one, parent-node-2.
+ *
+ * (TODO: parent-node-0 currently serves no purpose, but will as of a
+ * follow-up patch.)
+ *
+ * The job is then asked to complete before a section where the child
+ * is drained.
+ *
+ * Ending this section will undrain the child's parents, first
+ * parent-node-2, then parent-node-1, then parent-node-0 -- the parent
+ * list is in reverse order of how they were added. Ending the drain
+ * on parent-node-2 will resume the job, thus completing it and
+ * scheduling job_exit().
+ *
+ * Ending the drain on parent-node-1 will poll the AioContext, which
+ * lets job_exit() and thus test_drop_backing_job_commit() run. That
+ * function removes the child as parent-node-2's backing file.
+ *
+ * In old (and buggy) implementations, there are two problems with
+ * that:
+ * (A) bdrv_drain_invoke() polls for every node that leaves the
+ * drained section. This means that job_exit() is scheduled
+ * before the child has left the drained section. Its
+ * quiesce_counter is therefore still 1 when it is removed from
+ * parent-node-2.
+ *
+ * (B) bdrv_replace_child_noperm() calls drained_end() on the old
+ * child's parents as many times as the child is quiesced. This
+ * means it will call drained_end() on parent-node-2 once.
+ * Because parent-node-2 is no longer quiesced at this point, this
+ * will fail.
+ *
+ * bdrv_replace_child_noperm() therefore must call drained_end() on
+ * the parent only if it really is still drained because the child is
+ * drained.
+ */
+static void test_blockjob_commit_by_drained_end(void)
+{
+ BlockDriverState *bs_child, *bs_parents[3];
+ TestDropBackingBlockJob *job;
+ bool job_has_completed = false;
+ int i;
+
+ bs_child = bdrv_new_open_driver(&bdrv_test, "child-node", BDRV_O_RDWR,
+ &error_abort);
+
+ for (i = 0; i < 3; i++) {
+ char name[32];
+ snprintf(name, sizeof(name), "parent-node-%i", i);
+ bs_parents[i] = bdrv_new_open_driver(&bdrv_test, name, BDRV_O_RDWR,
+ &error_abort);
+ bdrv_set_backing_hd(bs_parents[i], bs_child, &error_abort);
+ }
+
+ job = block_job_create("job", &test_drop_backing_job_driver, NULL,
+ bs_parents[2], 0, BLK_PERM_ALL, 0, 0, NULL, NULL,
+ &error_abort);
+
+ job->did_complete = &job_has_completed;
+
+ job_start(&job->common.job);
+
+ job->should_complete = true;
+ bdrv_drained_begin(bs_child);
+ g_assert(!job_has_completed);
+ bdrv_drained_end(bs_child);
+ g_assert(job_has_completed);
+
+ bdrv_unref(bs_parents[0]);
+ bdrv_unref(bs_parents[1]);
+ bdrv_unref(bs_parents[2]);
+ bdrv_unref(bs_child);
+}
+
int main(int argc, char **argv)
{
int ret;
@@ -1610,6 +1726,9 @@ int main(int argc, char **argv)
g_test_add_func("/bdrv-drain/set_aio_context", test_set_aio_context);
+ g_test_add_func("/bdrv-drain/blockjob/commit_by_drained_end",
+ test_blockjob_commit_by_drained_end);
+
ret = g_test_run();
qemu_event_destroy(&done_event);
return ret;
--
2.20.1
next prev parent reply other threads:[~2019-07-19 13:45 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-07-19 13:43 [Qemu-devel] [PULL 00/13] Block layer patches Kevin Wolf
2019-07-19 13:43 ` [Qemu-devel] [PULL 01/13] iotests: Set read-zeroes on in null block driver for Valgrind Kevin Wolf
2019-07-24 7:18 ` Christian Borntraeger
2019-07-24 7:30 ` Andrey Shinkevich
2019-07-24 7:33 ` Christian Borntraeger
2019-07-24 7:37 ` Andrey Shinkevich
2019-07-24 7:38 ` Kevin Wolf
2019-07-24 7:57 ` Andrey Shinkevich
2019-07-24 8:05 ` Kevin Wolf
2019-07-24 8:23 ` Andrey Shinkevich
2019-07-19 13:43 ` [Qemu-devel] [PULL 02/13] block: Introduce BdrvChild.parent_quiesce_counter Kevin Wolf
2019-07-19 13:43 ` Kevin Wolf [this message]
2019-07-19 13:43 ` [Qemu-devel] [PULL 04/13] block: Add @drained_end_counter Kevin Wolf
2019-07-19 13:43 ` [Qemu-devel] [PULL 05/13] block: Make bdrv_parent_drained_[^_]*() static Kevin Wolf
2019-07-19 13:43 ` [Qemu-devel] [PULL 06/13] tests: Lock AioContexts in test-block-iothread Kevin Wolf
2019-07-19 13:43 ` [Qemu-devel] [PULL 07/13] block: Do not poll in bdrv_do_drained_end() Kevin Wolf
2019-07-19 13:43 ` [Qemu-devel] [PULL 08/13] tests: Extend commit by drained_end test Kevin Wolf
2019-07-19 13:43 ` [Qemu-devel] [PULL 09/13] block: Loop unsafely in bdrv*drained_end() Kevin Wolf
2019-07-19 13:43 ` [Qemu-devel] [PULL 10/13] iotests: Add @has_quit to vm.shutdown() Kevin Wolf
2019-07-19 13:43 ` [Qemu-devel] [PULL 11/13] iotests: Test commit with a filter on the chain Kevin Wolf
2019-07-19 13:43 ` [Qemu-devel] [PULL 12/13] vl: Drain before (block) job cancel when quitting Kevin Wolf
2019-07-19 13:43 ` [Qemu-devel] [PULL 13/13] iotests: Test quitting with job on throttled node Kevin Wolf
2019-07-22 9:11 ` [Qemu-devel] [PULL 00/13] Block layer patches Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190719134345.23526-4-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.