aboutsummaryrefslogtreecommitdiff
path: root/job.c
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2018-04-19 17:30:16 +0200
committerKevin Wolf <kwolf@redhat.com>2018-05-23 14:30:50 +0200
commit4ad351819b974d724e926fd23cdd66bec3c9768e (patch)
tree308f62a669a00a138090cb33e329f0232fdd5baf /job.c
parent139a9f020d49e9f863e0d46fd3d0b440dfb3b9d7 (diff)
downloadqemu-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.c100
1 files changed, 98 insertions, 2 deletions
diff --git a/job.c b/job.c
index 817c3b4..64b64da 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;