From 4ad351819b974d724e926fd23cdd66bec3c9768e Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 19 Apr 2018 17:30:16 +0200 Subject: 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 Reviewed-by: Max Reitz --- job.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 2 deletions(-) (limited to 'job.c') diff --git a/job.c b/job.c index 817c3b4426..64b64daf68 100644 --- a/job.c +++ b/job.c @@ -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; -- cgit v1.2.3