block: Cancel jobs first in bdrv_close_all()
So far, bdrv_close_all() first removed all root BlockDriverStates of BlockBackends and monitor owned BDSes, and then assumed that the remaining BDSes must be related to jobs and cancelled these jobs. This order doesn't work that well any more when block jobs use BlockBackends internally because then they will lose their BDS before being cancelled. This patch changes bdrv_close_all() to first cancel all jobs and then remove all root BDSes from the remaining BBs. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Reviewed-by: Alberto Garcia <berto@igalia.com> Reviewed-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
a7112795c1
commit
a1a2af0756
23
block.c
23
block.c
@ -2209,8 +2209,7 @@ static void bdrv_close(BlockDriverState *bs)
|
|||||||
|
|
||||||
void bdrv_close_all(void)
|
void bdrv_close_all(void)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs;
|
block_job_cancel_sync_all();
|
||||||
AioContext *aio_context;
|
|
||||||
|
|
||||||
/* Drop references from requests still in flight, such as canceled block
|
/* Drop references from requests still in flight, such as canceled block
|
||||||
* jobs whose AIO context has not been polled yet */
|
* jobs whose AIO context has not been polled yet */
|
||||||
@ -2219,25 +2218,7 @@ void bdrv_close_all(void)
|
|||||||
blk_remove_all_bs();
|
blk_remove_all_bs();
|
||||||
blockdev_close_all_bdrv_states();
|
blockdev_close_all_bdrv_states();
|
||||||
|
|
||||||
/* Cancel all block jobs */
|
assert(QTAILQ_EMPTY(&all_bdrv_states));
|
||||||
while (!QTAILQ_EMPTY(&all_bdrv_states)) {
|
|
||||||
QTAILQ_FOREACH(bs, &all_bdrv_states, bs_list) {
|
|
||||||
aio_context = bdrv_get_aio_context(bs);
|
|
||||||
|
|
||||||
aio_context_acquire(aio_context);
|
|
||||||
if (bs->job) {
|
|
||||||
block_job_cancel_sync(bs->job);
|
|
||||||
aio_context_release(aio_context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
aio_context_release(aio_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All the remaining BlockDriverStates are referenced directly or
|
|
||||||
* indirectly from block jobs, so there needs to be at least one BDS
|
|
||||||
* directly used by a block job */
|
|
||||||
assert(bs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void change_parent_backing_link(BlockDriverState *from,
|
static void change_parent_backing_link(BlockDriverState *from,
|
||||||
|
13
blockjob.c
13
blockjob.c
@ -331,6 +331,19 @@ int block_job_cancel_sync(BlockJob *job)
|
|||||||
return block_job_finish_sync(job, &block_job_cancel_err, NULL);
|
return block_job_finish_sync(job, &block_job_cancel_err, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void block_job_cancel_sync_all(void)
|
||||||
|
{
|
||||||
|
BlockJob *job;
|
||||||
|
AioContext *aio_context;
|
||||||
|
|
||||||
|
while ((job = QLIST_FIRST(&block_jobs))) {
|
||||||
|
aio_context = bdrv_get_aio_context(job->bs);
|
||||||
|
aio_context_acquire(aio_context);
|
||||||
|
block_job_cancel_sync(job);
|
||||||
|
aio_context_release(aio_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int block_job_complete_sync(BlockJob *job, Error **errp)
|
int block_job_complete_sync(BlockJob *job, Error **errp)
|
||||||
{
|
{
|
||||||
return block_job_finish_sync(job, &block_job_complete, errp);
|
return block_job_finish_sync(job, &block_job_complete, errp);
|
||||||
|
@ -370,6 +370,13 @@ bool block_job_is_paused(BlockJob *job);
|
|||||||
*/
|
*/
|
||||||
int block_job_cancel_sync(BlockJob *job);
|
int block_job_cancel_sync(BlockJob *job);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* block_job_cancel_sync_all:
|
||||||
|
*
|
||||||
|
* Synchronously cancels all jobs using block_job_cancel_sync().
|
||||||
|
*/
|
||||||
|
void block_job_cancel_sync_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* block_job_complete_sync:
|
* block_job_complete_sync:
|
||||||
* @job: The job to be completed.
|
* @job: The job to be completed.
|
||||||
|
Loading…
Reference in New Issue
Block a user