]>
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 ++++++++++++ | |
d03e1b3c FE |
10 | job.c | 34 ++++++++++++++++++++++++++++++++++ |
11 | 2 files changed, 46 insertions(+) | |
d333327a SR |
12 | |
13 | diff --git a/include/qemu/job.h b/include/qemu/job.h | |
d03e1b3c | 14 | index e502787dd8..963cf2bef5 100644 |
d333327a SR |
15 | --- a/include/qemu/job.h |
16 | +++ b/include/qemu/job.h | |
d03e1b3c | 17 | @@ -381,6 +381,18 @@ void job_unlock(void); |
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 | |
d03e1b3c | 37 | index 93e22d180b..2b31f1e14f 100644 |
d333327a SR |
38 | --- a/job.c |
39 | +++ b/job.c | |
d03e1b3c | 40 | @@ -93,6 +93,8 @@ struct JobTxn { |
d333327a SR |
41 | |
42 | /* Reference count */ | |
43 | int refcnt; | |
44 | + | |
45 | + bool sequential; | |
46 | }; | |
47 | ||
d03e1b3c FE |
48 | void job_lock(void) |
49 | @@ -118,6 +120,25 @@ JobTxn *job_txn_new(void) | |
d333327a SR |
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 | + | |
d03e1b3c FE |
72 | /* Called with job_mutex held. */ |
73 | static void job_txn_ref_locked(JobTxn *txn) | |
d333327a | 74 | { |
d03e1b3c | 75 | @@ -1057,6 +1078,12 @@ static void job_completed_txn_success_locked(Job *job) |
d333327a SR |
76 | */ |
77 | QLIST_FOREACH(other_job, &txn->jobs, txn_list) { | |
d03e1b3c | 78 | if (!job_is_completed_locked(other_job)) { |
d333327a | 79 | + if (txn->sequential) { |
d03e1b3c FE |
80 | + job_unlock(); |
81 | + /* Needs to be called without holding the job lock */ | |
d333327a | 82 | + job_start(other_job); |
d03e1b3c | 83 | + job_lock(); |
d333327a SR |
84 | + } |
85 | return; | |
86 | } | |
87 | assert(other_job->ret == 0); | |
d03e1b3c | 88 | @@ -1268,6 +1295,13 @@ int job_finish_sync_locked(Job *job, |
0c893fd8 SR |
89 | return -EBUSY; |
90 | } | |
91 | ||
92 | + /* in a sequential transaction jobs with status CREATED can appear at time | |
93 | + * of cancelling, these have not begun work so job_enter won't do anything, | |
94 | + * let's ensure they are marked as ABORTING if required */ | |
95 | + if (job->status == JOB_STATUS_CREATED && job->txn->sequential) { | |
d03e1b3c | 96 | + job_update_rc_locked(job); |
0c893fd8 SR |
97 | + } |
98 | + | |
d03e1b3c FE |
99 | job_unlock(); |
100 | AIO_WAIT_WHILE_UNLOCKED(job->aio_context, | |
101 | (job_enter(job), !job_is_completed(job))); |