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>
This commit is contained in:
Kevin Wolf 2018-08-17 14:53:05 +02:00
parent d1756c780b
commit 34dc97b9a0
4 changed files with 41 additions and 0 deletions

View file

@ -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.