aboutsummaryrefslogtreecommitdiff
path: root/blockjob.c
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2018-08-17 14:53:05 +0200
committerKevin Wolf <kwolf@redhat.com>2018-09-25 15:50:15 +0200
commit34dc97b9a0e592bc466bdb0bbfe45d77304a72b6 (patch)
tree3edd653e46d14ca5fb2e1551a4cb3427875e6865 /blockjob.c
parentd1756c780b7879fb64e41135feac781d84a1f995 (diff)
blockjob: Wake up BDS when job becomes idle
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 <kwolf@redhat.com> Reviewed-by: Fam Zheng <famz@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com>
Diffstat (limited to 'blockjob.c')
-rw-r--r--blockjob.c18
1 files changed, 18 insertions, 0 deletions
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));