X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=job.c;h=28dd48f8a59c58c74ad65056f0be4a9345abde9e;hb=9dc83cd9c3cd766263a7180bccaf67afe970d816;hp=518f603314c5681ef61fd8f2749955d441e30a94;hpb=b5a7a0573530698ee448b063ac01d485e30446bd;p=mirror_qemu.git diff --git a/job.c b/job.c index 518f603314..28dd48f8a5 100644 --- a/job.c +++ b/job.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "qapi/error.h" #include "qemu/job.h" #include "qemu/id.h" @@ -159,7 +158,7 @@ bool job_is_internal(Job *job) static void job_state_transition(Job *job, JobStatus s1) { JobStatus s0 = job->status; - assert(s1 >= 0 && s1 <= JOB_STATUS__MAX); + assert(s1 >= 0 && s1 < JOB_STATUS__MAX); trace_job_state_transition(job, job->ret, JobSTT[s0][s1] ? "allowed" : "disallowed", JobStatus_str(s0), JobStatus_str(s1)); @@ -174,7 +173,7 @@ static void job_state_transition(Job *job, JobStatus s1) int job_apply_verb(Job *job, JobVerb verb, Error **errp) { JobStatus s0 = job->status; - assert(verb >= 0 && verb <= JOB_VERB__MAX); + assert(verb >= 0 && verb < JOB_VERB__MAX); trace_job_apply_verb(job, JobStatus_str(s0), JobVerb_str(verb), JobVerbTable[verb][s0] ? "allowed" : "prohibited"); if (JobVerbTable[verb][s0]) { @@ -432,7 +431,7 @@ void job_enter_cond(Job *job, bool(*fn)(Job *job)) timer_del(&job->sleep_timer); job->busy = true; job_unlock(); - aio_co_wake(job->co); + aio_co_enter(job->aio_context, job->co); } void job_enter(Job *job) @@ -718,6 +717,7 @@ static void job_cancel_async(Job *job, bool force) static void job_completed_txn_abort(Job *job) { + AioContext *outer_ctx = job->aio_context; AioContext *ctx; JobTxn *txn = job->txn; Job *other_job; @@ -731,23 +731,26 @@ static void job_completed_txn_abort(Job *job) txn->aborting = true; job_txn_ref(txn); - /* We are the first failed job. Cancel other jobs. */ - QLIST_FOREACH(other_job, &txn->jobs, txn_list) { - ctx = other_job->aio_context; - aio_context_acquire(ctx); - } + /* We can only hold the single job's AioContext lock while calling + * job_finalize_single() because the finalization callbacks can involve + * calls of AIO_WAIT_WHILE(), which could deadlock otherwise. */ + aio_context_release(outer_ctx); /* Other jobs are effectively cancelled by us, set the status for * them; this job, however, may or may not be cancelled, depending * on the caller, so leave it. */ QLIST_FOREACH(other_job, &txn->jobs, txn_list) { if (other_job != job) { + ctx = other_job->aio_context; + aio_context_acquire(ctx); job_cancel_async(other_job, false); + aio_context_release(ctx); } } while (!QLIST_EMPTY(&txn->jobs)) { other_job = QLIST_FIRST(&txn->jobs); ctx = other_job->aio_context; + aio_context_acquire(ctx); if (!job_is_completed(other_job)) { assert(job_is_cancelled(other_job)); job_finish_sync(other_job, NULL, NULL); @@ -756,6 +759,8 @@ static void job_completed_txn_abort(Job *job) aio_context_release(ctx); } + aio_context_acquire(outer_ctx); + job_txn_unref(txn); } @@ -972,7 +977,6 @@ void job_complete(Job *job, Error **errp) int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) { Error *local_err = NULL; - AioWait dummy_wait = {}; int ret; job_ref(job); @@ -986,7 +990,7 @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) return -EBUSY; } - AIO_WAIT_WHILE(&dummy_wait, job->aio_context, + AIO_WAIT_WHILE(job->aio_context, (job_drain(job), !job_is_completed(job))); ret = (job_is_cancelled(job) && job->ret == 0) ? -ECANCELED : job->ret;