[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-block] [PULL 25/42] blockjob: Wake up BDS when job becomes idle
From: |
Max Reitz |
Subject: |
[Qemu-block] [PULL 25/42] blockjob: Wake up BDS when job becomes idle |
Date: |
Tue, 25 Sep 2018 17:15:24 +0200 |
From: Kevin Wolf <address@hidden>
In the context of draining a BDS, the .drained_poll callback of block
jobs is called. If this returns true (i.e. there is still some activity
pending), the drain operation may call aio_poll() with blocking=true to
wait for completion.
As soon as the pending activity is completed and the job finally arrives
in a quiescent state (i.e. its coroutine either yields with busy=false
or terminates), the block job must notify the aio_poll() loop to wake
up, otherwise we get a deadlock if both are running in different
threads.
Signed-off-by: Kevin Wolf <address@hidden>
Reviewed-by: Fam Zheng <address@hidden>
Reviewed-by: Max Reitz <address@hidden>
---
include/block/blockjob.h | 13 +++++++++++++
include/qemu/job.h | 3 +++
blockjob.c | 18 ++++++++++++++++++
job.c | 7 +++++++
4 files changed, 41 insertions(+)
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
index 32c00b7dc0..2290bbb824 100644
--- a/include/block/blockjob.h
+++ b/include/block/blockjob.h
@@ -70,6 +70,9 @@ typedef struct BlockJob {
/** Called when the job transitions to READY */
Notifier ready_notifier;
+ /** Called when the job coroutine yields or terminates */
+ Notifier idle_notifier;
+
/** BlockDriverStates that are involved in this block job */
GSList *nodes;
} BlockJob;
@@ -118,6 +121,16 @@ int block_job_add_bdrv(BlockJob *job, const char *name,
BlockDriverState *bs,
*/
void block_job_remove_all_bdrv(BlockJob *job);
+/**
+ * block_job_wakeup_all_bdrv:
+ * @job: The block job
+ *
+ * Calls bdrv_wakeup() for all BlockDriverStates that have been added to the
+ * job. This function is to be called whenever child_job_drained_poll() would
+ * go from true to false to notify waiting drain requests.
+ */
+void block_job_wakeup_all_bdrv(BlockJob *job);
+
/**
* block_job_set_speed:
* @job: The job to set the speed for.
diff --git a/include/qemu/job.h b/include/qemu/job.h
index 5cb0681834..b4a784d3cc 100644
--- a/include/qemu/job.h
+++ b/include/qemu/job.h
@@ -156,6 +156,9 @@ typedef struct Job {
/** Notifiers called when the job transitions to READY */
NotifierList on_ready;
+ /** Notifiers called when the job coroutine yields or terminates */
+ NotifierList on_idle;
+
/** Element of the list of jobs */
QLIST_ENTRY(Job) job_list;
diff --git a/blockjob.c b/blockjob.c
index bf7ef48f98..58dbd87a51 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -221,6 +221,22 @@ int block_job_add_bdrv(BlockJob *job, const char *name,
BlockDriverState *bs,
return 0;
}
+void block_job_wakeup_all_bdrv(BlockJob *job)
+{
+ GSList *l;
+
+ for (l = job->nodes; l; l = l->next) {
+ BdrvChild *c = l->data;
+ bdrv_wakeup(c->bs);
+ }
+}
+
+static void block_job_on_idle(Notifier *n, void *opaque)
+{
+ BlockJob *job = opaque;
+ block_job_wakeup_all_bdrv(job);
+}
+
bool block_job_is_internal(BlockJob *job)
{
return (job->job.id == NULL);
@@ -416,6 +432,7 @@ void *block_job_create(const char *job_id, const
BlockJobDriver *driver,
job->finalize_completed_notifier.notify = block_job_event_completed;
job->pending_notifier.notify = block_job_event_pending;
job->ready_notifier.notify = block_job_event_ready;
+ job->idle_notifier.notify = block_job_on_idle;
notifier_list_add(&job->job.on_finalize_cancelled,
&job->finalize_cancelled_notifier);
@@ -423,6 +440,7 @@ void *block_job_create(const char *job_id, const
BlockJobDriver *driver,
&job->finalize_completed_notifier);
notifier_list_add(&job->job.on_pending, &job->pending_notifier);
notifier_list_add(&job->job.on_ready, &job->ready_notifier);
+ notifier_list_add(&job->job.on_idle, &job->idle_notifier);
error_setg(&job->blocker, "block device is in use by block job: %s",
job_type_str(&job->job));
diff --git a/job.c b/job.c
index d17b1c82da..4812962fb5 100644
--- a/job.c
+++ b/job.c
@@ -402,6 +402,11 @@ static void job_event_ready(Job *job)
notifier_list_notify(&job->on_ready, job);
}
+static void job_event_idle(Job *job)
+{
+ notifier_list_notify(&job->on_idle, job);
+}
+
void job_enter_cond(Job *job, bool(*fn)(Job *job))
{
if (!job_started(job)) {
@@ -447,6 +452,7 @@ static void coroutine_fn job_do_yield(Job *job, uint64_t ns)
timer_mod(&job->sleep_timer, ns);
}
job->busy = false;
+ job_event_idle(job);
job_unlock();
qemu_coroutine_yield();
@@ -865,6 +871,7 @@ static void coroutine_fn job_co_entry(void *opaque)
assert(job && job->driver && job->driver->run);
job_pause_point(job);
job->ret = job->driver->run(job, &job->err);
+ job_event_idle(job);
job->deferred_to_main_loop = true;
aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job);
}
--
2.17.1
- [Qemu-block] [PULL 16/42] blockdev: document transactional shortcomings, (continued)
- [Qemu-block] [PULL 16/42] blockdev: document transactional shortcomings, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 13/42] qapi/block-mirror: expose new job properties, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 15/42] block/backup: qapi documentation fixup, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 14/42] qapi/block-stream: expose new job properties, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 19/42] block/linux-aio: acquire AioContext before qemu_laio_process_completions, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 17/42] commit: Add top-node/base-node options, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 18/42] qemu-iotests: Test commit with top-node/base-node, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 20/42] block: Fix use after free error in bdrv_open_inherit(), Max Reitz, 2018/09/25
- [Qemu-block] [PULL 21/42] qemu-iotests: Test snapshot=on with nonexistent TMPDIR, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 22/42] util/async: use qemu_aio_coroutine_enter in co_schedule_bh_cb, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 25/42] blockjob: Wake up BDS when job becomes idle,
Max Reitz <=
- [Qemu-block] [PULL 24/42] job: Fix missing locking due to mismerge, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 23/42] job: Fix nested aio_poll() hanging in job_txn_apply, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 26/42] aio-wait: Increase num_waiters even in home thread, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 27/42] test-bdrv-drain: Drain with block jobs in an I/O thread, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 28/42] test-blockjob: Acquire AioContext around job_cancel_sync(), Max Reitz, 2018/09/25
- [Qemu-block] [PULL 29/42] job: Use AIO_WAIT_WHILE() in job_finish_sync(), Max Reitz, 2018/09/25
- [Qemu-block] [PULL 30/42] test-bdrv-drain: Test AIO_WAIT_WHILE() in completion callback, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 31/42] block: Add missing locking in bdrv_co_drain_bh_cb(), Max Reitz, 2018/09/25
- [Qemu-block] [PULL 32/42] block-backend: Add .drained_poll callback, Max Reitz, 2018/09/25
- [Qemu-block] [PULL 34/42] block-backend: Decrease in_flight only after callback, Max Reitz, 2018/09/25