blockjob: Introduce block_job_complete_sync()
Implement block_job_complete_sync() by doing the exact same thing as block_job_cancel_sync() does, only with calling block_job_complete() instead of block_job_cancel(). Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 1414159063-25977-5-git-send-email-mreitz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
94054183da
commit
345f9e1b04
39
blockjob.c
39
blockjob.c
@ -153,7 +153,7 @@ void block_job_iostatus_reset(BlockJob *job)
|
||||
}
|
||||
}
|
||||
|
||||
struct BlockCancelData {
|
||||
struct BlockFinishData {
|
||||
BlockJob *job;
|
||||
BlockCompletionFunc *cb;
|
||||
void *opaque;
|
||||
@ -161,19 +161,22 @@ struct BlockCancelData {
|
||||
int ret;
|
||||
};
|
||||
|
||||
static void block_job_cancel_cb(void *opaque, int ret)
|
||||
static void block_job_finish_cb(void *opaque, int ret)
|
||||
{
|
||||
struct BlockCancelData *data = opaque;
|
||||
struct BlockFinishData *data = opaque;
|
||||
|
||||
data->cancelled = block_job_is_cancelled(data->job);
|
||||
data->ret = ret;
|
||||
data->cb(data->opaque, ret);
|
||||
}
|
||||
|
||||
int block_job_cancel_sync(BlockJob *job)
|
||||
static int block_job_finish_sync(BlockJob *job,
|
||||
void (*finish)(BlockJob *, Error **errp),
|
||||
Error **errp)
|
||||
{
|
||||
struct BlockCancelData data;
|
||||
struct BlockFinishData data;
|
||||
BlockDriverState *bs = job->bs;
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(bs->job == job);
|
||||
|
||||
@ -184,15 +187,37 @@ int block_job_cancel_sync(BlockJob *job)
|
||||
data.cb = job->cb;
|
||||
data.opaque = job->opaque;
|
||||
data.ret = -EINPROGRESS;
|
||||
job->cb = block_job_cancel_cb;
|
||||
job->cb = block_job_finish_cb;
|
||||
job->opaque = &data;
|
||||
block_job_cancel(job);
|
||||
finish(job, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return -EBUSY;
|
||||
}
|
||||
while (data.ret == -EINPROGRESS) {
|
||||
aio_poll(bdrv_get_aio_context(bs), true);
|
||||
}
|
||||
return (data.cancelled && data.ret == 0) ? -ECANCELED : data.ret;
|
||||
}
|
||||
|
||||
/* A wrapper around block_job_cancel() taking an Error ** parameter so it may be
|
||||
* used with block_job_finish_sync() without the need for (rather nasty)
|
||||
* function pointer casts there. */
|
||||
static void block_job_cancel_err(BlockJob *job, Error **errp)
|
||||
{
|
||||
block_job_cancel(job);
|
||||
}
|
||||
|
||||
int block_job_cancel_sync(BlockJob *job)
|
||||
{
|
||||
return block_job_finish_sync(job, &block_job_cancel_err, NULL);
|
||||
}
|
||||
|
||||
int block_job_complete_sync(BlockJob *job, Error **errp)
|
||||
{
|
||||
return block_job_finish_sync(job, &block_job_complete, errp);
|
||||
}
|
||||
|
||||
void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns)
|
||||
{
|
||||
assert(job->busy);
|
||||
|
@ -272,6 +272,21 @@ bool block_job_is_paused(BlockJob *job);
|
||||
*/
|
||||
int block_job_cancel_sync(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_complete_sync:
|
||||
* @job: The job to be completed.
|
||||
* @errp: Error object which may be set by block_job_complete(); this is not
|
||||
* necessarily set on every error, the job return value has to be
|
||||
* checked as well.
|
||||
*
|
||||
* Synchronously complete the job. The completion callback is called before the
|
||||
* function returns, unless it is NULL (which is permissible when using this
|
||||
* function).
|
||||
*
|
||||
* Returns the return value from the job.
|
||||
*/
|
||||
int block_job_complete_sync(BlockJob *job, Error **errp);
|
||||
|
||||
/**
|
||||
* block_job_iostatus_reset:
|
||||
* @job: The job whose I/O status should be reset.
|
||||
|
Loading…
Reference in New Issue
Block a user