]>
Commit | Line | Data |
---|---|---|
d333327a SR |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: Stefan Reiter <s.reiter@proxmox.com> | |
3 | Date: Thu, 20 Aug 2020 14:31:59 +0200 | |
4 | Subject: [PATCH] PVE: Add sequential job transaction support | |
5 | ||
72ae34ec | 6 | Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> |
ddbf7a87 | 7 | Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> |
d333327a SR |
8 | --- |
9 | include/qemu/job.h | 12 ++++++++++++ | |
0c893fd8 SR |
10 | job.c | 31 +++++++++++++++++++++++++++++++ |
11 | 2 files changed, 43 insertions(+) | |
d333327a SR |
12 | |
13 | diff --git a/include/qemu/job.h b/include/qemu/job.h | |
4567474e | 14 | index 6e67b6977f..60376c99ee 100644 |
d333327a SR |
15 | --- a/include/qemu/job.h |
16 | +++ b/include/qemu/job.h | |
4567474e | 17 | @@ -294,6 +294,18 @@ typedef enum JobCreateFlags { |
d333327a SR |
18 | */ |
19 | JobTxn *job_txn_new(void); | |
20 | ||
21 | +/** | |
22 | + * Create a new transaction and set it to sequential mode, i.e. run all jobs | |
23 | + * one after the other instead of at the same time. | |
24 | + */ | |
25 | +JobTxn *job_txn_new_seq(void); | |
26 | + | |
27 | +/** | |
28 | + * Helper method to start the first job in a sequential transaction to kick it | |
29 | + * off. Other jobs will be run after this one completes. | |
30 | + */ | |
31 | +void job_txn_start_seq(JobTxn *txn); | |
32 | + | |
33 | /** | |
34 | * Release a reference that was previously acquired with job_txn_add_job or | |
35 | * job_txn_new. If it's the last reference to the object, it will be freed. | |
36 | diff --git a/job.c b/job.c | |
4567474e | 37 | index af25dd5b98..d0d152e697 100644 |
d333327a SR |
38 | --- a/job.c |
39 | +++ b/job.c | |
40 | @@ -72,6 +72,8 @@ struct JobTxn { | |
41 | ||
42 | /* Reference count */ | |
43 | int refcnt; | |
44 | + | |
45 | + bool sequential; | |
46 | }; | |
47 | ||
48 | /* Right now, this mutex is only needed to synchronize accesses to job->busy | |
49 | @@ -102,6 +104,25 @@ JobTxn *job_txn_new(void) | |
50 | return txn; | |
51 | } | |
52 | ||
53 | +JobTxn *job_txn_new_seq(void) | |
54 | +{ | |
55 | + JobTxn *txn = job_txn_new(); | |
56 | + txn->sequential = true; | |
57 | + return txn; | |
58 | +} | |
59 | + | |
60 | +void job_txn_start_seq(JobTxn *txn) | |
61 | +{ | |
62 | + assert(txn->sequential); | |
63 | + assert(!txn->aborting); | |
64 | + | |
65 | + Job *first = QLIST_FIRST(&txn->jobs); | |
66 | + assert(first); | |
67 | + assert(first->status == JOB_STATUS_CREATED); | |
68 | + | |
69 | + job_start(first); | |
70 | +} | |
71 | + | |
72 | static void job_txn_ref(JobTxn *txn) | |
73 | { | |
74 | txn->refcnt++; | |
4567474e | 75 | @@ -888,6 +909,9 @@ static void job_completed_txn_success(Job *job) |
d333327a SR |
76 | */ |
77 | QLIST_FOREACH(other_job, &txn->jobs, txn_list) { | |
78 | if (!job_is_completed(other_job)) { | |
79 | + if (txn->sequential) { | |
80 | + job_start(other_job); | |
81 | + } | |
82 | return; | |
83 | } | |
84 | assert(other_job->ret == 0); | |
4567474e | 85 | @@ -1082,6 +1106,13 @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) |
0c893fd8 SR |
86 | return -EBUSY; |
87 | } | |
88 | ||
89 | + /* in a sequential transaction jobs with status CREATED can appear at time | |
90 | + * of cancelling, these have not begun work so job_enter won't do anything, | |
91 | + * let's ensure they are marked as ABORTING if required */ | |
92 | + if (job->status == JOB_STATUS_CREATED && job->txn->sequential) { | |
93 | + job_update_rc(job); | |
94 | + } | |
95 | + | |
96 | AIO_WAIT_WHILE(job->aio_context, | |
97 | (job_enter(job), !job_is_completed(job))); | |
98 |