diff options
author | Kevin Wolf <kwolf@redhat.com> | 2018-04-19 17:30:16 +0200 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2018-05-23 14:30:50 +0200 |
commit | 4ad351819b974d724e926fd23cdd66bec3c9768e (patch) | |
tree | 308f62a669a00a138090cb33e329f0232fdd5baf /job.c | |
parent | 139a9f020d49e9f863e0d46fd3d0b440dfb3b9d7 (diff) | |
download | qemu-4ad351819b974d724e926fd23cdd66bec3c9768e.zip qemu-4ad351819b974d724e926fd23cdd66bec3c9768e.tar.gz qemu-4ad351819b974d724e926fd23cdd66bec3c9768e.tar.bz2 |
job: Move single job finalisation to Job
This moves the finalisation of a single job from BlockJob to Job.
Some part of this code depends on job transactions, and job transactions
call this code, we introduce some temporary calls from Job functions to
BlockJob ones. This will be fixed once transactions move to Job, too.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Diffstat (limited to 'job.c')
-rw-r--r-- | job.c | 100 |
1 files changed, 98 insertions, 2 deletions
@@ -85,7 +85,7 @@ void job_state_transition(Job *job, JobStatus s1) { JobStatus s0 = job->status; assert(s1 >= 0 && s1 <= JOB_STATUS__MAX); - trace_job_state_transition(job, /* TODO re-enable: job->ret */ 0, + trace_job_state_transition(job, job->ret, JobSTT[s0][s1] ? "allowed" : "disallowed", JobStatus_str(s0), JobStatus_str(s1)); assert(JobSTT[s0][s1]); @@ -182,7 +182,7 @@ static void job_sleep_timer_cb(void *opaque) } void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, - int flags, Error **errp) + int flags, BlockCompletionFunc *cb, void *opaque, Error **errp) { Job *job; @@ -214,6 +214,8 @@ void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, job->pause_count = 1; job->auto_finalize = !(flags & JOB_MANUAL_FINALIZE); job->auto_dismiss = !(flags & JOB_MANUAL_DISMISS); + job->cb = cb; + job->opaque = opaque; notifier_list_init(&job->on_finalize_cancelled); notifier_list_init(&job->on_finalize_completed); @@ -449,6 +451,100 @@ void job_user_resume(Job *job, Error **errp) job_resume(job); } +void job_do_dismiss(Job *job) +{ + assert(job); + job->busy = false; + job->paused = false; + job->deferred_to_main_loop = true; + + /* TODO Don't assume it's a BlockJob */ + block_job_txn_del_job((BlockJob*) job); + + job_state_transition(job, JOB_STATUS_NULL); + job_unref(job); +} + +void job_early_fail(Job *job) +{ + assert(job->status == JOB_STATUS_CREATED); + job_do_dismiss(job); +} + +static void job_conclude(Job *job) +{ + job_state_transition(job, JOB_STATUS_CONCLUDED); + if (job->auto_dismiss || !job_started(job)) { + job_do_dismiss(job); + } +} + +void job_update_rc(Job *job) +{ + if (!job->ret && job_is_cancelled(job)) { + job->ret = -ECANCELED; + } + if (job->ret) { + job_state_transition(job, JOB_STATUS_ABORTING); + } +} + +static void job_commit(Job *job) +{ + assert(!job->ret); + if (job->driver->commit) { + job->driver->commit(job); + } +} + +static void job_abort(Job *job) +{ + assert(job->ret); + if (job->driver->abort) { + job->driver->abort(job); + } +} + +static void job_clean(Job *job) +{ + if (job->driver->clean) { + job->driver->clean(job); + } +} + +int job_finalize_single(Job *job) +{ + assert(job_is_completed(job)); + + /* Ensure abort is called for late-transactional failures */ + job_update_rc(job); + + if (!job->ret) { + job_commit(job); + } else { + job_abort(job); + } + job_clean(job); + + if (job->cb) { + job->cb(job->opaque, job->ret); + } + + /* Emit events only if we actually started */ + if (job_started(job)) { + if (job_is_cancelled(job)) { + job_event_cancelled(job); + } else { + job_event_completed(job); + } + } + + /* TODO Don't assume it's a BlockJob */ + block_job_txn_del_job((BlockJob*) job); + job_conclude(job); + return 0; +} + typedef struct { Job *job; |