diff --git a/block.c b/block.c index 45cddd6773..736432f67e 100644 --- a/block.c +++ b/block.c @@ -2209,8 +2209,7 @@ static void bdrv_close(BlockDriverState *bs) void bdrv_close_all(void) { - BlockDriverState *bs; - AioContext *aio_context; + block_job_cancel_sync_all(); /* Drop references from requests still in flight, such as canceled block * jobs whose AIO context has not been polled yet */ @@ -2219,25 +2218,7 @@ void bdrv_close_all(void) blk_remove_all_bs(); blockdev_close_all_bdrv_states(); - /* Cancel all block jobs */ - 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); - } + assert(QTAILQ_EMPTY(&all_bdrv_states)); } static void change_parent_backing_link(BlockDriverState *from, diff --git a/blockjob.c b/blockjob.c index 0f1bc77b1d..e916b41030 100644 --- a/blockjob.c +++ b/blockjob.c @@ -331,6 +331,19 @@ int block_job_cancel_sync(BlockJob *job) 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) { return block_job_finish_sync(job, &block_job_complete, errp); diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 30bb2c6fd6..4ac68314ae 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -370,6 +370,13 @@ bool block_job_is_paused(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: * @job: The job to be completed.