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:
Max Reitz 2014-10-24 15:57:33 +02:00 committed by Stefan Hajnoczi
parent 94054183da
commit 345f9e1b04
2 changed files with 47 additions and 7 deletions

View File

@ -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);

View File

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