27199bd753
This is necessary for multi-disk backups where not all jobs are immediately started after they are created. QEMU commit 06e0a9c16405c0a4c1eca33cf286cc04c42066a2 did already part of the work, ensuring that new writes after job creation don't pass through to the backup, but not yet for the MIRROR_SYNC_MODE_BITMAP case which is used for PBS. Signed-off-by: Fabian Ebner <f.ebner@proxmox.com> Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
99 lines
2.8 KiB
Diff
99 lines
2.8 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Reiter <s.reiter@proxmox.com>
|
|
Date: Thu, 20 Aug 2020 14:31:59 +0200
|
|
Subject: [PATCH] PVE: Add sequential job transaction support
|
|
|
|
Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
|
|
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
|
|
---
|
|
include/qemu/job.h | 12 ++++++++++++
|
|
job.c | 31 +++++++++++++++++++++++++++++++
|
|
2 files changed, 43 insertions(+)
|
|
|
|
diff --git a/include/qemu/job.h b/include/qemu/job.h
|
|
index 6e67b6977f..60376c99ee 100644
|
|
--- a/include/qemu/job.h
|
|
+++ b/include/qemu/job.h
|
|
@@ -294,6 +294,18 @@ typedef enum JobCreateFlags {
|
|
*/
|
|
JobTxn *job_txn_new(void);
|
|
|
|
+/**
|
|
+ * Create a new transaction and set it to sequential mode, i.e. run all jobs
|
|
+ * one after the other instead of at the same time.
|
|
+ */
|
|
+JobTxn *job_txn_new_seq(void);
|
|
+
|
|
+/**
|
|
+ * Helper method to start the first job in a sequential transaction to kick it
|
|
+ * off. Other jobs will be run after this one completes.
|
|
+ */
|
|
+void job_txn_start_seq(JobTxn *txn);
|
|
+
|
|
/**
|
|
* Release a reference that was previously acquired with job_txn_add_job or
|
|
* job_txn_new. If it's the last reference to the object, it will be freed.
|
|
diff --git a/job.c b/job.c
|
|
index af25dd5b98..d0d152e697 100644
|
|
--- a/job.c
|
|
+++ b/job.c
|
|
@@ -72,6 +72,8 @@ struct JobTxn {
|
|
|
|
/* Reference count */
|
|
int refcnt;
|
|
+
|
|
+ bool sequential;
|
|
};
|
|
|
|
/* Right now, this mutex is only needed to synchronize accesses to job->busy
|
|
@@ -102,6 +104,25 @@ JobTxn *job_txn_new(void)
|
|
return txn;
|
|
}
|
|
|
|
+JobTxn *job_txn_new_seq(void)
|
|
+{
|
|
+ JobTxn *txn = job_txn_new();
|
|
+ txn->sequential = true;
|
|
+ return txn;
|
|
+}
|
|
+
|
|
+void job_txn_start_seq(JobTxn *txn)
|
|
+{
|
|
+ assert(txn->sequential);
|
|
+ assert(!txn->aborting);
|
|
+
|
|
+ Job *first = QLIST_FIRST(&txn->jobs);
|
|
+ assert(first);
|
|
+ assert(first->status == JOB_STATUS_CREATED);
|
|
+
|
|
+ job_start(first);
|
|
+}
|
|
+
|
|
static void job_txn_ref(JobTxn *txn)
|
|
{
|
|
txn->refcnt++;
|
|
@@ -888,6 +909,9 @@ static void job_completed_txn_success(Job *job)
|
|
*/
|
|
QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
|
|
if (!job_is_completed(other_job)) {
|
|
+ if (txn->sequential) {
|
|
+ job_start(other_job);
|
|
+ }
|
|
return;
|
|
}
|
|
assert(other_job->ret == 0);
|
|
@@ -1082,6 +1106,13 @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp)
|
|
return -EBUSY;
|
|
}
|
|
|
|
+ /* in a sequential transaction jobs with status CREATED can appear at time
|
|
+ * of cancelling, these have not begun work so job_enter won't do anything,
|
|
+ * let's ensure they are marked as ABORTING if required */
|
|
+ if (job->status == JOB_STATUS_CREATED && job->txn->sequential) {
|
|
+ job_update_rc(job);
|
|
+ }
|
|
+
|
|
AIO_WAIT_WHILE(job->aio_context,
|
|
(job_enter(job), !job_is_completed(job)));
|
|
|