mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 00:33:55 -06:00
blockjob: add block_job_start
Instead of automatically starting jobs at creation time via backup_start et al, we'd like to return a job object pointer that can be started manually at later point in time. For now, add the block_job_start mechanism and start the jobs automatically as we have been doing, with conversions job-by-job coming in later patches. Of note: cancellation of unstarted jobs will perform all the normal cleanup as if the job had started, particularly abort and clean. The only difference is that we will not emit any events, because the job never actually started. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 1478587839-9834-5-git-send-email-jsnow@redhat.com Signed-off-by: Jeff Cody <jcody@redhat.com>
This commit is contained in:
parent
a7815a764c
commit
5ccac6f186
8 changed files with 67 additions and 32 deletions
54
blockjob.c
54
blockjob.c
|
@ -174,7 +174,9 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
|||
job->blk = blk;
|
||||
job->cb = cb;
|
||||
job->opaque = opaque;
|
||||
job->busy = true;
|
||||
job->busy = false;
|
||||
job->paused = true;
|
||||
job->pause_count = 1;
|
||||
job->refcnt = 1;
|
||||
bs->job = job;
|
||||
|
||||
|
@ -202,6 +204,23 @@ bool block_job_is_internal(BlockJob *job)
|
|||
return (job->id == NULL);
|
||||
}
|
||||
|
||||
static bool block_job_started(BlockJob *job)
|
||||
{
|
||||
return job->co;
|
||||
}
|
||||
|
||||
void block_job_start(BlockJob *job)
|
||||
{
|
||||
assert(job && !block_job_started(job) && job->paused &&
|
||||
!job->busy && job->driver->start);
|
||||
job->co = qemu_coroutine_create(job->driver->start, job);
|
||||
if (--job->pause_count == 0) {
|
||||
job->paused = false;
|
||||
job->busy = true;
|
||||
qemu_coroutine_enter(job->co);
|
||||
}
|
||||
}
|
||||
|
||||
void block_job_ref(BlockJob *job)
|
||||
{
|
||||
++job->refcnt;
|
||||
|
@ -248,14 +267,18 @@ static void block_job_completed_single(BlockJob *job)
|
|||
if (job->cb) {
|
||||
job->cb(job->opaque, job->ret);
|
||||
}
|
||||
if (block_job_is_cancelled(job)) {
|
||||
block_job_event_cancelled(job);
|
||||
} else {
|
||||
const char *msg = NULL;
|
||||
if (job->ret < 0) {
|
||||
msg = strerror(-job->ret);
|
||||
|
||||
/* Emit events only if we actually started */
|
||||
if (block_job_started(job)) {
|
||||
if (block_job_is_cancelled(job)) {
|
||||
block_job_event_cancelled(job);
|
||||
} else {
|
||||
const char *msg = NULL;
|
||||
if (job->ret < 0) {
|
||||
msg = strerror(-job->ret);
|
||||
}
|
||||
block_job_event_completed(job, msg);
|
||||
}
|
||||
block_job_event_completed(job, msg);
|
||||
}
|
||||
|
||||
if (job->txn) {
|
||||
|
@ -363,7 +386,8 @@ void block_job_complete(BlockJob *job, Error **errp)
|
|||
{
|
||||
/* Should not be reachable via external interface for internal jobs */
|
||||
assert(job->id);
|
||||
if (job->pause_count || job->cancelled || !job->driver->complete) {
|
||||
if (job->pause_count || job->cancelled ||
|
||||
!block_job_started(job) || !job->driver->complete) {
|
||||
error_setg(errp, "The active block job '%s' cannot be completed",
|
||||
job->id);
|
||||
return;
|
||||
|
@ -395,6 +419,8 @@ bool block_job_user_paused(BlockJob *job)
|
|||
|
||||
void coroutine_fn block_job_pause_point(BlockJob *job)
|
||||
{
|
||||
assert(job && block_job_started(job));
|
||||
|
||||
if (!block_job_should_pause(job)) {
|
||||
return;
|
||||
}
|
||||
|
@ -446,9 +472,13 @@ void block_job_enter(BlockJob *job)
|
|||
|
||||
void block_job_cancel(BlockJob *job)
|
||||
{
|
||||
job->cancelled = true;
|
||||
block_job_iostatus_reset(job);
|
||||
block_job_enter(job);
|
||||
if (block_job_started(job)) {
|
||||
job->cancelled = true;
|
||||
block_job_iostatus_reset(job);
|
||||
block_job_enter(job);
|
||||
} else {
|
||||
block_job_completed(job, -ECANCELED);
|
||||
}
|
||||
}
|
||||
|
||||
bool block_job_is_cancelled(BlockJob *job)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue