blockjob: add block_job_defer_to_main_loop()
Block jobs will run in the BlockDriverState's AioContext, which may not always be the QEMU main loop. There are some block layer APIs that are either not thread-safe or risk lock ordering problems. This includes bdrv_unref(), bdrv_close(), and anything that calls bdrv_drain_all(). The block_job_defer_to_main_loop() API allows a block job to schedule a function to run in the main loop with the BlockDriverState AioContext held. This function will be used to perform cleanup and backing chain manipulations in block jobs. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-id: 1413889440-32577-6-git-send-email-stefanha@redhat.com
This commit is contained in:
parent
723c5d93c5
commit
dec7d421f8
45
blockjob.c
45
blockjob.c
|
@ -342,3 +342,48 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
|
||||||
}
|
}
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BlockJob *job;
|
||||||
|
QEMUBH *bh;
|
||||||
|
AioContext *aio_context;
|
||||||
|
BlockJobDeferToMainLoopFn *fn;
|
||||||
|
void *opaque;
|
||||||
|
} BlockJobDeferToMainLoopData;
|
||||||
|
|
||||||
|
static void block_job_defer_to_main_loop_bh(void *opaque)
|
||||||
|
{
|
||||||
|
BlockJobDeferToMainLoopData *data = opaque;
|
||||||
|
AioContext *aio_context;
|
||||||
|
|
||||||
|
qemu_bh_delete(data->bh);
|
||||||
|
|
||||||
|
/* Prevent race with block_job_defer_to_main_loop() */
|
||||||
|
aio_context_acquire(data->aio_context);
|
||||||
|
|
||||||
|
/* Fetch BDS AioContext again, in case it has changed */
|
||||||
|
aio_context = bdrv_get_aio_context(data->job->bs);
|
||||||
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
|
data->fn(data->job, data->opaque);
|
||||||
|
|
||||||
|
aio_context_release(aio_context);
|
||||||
|
|
||||||
|
aio_context_release(data->aio_context);
|
||||||
|
|
||||||
|
g_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void block_job_defer_to_main_loop(BlockJob *job,
|
||||||
|
BlockJobDeferToMainLoopFn *fn,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data));
|
||||||
|
data->job = job;
|
||||||
|
data->bh = qemu_bh_new(block_job_defer_to_main_loop_bh, data);
|
||||||
|
data->aio_context = bdrv_get_aio_context(job->bs);
|
||||||
|
data->fn = fn;
|
||||||
|
data->opaque = opaque;
|
||||||
|
|
||||||
|
qemu_bh_schedule(data->bh);
|
||||||
|
}
|
||||||
|
|
|
@ -315,4 +315,23 @@ void block_job_iostatus_reset(BlockJob *job);
|
||||||
BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
|
BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
|
||||||
BlockdevOnError on_err,
|
BlockdevOnError on_err,
|
||||||
int is_read, int error);
|
int is_read, int error);
|
||||||
|
|
||||||
|
typedef void BlockJobDeferToMainLoopFn(BlockJob *job, void *opaque);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* block_job_defer_to_main_loop:
|
||||||
|
* @job: The job
|
||||||
|
* @fn: The function to run in the main loop
|
||||||
|
* @opaque: The opaque value that is passed to @fn
|
||||||
|
*
|
||||||
|
* Execute a given function in the main loop with the BlockDriverState
|
||||||
|
* AioContext acquired. Block jobs must call bdrv_unref(), bdrv_close(), and
|
||||||
|
* anything that uses bdrv_drain_all() in the main loop.
|
||||||
|
*
|
||||||
|
* The @job AioContext is held while @fn executes.
|
||||||
|
*/
|
||||||
|
void block_job_defer_to_main_loop(BlockJob *job,
|
||||||
|
BlockJobDeferToMainLoopFn *fn,
|
||||||
|
void *opaque);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue