aboutsummaryrefslogtreecommitdiff
path: root/blockdev.c
diff options
context:
space:
mode:
authorStefan Reiter <s.reiter@proxmox.com>2020-04-07 13:56:49 +0200
committerKevin Wolf <kwolf@redhat.com>2020-04-07 14:34:47 +0200
commitb660a84bbb0eb1a76b505648d31d5e82594fb75e (patch)
tree50cd750825acaaf28d5adc0e7b736043b682a8a6 /blockdev.c
parent53ef8a92eb04ee19640f5aad3bff36cd4a36c250 (diff)
job: take each job's lock individually in job_txn_apply
All callers of job_txn_apply hold a single job's lock, but different jobs within a transaction can have different contexts, thus we need to lock each one individually before applying the callback function. Similar to job_completed_txn_abort this also requires releasing the caller's context before and reacquiring it after to avoid recursive locks which might break AIO_WAIT_WHILE in the callback. This is safe, since existing code would already have to take this into account, lest job_completed_txn_abort might have broken. This also brings to light a different issue: When a callback function in job_txn_apply moves it's job to a different AIO context, callers will try to release the wrong lock (now that we re-acquire the lock correctly, previously it would just continue with the old lock, leaving the job unlocked for the rest of the return path). Fix this by not caching the job's context. This is only necessary for qmp_block_job_finalize, qmp_job_finalize and job_exit, since everyone else calls through job_exit. One test needed adapting, since it calls job_finalize directly, so it manually needs to acquire the correct context. Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> Message-Id: <20200407115651.69472-2-s.reiter@proxmox.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'blockdev.c')
-rw-r--r--blockdev.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/blockdev.c b/blockdev.c
index fa8630cb41..5faddaa705 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3612,7 +3612,16 @@ void qmp_block_job_finalize(const char *id, Error **errp)
}
trace_qmp_block_job_finalize(job);
+ job_ref(&job->job);
job_finalize(&job->job, errp);
+
+ /*
+ * Job's context might have changed via job_finalize (and job_txn_apply
+ * automatically acquires the new one), so make sure we release the correct
+ * one.
+ */
+ aio_context = blk_get_aio_context(job->blk);
+ job_unref(&job->job);
aio_context_release(aio_context);
}