xref: /qemu/job.c (revision 6f592e5a)
133e9e9bdSKevin Wolf /*
233e9e9bdSKevin Wolf  * Background jobs (long-running operations)
333e9e9bdSKevin Wolf  *
433e9e9bdSKevin Wolf  * Copyright (c) 2011 IBM Corp.
533e9e9bdSKevin Wolf  * Copyright (c) 2012, 2018 Red Hat, Inc.
633e9e9bdSKevin Wolf  *
733e9e9bdSKevin Wolf  * Permission is hereby granted, free of charge, to any person obtaining a copy
833e9e9bdSKevin Wolf  * of this software and associated documentation files (the "Software"), to deal
933e9e9bdSKevin Wolf  * in the Software without restriction, including without limitation the rights
1033e9e9bdSKevin Wolf  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1133e9e9bdSKevin Wolf  * copies of the Software, and to permit persons to whom the Software is
1233e9e9bdSKevin Wolf  * furnished to do so, subject to the following conditions:
1333e9e9bdSKevin Wolf  *
1433e9e9bdSKevin Wolf  * The above copyright notice and this permission notice shall be included in
1533e9e9bdSKevin Wolf  * all copies or substantial portions of the Software.
1633e9e9bdSKevin Wolf  *
1733e9e9bdSKevin Wolf  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1833e9e9bdSKevin Wolf  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1933e9e9bdSKevin Wolf  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2033e9e9bdSKevin Wolf  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2133e9e9bdSKevin Wolf  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2233e9e9bdSKevin Wolf  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2333e9e9bdSKevin Wolf  * THE SOFTWARE.
2433e9e9bdSKevin Wolf  */
2533e9e9bdSKevin Wolf 
2633e9e9bdSKevin Wolf #include "qemu/osdep.h"
2733e9e9bdSKevin Wolf #include "qapi/error.h"
2833e9e9bdSKevin Wolf #include "qemu/job.h"
2933e9e9bdSKevin Wolf #include "qemu/id.h"
301908a559SKevin Wolf #include "qemu/main-loop.h"
31de0fbe64SKevin Wolf #include "block/aio-wait.h"
32243af022SPaolo Bonzini #include "trace/trace-root.h"
331dac83f1SKevin Wolf #include "qapi/qapi-events-job.h"
3433e9e9bdSKevin Wolf 
3555c5a25aSEmanuele Giuseppe Esposito /*
36bf61c583SEmanuele Giuseppe Esposito  * The job API is composed of two categories of functions.
37bf61c583SEmanuele Giuseppe Esposito  *
38bf61c583SEmanuele Giuseppe Esposito  * The first includes functions used by the monitor.  The monitor is
39bf61c583SEmanuele Giuseppe Esposito  * peculiar in that it accesses the job list with job_get, and
40bf61c583SEmanuele Giuseppe Esposito  * therefore needs consistency across job_get and the actual operation
41bf61c583SEmanuele Giuseppe Esposito  * (e.g. job_user_cancel). To achieve this consistency, the caller
42bf61c583SEmanuele Giuseppe Esposito  * calls job_lock/job_unlock itself around the whole operation.
43bf61c583SEmanuele Giuseppe Esposito  *
44bf61c583SEmanuele Giuseppe Esposito  *
45bf61c583SEmanuele Giuseppe Esposito  * The second includes functions used by the job drivers and sometimes
46bf61c583SEmanuele Giuseppe Esposito  * by the core block layer. These delegate the locking to the callee instead.
47bf61c583SEmanuele Giuseppe Esposito  */
48bf61c583SEmanuele Giuseppe Esposito 
49bf61c583SEmanuele Giuseppe Esposito /*
5055c5a25aSEmanuele Giuseppe Esposito  * job_mutex protects the jobs list, but also makes the
5155c5a25aSEmanuele Giuseppe Esposito  * struct job fields thread-safe.
5255c5a25aSEmanuele Giuseppe Esposito  */
5355c5a25aSEmanuele Giuseppe Esposito QemuMutex job_mutex;
5455c5a25aSEmanuele Giuseppe Esposito 
55afe1e8a7SEmanuele Giuseppe Esposito /* Protected by job_mutex */
56e7c1d78bSKevin Wolf static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs);
57e7c1d78bSKevin Wolf 
58a50c2ab8SKevin Wolf /* Job State Transition Table */
59a50c2ab8SKevin Wolf bool JobSTT[JOB_STATUS__MAX][JOB_STATUS__MAX] = {
60a50c2ab8SKevin Wolf                                     /* U, C, R, P, Y, S, W, D, X, E, N */
61a50c2ab8SKevin Wolf     /* U: */ [JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
62a50c2ab8SKevin Wolf     /* C: */ [JOB_STATUS_CREATED]   = {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1},
63a50c2ab8SKevin Wolf     /* R: */ [JOB_STATUS_RUNNING]   = {0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0},
64a50c2ab8SKevin Wolf     /* P: */ [JOB_STATUS_PAUSED]    = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
65a50c2ab8SKevin Wolf     /* Y: */ [JOB_STATUS_READY]     = {0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0},
66a50c2ab8SKevin Wolf     /* S: */ [JOB_STATUS_STANDBY]   = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
67a50c2ab8SKevin Wolf     /* W: */ [JOB_STATUS_WAITING]   = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0},
68a50c2ab8SKevin Wolf     /* D: */ [JOB_STATUS_PENDING]   = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
69a50c2ab8SKevin Wolf     /* X: */ [JOB_STATUS_ABORTING]  = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
70a50c2ab8SKevin Wolf     /* E: */ [JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
71a50c2ab8SKevin Wolf     /* N: */ [JOB_STATUS_NULL]      = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
72a50c2ab8SKevin Wolf };
73a50c2ab8SKevin Wolf 
74a50c2ab8SKevin Wolf bool JobVerbTable[JOB_VERB__MAX][JOB_STATUS__MAX] = {
75a50c2ab8SKevin Wolf                                     /* U, C, R, P, Y, S, W, D, X, E, N */
76a50c2ab8SKevin Wolf     [JOB_VERB_CANCEL]               = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
77a50c2ab8SKevin Wolf     [JOB_VERB_PAUSE]                = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
78a50c2ab8SKevin Wolf     [JOB_VERB_RESUME]               = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
79a50c2ab8SKevin Wolf     [JOB_VERB_SET_SPEED]            = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
8053ddb9c8SMax Reitz     [JOB_VERB_COMPLETE]             = {0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0},
81a50c2ab8SKevin Wolf     [JOB_VERB_FINALIZE]             = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
82a50c2ab8SKevin Wolf     [JOB_VERB_DISMISS]              = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
83a50c2ab8SKevin Wolf };
84a50c2ab8SKevin Wolf 
857eaa8fb5SKevin Wolf /* Transactional group of jobs */
867eaa8fb5SKevin Wolf struct JobTxn {
877eaa8fb5SKevin Wolf 
887eaa8fb5SKevin Wolf     /* Is this txn being cancelled? */
897eaa8fb5SKevin Wolf     bool aborting;
907eaa8fb5SKevin Wolf 
917eaa8fb5SKevin Wolf     /* List of jobs */
927eaa8fb5SKevin Wolf     QLIST_HEAD(, Job) jobs;
937eaa8fb5SKevin Wolf 
947eaa8fb5SKevin Wolf     /* Reference count */
957eaa8fb5SKevin Wolf     int refcnt;
967eaa8fb5SKevin Wolf };
977eaa8fb5SKevin Wolf 
9855c5a25aSEmanuele Giuseppe Esposito void job_lock(void)
9955c5a25aSEmanuele Giuseppe Esposito {
100da01ff7fSKevin Wolf     qemu_mutex_lock(&job_mutex);
101da01ff7fSKevin Wolf }
102da01ff7fSKevin Wolf 
1036f592e5aSEmanuele Giuseppe Esposito void job_unlock(void)
104da01ff7fSKevin Wolf {
105da01ff7fSKevin Wolf     qemu_mutex_unlock(&job_mutex);
106da01ff7fSKevin Wolf }
107da01ff7fSKevin Wolf 
108da01ff7fSKevin Wolf static void __attribute__((__constructor__)) job_init(void)
109da01ff7fSKevin Wolf {
110da01ff7fSKevin Wolf     qemu_mutex_init(&job_mutex);
111da01ff7fSKevin Wolf }
112da01ff7fSKevin Wolf 
1137eaa8fb5SKevin Wolf JobTxn *job_txn_new(void)
1147eaa8fb5SKevin Wolf {
1157eaa8fb5SKevin Wolf     JobTxn *txn = g_new0(JobTxn, 1);
1167eaa8fb5SKevin Wolf     QLIST_INIT(&txn->jobs);
1177eaa8fb5SKevin Wolf     txn->refcnt = 1;
1187eaa8fb5SKevin Wolf     return txn;
1197eaa8fb5SKevin Wolf }
1207eaa8fb5SKevin Wolf 
121afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
122afe1e8a7SEmanuele Giuseppe Esposito static void job_txn_ref_locked(JobTxn *txn)
1237eaa8fb5SKevin Wolf {
1247eaa8fb5SKevin Wolf     txn->refcnt++;
1257eaa8fb5SKevin Wolf }
1267eaa8fb5SKevin Wolf 
127afe1e8a7SEmanuele Giuseppe Esposito void job_txn_unref_locked(JobTxn *txn)
1287eaa8fb5SKevin Wolf {
1297eaa8fb5SKevin Wolf     if (txn && --txn->refcnt == 0) {
1307eaa8fb5SKevin Wolf         g_free(txn);
1317eaa8fb5SKevin Wolf     }
1327eaa8fb5SKevin Wolf }
1337eaa8fb5SKevin Wolf 
134afe1e8a7SEmanuele Giuseppe Esposito void job_txn_unref(JobTxn *txn)
135afe1e8a7SEmanuele Giuseppe Esposito {
136afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
137afe1e8a7SEmanuele Giuseppe Esposito     job_txn_unref_locked(txn);
138afe1e8a7SEmanuele Giuseppe Esposito }
139afe1e8a7SEmanuele Giuseppe Esposito 
140544f4d52SEmanuele Giuseppe Esposito /**
141544f4d52SEmanuele Giuseppe Esposito  * @txn: The transaction (may be NULL)
142544f4d52SEmanuele Giuseppe Esposito  * @job: Job to add to the transaction
143544f4d52SEmanuele Giuseppe Esposito  *
144544f4d52SEmanuele Giuseppe Esposito  * Add @job to the transaction.  The @job must not already be in a transaction.
145544f4d52SEmanuele Giuseppe Esposito  * The caller must call either job_txn_unref() or job_completed() to release
146544f4d52SEmanuele Giuseppe Esposito  * the reference that is automatically grabbed here.
147544f4d52SEmanuele Giuseppe Esposito  *
148544f4d52SEmanuele Giuseppe Esposito  * If @txn is NULL, the function does nothing.
149afe1e8a7SEmanuele Giuseppe Esposito  *
150afe1e8a7SEmanuele Giuseppe Esposito  * Called with job_mutex held.
151544f4d52SEmanuele Giuseppe Esposito  */
152afe1e8a7SEmanuele Giuseppe Esposito static void job_txn_add_job_locked(JobTxn *txn, Job *job)
1537eaa8fb5SKevin Wolf {
1547eaa8fb5SKevin Wolf     if (!txn) {
1557eaa8fb5SKevin Wolf         return;
1567eaa8fb5SKevin Wolf     }
1577eaa8fb5SKevin Wolf 
1587eaa8fb5SKevin Wolf     assert(!job->txn);
1597eaa8fb5SKevin Wolf     job->txn = txn;
1607eaa8fb5SKevin Wolf 
1617eaa8fb5SKevin Wolf     QLIST_INSERT_HEAD(&txn->jobs, job, txn_list);
162afe1e8a7SEmanuele Giuseppe Esposito     job_txn_ref_locked(txn);
1637eaa8fb5SKevin Wolf }
1647eaa8fb5SKevin Wolf 
165afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
166afe1e8a7SEmanuele Giuseppe Esposito static void job_txn_del_job_locked(Job *job)
1677eaa8fb5SKevin Wolf {
1687eaa8fb5SKevin Wolf     if (job->txn) {
1697eaa8fb5SKevin Wolf         QLIST_REMOVE(job, txn_list);
170afe1e8a7SEmanuele Giuseppe Esposito         job_txn_unref_locked(job->txn);
1717eaa8fb5SKevin Wolf         job->txn = NULL;
1727eaa8fb5SKevin Wolf     }
1737eaa8fb5SKevin Wolf }
1747eaa8fb5SKevin Wolf 
175afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held, but releases it temporarily. */
176afe1e8a7SEmanuele Giuseppe Esposito static int job_txn_apply_locked(Job *job, int fn(Job *))
1777eaa8fb5SKevin Wolf {
178b660a84bSStefan Reiter     Job *other_job, *next;
179b660a84bSStefan Reiter     JobTxn *txn = job->txn;
1807eaa8fb5SKevin Wolf     int rc = 0;
1817eaa8fb5SKevin Wolf 
182b660a84bSStefan Reiter     /*
183b660a84bSStefan Reiter      * Similar to job_completed_txn_abort, we take each job's lock before
184b660a84bSStefan Reiter      * applying fn, but since we assume that outer_ctx is held by the caller,
185b660a84bSStefan Reiter      * we need to release it here to avoid holding the lock twice - which would
186b660a84bSStefan Reiter      * break AIO_WAIT_WHILE from within fn.
187b660a84bSStefan Reiter      */
188afe1e8a7SEmanuele Giuseppe Esposito     job_ref_locked(job);
189b660a84bSStefan Reiter 
190b660a84bSStefan Reiter     QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) {
191b660a84bSStefan Reiter         rc = fn(other_job);
1927eaa8fb5SKevin Wolf         if (rc) {
1937eaa8fb5SKevin Wolf             break;
1947eaa8fb5SKevin Wolf         }
1957eaa8fb5SKevin Wolf     }
196b660a84bSStefan Reiter 
197afe1e8a7SEmanuele Giuseppe Esposito     job_unref_locked(job);
1987eaa8fb5SKevin Wolf     return rc;
1997eaa8fb5SKevin Wolf }
2007eaa8fb5SKevin Wolf 
201456273b0SKevin Wolf bool job_is_internal(Job *job)
2021dac83f1SKevin Wolf {
2031dac83f1SKevin Wolf     return (job->id == NULL);
2041dac83f1SKevin Wolf }
2051dac83f1SKevin Wolf 
206afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
207afe1e8a7SEmanuele Giuseppe Esposito static void job_state_transition_locked(Job *job, JobStatus s1)
208a50c2ab8SKevin Wolf {
209a50c2ab8SKevin Wolf     JobStatus s0 = job->status;
210c2032289SLiam Merwick     assert(s1 >= 0 && s1 < JOB_STATUS__MAX);
2114ad35181SKevin Wolf     trace_job_state_transition(job, job->ret,
212a50c2ab8SKevin Wolf                                JobSTT[s0][s1] ? "allowed" : "disallowed",
213a50c2ab8SKevin Wolf                                JobStatus_str(s0), JobStatus_str(s1));
214a50c2ab8SKevin Wolf     assert(JobSTT[s0][s1]);
215a50c2ab8SKevin Wolf     job->status = s1;
2161dac83f1SKevin Wolf 
2171dac83f1SKevin Wolf     if (!job_is_internal(job) && s1 != s0) {
2183ab72385SPeter Xu         qapi_event_send_job_status_change(job->id, job->status);
2191dac83f1SKevin Wolf     }
220a50c2ab8SKevin Wolf }
221a50c2ab8SKevin Wolf 
222afe1e8a7SEmanuele Giuseppe Esposito int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp)
223a50c2ab8SKevin Wolf {
224a50c2ab8SKevin Wolf     JobStatus s0 = job->status;
225c2032289SLiam Merwick     assert(verb >= 0 && verb < JOB_VERB__MAX);
226a50c2ab8SKevin Wolf     trace_job_apply_verb(job, JobStatus_str(s0), JobVerb_str(verb),
227a50c2ab8SKevin Wolf                          JobVerbTable[verb][s0] ? "allowed" : "prohibited");
228a50c2ab8SKevin Wolf     if (JobVerbTable[verb][s0]) {
229a50c2ab8SKevin Wolf         return 0;
230a50c2ab8SKevin Wolf     }
231a50c2ab8SKevin Wolf     error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%s'",
232a50c2ab8SKevin Wolf                job->id, JobStatus_str(s0), JobVerb_str(verb));
233a50c2ab8SKevin Wolf     return -EPERM;
234a50c2ab8SKevin Wolf }
235a50c2ab8SKevin Wolf 
236afe1e8a7SEmanuele Giuseppe Esposito int job_apply_verb(Job *job, JobVerb verb, Error **errp)
237afe1e8a7SEmanuele Giuseppe Esposito {
238afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
239afe1e8a7SEmanuele Giuseppe Esposito     return job_apply_verb_locked(job, verb, errp);
240afe1e8a7SEmanuele Giuseppe Esposito }
241afe1e8a7SEmanuele Giuseppe Esposito 
242252291eaSKevin Wolf JobType job_type(const Job *job)
243252291eaSKevin Wolf {
244252291eaSKevin Wolf     return job->driver->job_type;
245252291eaSKevin Wolf }
246252291eaSKevin Wolf 
247252291eaSKevin Wolf const char *job_type_str(const Job *job)
248252291eaSKevin Wolf {
249252291eaSKevin Wolf     return JobType_str(job_type(job));
250252291eaSKevin Wolf }
251252291eaSKevin Wolf 
252afe1e8a7SEmanuele Giuseppe Esposito bool job_is_cancelled_locked(Job *job)
253daa7f2f9SKevin Wolf {
254a640fa0eSHanna Reitz     /* force_cancel may be true only if cancelled is true, too */
255a640fa0eSHanna Reitz     assert(job->cancelled || !job->force_cancel);
256a640fa0eSHanna Reitz     return job->force_cancel;
25708b83bffSHanna Reitz }
25808b83bffSHanna Reitz 
259afe1e8a7SEmanuele Giuseppe Esposito bool job_is_cancelled(Job *job)
260afe1e8a7SEmanuele Giuseppe Esposito {
261afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
262afe1e8a7SEmanuele Giuseppe Esposito     return job_is_cancelled_locked(job);
263afe1e8a7SEmanuele Giuseppe Esposito }
264afe1e8a7SEmanuele Giuseppe Esposito 
265afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
266afe1e8a7SEmanuele Giuseppe Esposito static bool job_cancel_requested_locked(Job *job)
26708b83bffSHanna Reitz {
268daa7f2f9SKevin Wolf     return job->cancelled;
269daa7f2f9SKevin Wolf }
270daa7f2f9SKevin Wolf 
271afe1e8a7SEmanuele Giuseppe Esposito bool job_cancel_requested(Job *job)
272afe1e8a7SEmanuele Giuseppe Esposito {
273afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
274afe1e8a7SEmanuele Giuseppe Esposito     return job_cancel_requested_locked(job);
275afe1e8a7SEmanuele Giuseppe Esposito }
276afe1e8a7SEmanuele Giuseppe Esposito 
277afe1e8a7SEmanuele Giuseppe Esposito bool job_is_ready_locked(Job *job)
278df956ae2SKevin Wolf {
279df956ae2SKevin Wolf     switch (job->status) {
280df956ae2SKevin Wolf     case JOB_STATUS_UNDEFINED:
281df956ae2SKevin Wolf     case JOB_STATUS_CREATED:
282df956ae2SKevin Wolf     case JOB_STATUS_RUNNING:
283df956ae2SKevin Wolf     case JOB_STATUS_PAUSED:
284df956ae2SKevin Wolf     case JOB_STATUS_WAITING:
285df956ae2SKevin Wolf     case JOB_STATUS_PENDING:
286df956ae2SKevin Wolf     case JOB_STATUS_ABORTING:
287df956ae2SKevin Wolf     case JOB_STATUS_CONCLUDED:
288df956ae2SKevin Wolf     case JOB_STATUS_NULL:
289df956ae2SKevin Wolf         return false;
290df956ae2SKevin Wolf     case JOB_STATUS_READY:
291df956ae2SKevin Wolf     case JOB_STATUS_STANDBY:
292df956ae2SKevin Wolf         return true;
293df956ae2SKevin Wolf     default:
294df956ae2SKevin Wolf         g_assert_not_reached();
295df956ae2SKevin Wolf     }
296df956ae2SKevin Wolf     return false;
297df956ae2SKevin Wolf }
298df956ae2SKevin Wolf 
299afe1e8a7SEmanuele Giuseppe Esposito bool job_is_ready(Job *job)
300afe1e8a7SEmanuele Giuseppe Esposito {
301afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
302afe1e8a7SEmanuele Giuseppe Esposito     return job_is_ready_locked(job);
303afe1e8a7SEmanuele Giuseppe Esposito }
304afe1e8a7SEmanuele Giuseppe Esposito 
305afe1e8a7SEmanuele Giuseppe Esposito bool job_is_completed_locked(Job *job)
306afe1e8a7SEmanuele Giuseppe Esposito {
307afe1e8a7SEmanuele Giuseppe Esposito     switch (job->status) {
308afe1e8a7SEmanuele Giuseppe Esposito     case JOB_STATUS_UNDEFINED:
309afe1e8a7SEmanuele Giuseppe Esposito     case JOB_STATUS_CREATED:
310afe1e8a7SEmanuele Giuseppe Esposito     case JOB_STATUS_RUNNING:
311afe1e8a7SEmanuele Giuseppe Esposito     case JOB_STATUS_PAUSED:
312afe1e8a7SEmanuele Giuseppe Esposito     case JOB_STATUS_READY:
313afe1e8a7SEmanuele Giuseppe Esposito     case JOB_STATUS_STANDBY:
314afe1e8a7SEmanuele Giuseppe Esposito         return false;
315afe1e8a7SEmanuele Giuseppe Esposito     case JOB_STATUS_WAITING:
316afe1e8a7SEmanuele Giuseppe Esposito     case JOB_STATUS_PENDING:
317afe1e8a7SEmanuele Giuseppe Esposito     case JOB_STATUS_ABORTING:
318afe1e8a7SEmanuele Giuseppe Esposito     case JOB_STATUS_CONCLUDED:
319afe1e8a7SEmanuele Giuseppe Esposito     case JOB_STATUS_NULL:
320afe1e8a7SEmanuele Giuseppe Esposito         return true;
321afe1e8a7SEmanuele Giuseppe Esposito     default:
322afe1e8a7SEmanuele Giuseppe Esposito         g_assert_not_reached();
323afe1e8a7SEmanuele Giuseppe Esposito     }
324afe1e8a7SEmanuele Giuseppe Esposito     return false;
325afe1e8a7SEmanuele Giuseppe Esposito }
326afe1e8a7SEmanuele Giuseppe Esposito 
327dbe5e6c1SKevin Wolf bool job_is_completed(Job *job)
328dbe5e6c1SKevin Wolf {
329afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
330afe1e8a7SEmanuele Giuseppe Esposito     return job_is_completed_locked(job);
331dbe5e6c1SKevin Wolf }
332dbe5e6c1SKevin Wolf 
333afe1e8a7SEmanuele Giuseppe Esposito static bool job_started_locked(Job *job)
334da01ff7fSKevin Wolf {
335da01ff7fSKevin Wolf     return job->co;
336da01ff7fSKevin Wolf }
337da01ff7fSKevin Wolf 
338afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
339afe1e8a7SEmanuele Giuseppe Esposito static bool job_should_pause_locked(Job *job)
340da01ff7fSKevin Wolf {
341da01ff7fSKevin Wolf     return job->pause_count > 0;
342da01ff7fSKevin Wolf }
343da01ff7fSKevin Wolf 
344afe1e8a7SEmanuele Giuseppe Esposito Job *job_next_locked(Job *job)
345e7c1d78bSKevin Wolf {
346e7c1d78bSKevin Wolf     if (!job) {
347e7c1d78bSKevin Wolf         return QLIST_FIRST(&jobs);
348e7c1d78bSKevin Wolf     }
349e7c1d78bSKevin Wolf     return QLIST_NEXT(job, job_list);
350e7c1d78bSKevin Wolf }
351e7c1d78bSKevin Wolf 
352afe1e8a7SEmanuele Giuseppe Esposito Job *job_next(Job *job)
353afe1e8a7SEmanuele Giuseppe Esposito {
354afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
355afe1e8a7SEmanuele Giuseppe Esposito     return job_next_locked(job);
356afe1e8a7SEmanuele Giuseppe Esposito }
357afe1e8a7SEmanuele Giuseppe Esposito 
358afe1e8a7SEmanuele Giuseppe Esposito Job *job_get_locked(const char *id)
359e7c1d78bSKevin Wolf {
360e7c1d78bSKevin Wolf     Job *job;
361e7c1d78bSKevin Wolf 
362e7c1d78bSKevin Wolf     QLIST_FOREACH(job, &jobs, job_list) {
363e7c1d78bSKevin Wolf         if (job->id && !strcmp(id, job->id)) {
364e7c1d78bSKevin Wolf             return job;
365e7c1d78bSKevin Wolf         }
366e7c1d78bSKevin Wolf     }
367e7c1d78bSKevin Wolf 
368e7c1d78bSKevin Wolf     return NULL;
369e7c1d78bSKevin Wolf }
370e7c1d78bSKevin Wolf 
371afe1e8a7SEmanuele Giuseppe Esposito Job *job_get(const char *id)
372afe1e8a7SEmanuele Giuseppe Esposito {
373afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
374afe1e8a7SEmanuele Giuseppe Esposito     return job_get_locked(id);
375afe1e8a7SEmanuele Giuseppe Esposito }
376afe1e8a7SEmanuele Giuseppe Esposito 
3773ed4f708SEmanuele Giuseppe Esposito void job_set_aio_context(Job *job, AioContext *ctx)
3783ed4f708SEmanuele Giuseppe Esposito {
3793ed4f708SEmanuele Giuseppe Esposito     /* protect against read in job_finish_sync_locked and job_start */
3803ed4f708SEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
3813ed4f708SEmanuele Giuseppe Esposito     /* protect against read in job_do_yield_locked */
3823ed4f708SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
3833ed4f708SEmanuele Giuseppe Esposito     /* ensure the job is quiescent while the AioContext is changed */
3843ed4f708SEmanuele Giuseppe Esposito     assert(job->paused || job_is_completed_locked(job));
3853ed4f708SEmanuele Giuseppe Esposito     job->aio_context = ctx;
3863ed4f708SEmanuele Giuseppe Esposito }
3873ed4f708SEmanuele Giuseppe Esposito 
388afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex *not* held. */
3895d43e86eSKevin Wolf static void job_sleep_timer_cb(void *opaque)
3905d43e86eSKevin Wolf {
3915d43e86eSKevin Wolf     Job *job = opaque;
3925d43e86eSKevin Wolf 
3935d43e86eSKevin Wolf     job_enter(job);
3945d43e86eSKevin Wolf }
3955d43e86eSKevin Wolf 
3967eaa8fb5SKevin Wolf void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn,
3977eaa8fb5SKevin Wolf                  AioContext *ctx, int flags, BlockCompletionFunc *cb,
3987eaa8fb5SKevin Wolf                  void *opaque, Error **errp)
39933e9e9bdSKevin Wolf {
40033e9e9bdSKevin Wolf     Job *job;
40133e9e9bdSKevin Wolf 
402afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
403afe1e8a7SEmanuele Giuseppe Esposito 
40433e9e9bdSKevin Wolf     if (job_id) {
405bb02b65cSKevin Wolf         if (flags & JOB_INTERNAL) {
406bb02b65cSKevin Wolf             error_setg(errp, "Cannot specify job ID for internal job");
407bb02b65cSKevin Wolf             return NULL;
408bb02b65cSKevin Wolf         }
40933e9e9bdSKevin Wolf         if (!id_wellformed(job_id)) {
41033e9e9bdSKevin Wolf             error_setg(errp, "Invalid job ID '%s'", job_id);
41133e9e9bdSKevin Wolf             return NULL;
41233e9e9bdSKevin Wolf         }
413afe1e8a7SEmanuele Giuseppe Esposito         if (job_get_locked(job_id)) {
414e7c1d78bSKevin Wolf             error_setg(errp, "Job ID '%s' already in use", job_id);
415e7c1d78bSKevin Wolf             return NULL;
416e7c1d78bSKevin Wolf         }
417bb02b65cSKevin Wolf     } else if (!(flags & JOB_INTERNAL)) {
418bb02b65cSKevin Wolf         error_setg(errp, "An explicit job ID is required");
419bb02b65cSKevin Wolf         return NULL;
42033e9e9bdSKevin Wolf     }
42133e9e9bdSKevin Wolf 
42233e9e9bdSKevin Wolf     job = g_malloc0(driver->instance_size);
42333e9e9bdSKevin Wolf     job->driver        = driver;
42433e9e9bdSKevin Wolf     job->id            = g_strdup(job_id);
42580fa2c75SKevin Wolf     job->refcnt        = 1;
42608be6fe2SKevin Wolf     job->aio_context   = ctx;
427da01ff7fSKevin Wolf     job->busy          = false;
428da01ff7fSKevin Wolf     job->paused        = true;
429da01ff7fSKevin Wolf     job->pause_count   = 1;
430bb02b65cSKevin Wolf     job->auto_finalize = !(flags & JOB_MANUAL_FINALIZE);
431bb02b65cSKevin Wolf     job->auto_dismiss  = !(flags & JOB_MANUAL_DISMISS);
4324ad35181SKevin Wolf     job->cb            = cb;
4334ad35181SKevin Wolf     job->opaque        = opaque;
43433e9e9bdSKevin Wolf 
435a7b4f8fcSEmanuele Giuseppe Esposito     progress_init(&job->progress);
436a7b4f8fcSEmanuele Giuseppe Esposito 
437139a9f02SKevin Wolf     notifier_list_init(&job->on_finalize_cancelled);
438139a9f02SKevin Wolf     notifier_list_init(&job->on_finalize_completed);
439139a9f02SKevin Wolf     notifier_list_init(&job->on_pending);
4402e1795b5SKevin Wolf     notifier_list_init(&job->on_ready);
441252f4091SEmanuele Giuseppe Esposito     notifier_list_init(&job->on_idle);
442139a9f02SKevin Wolf 
443afe1e8a7SEmanuele Giuseppe Esposito     job_state_transition_locked(job, JOB_STATUS_CREATED);
4445d43e86eSKevin Wolf     aio_timer_init(qemu_get_aio_context(), &job->sleep_timer,
4455d43e86eSKevin Wolf                    QEMU_CLOCK_REALTIME, SCALE_NS,
4465d43e86eSKevin Wolf                    job_sleep_timer_cb, job);
447a50c2ab8SKevin Wolf 
448e7c1d78bSKevin Wolf     QLIST_INSERT_HEAD(&jobs, job, job_list);
449e7c1d78bSKevin Wolf 
4507eaa8fb5SKevin Wolf     /* Single jobs are modeled as single-job transactions for sake of
4517eaa8fb5SKevin Wolf      * consolidating the job management logic */
4527eaa8fb5SKevin Wolf     if (!txn) {
4537eaa8fb5SKevin Wolf         txn = job_txn_new();
454afe1e8a7SEmanuele Giuseppe Esposito         job_txn_add_job_locked(txn, job);
455afe1e8a7SEmanuele Giuseppe Esposito         job_txn_unref_locked(txn);
4567eaa8fb5SKevin Wolf     } else {
457afe1e8a7SEmanuele Giuseppe Esposito         job_txn_add_job_locked(txn, job);
4587eaa8fb5SKevin Wolf     }
4597eaa8fb5SKevin Wolf 
46033e9e9bdSKevin Wolf     return job;
46133e9e9bdSKevin Wolf }
462fd61a701SKevin Wolf 
463afe1e8a7SEmanuele Giuseppe Esposito void job_ref_locked(Job *job)
464fd61a701SKevin Wolf {
46580fa2c75SKevin Wolf     ++job->refcnt;
46680fa2c75SKevin Wolf }
46780fa2c75SKevin Wolf 
468afe1e8a7SEmanuele Giuseppe Esposito void job_ref(Job *job)
469afe1e8a7SEmanuele Giuseppe Esposito {
470afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
471afe1e8a7SEmanuele Giuseppe Esposito     job_ref_locked(job);
472afe1e8a7SEmanuele Giuseppe Esposito }
473afe1e8a7SEmanuele Giuseppe Esposito 
474afe1e8a7SEmanuele Giuseppe Esposito void job_unref_locked(Job *job)
47580fa2c75SKevin Wolf {
476c70b8031SEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
477c70b8031SEmanuele Giuseppe Esposito 
47880fa2c75SKevin Wolf     if (--job->refcnt == 0) {
47980fa2c75SKevin Wolf         assert(job->status == JOB_STATUS_NULL);
4805d43e86eSKevin Wolf         assert(!timer_pending(&job->sleep_timer));
4817eaa8fb5SKevin Wolf         assert(!job->txn);
48280fa2c75SKevin Wolf 
48380fa2c75SKevin Wolf         if (job->driver->free) {
4846f592e5aSEmanuele Giuseppe Esposito             AioContext *aio_context = job->aio_context;
485afe1e8a7SEmanuele Giuseppe Esposito             job_unlock();
4866f592e5aSEmanuele Giuseppe Esposito             /* FIXME: aiocontext lock is required because cb calls blk_unref */
4876f592e5aSEmanuele Giuseppe Esposito             aio_context_acquire(aio_context);
48880fa2c75SKevin Wolf             job->driver->free(job);
4896f592e5aSEmanuele Giuseppe Esposito             aio_context_release(aio_context);
490afe1e8a7SEmanuele Giuseppe Esposito             job_lock();
49180fa2c75SKevin Wolf         }
49280fa2c75SKevin Wolf 
493e7c1d78bSKevin Wolf         QLIST_REMOVE(job, job_list);
494e7c1d78bSKevin Wolf 
495a7b4f8fcSEmanuele Giuseppe Esposito         progress_destroy(&job->progress);
4963d1f8b07SJohn Snow         error_free(job->err);
497fd61a701SKevin Wolf         g_free(job->id);
498fd61a701SKevin Wolf         g_free(job);
499fd61a701SKevin Wolf     }
50080fa2c75SKevin Wolf }
5011908a559SKevin Wolf 
502afe1e8a7SEmanuele Giuseppe Esposito void job_unref(Job *job)
503afe1e8a7SEmanuele Giuseppe Esposito {
504afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
505afe1e8a7SEmanuele Giuseppe Esposito     job_unref_locked(job);
506afe1e8a7SEmanuele Giuseppe Esposito }
507afe1e8a7SEmanuele Giuseppe Esposito 
50830a5c887SKevin Wolf void job_progress_update(Job *job, uint64_t done)
50930a5c887SKevin Wolf {
51001fe1ca9SVladimir Sementsov-Ogievskiy     progress_work_done(&job->progress, done);
51130a5c887SKevin Wolf }
51230a5c887SKevin Wolf 
51330a5c887SKevin Wolf void job_progress_set_remaining(Job *job, uint64_t remaining)
51430a5c887SKevin Wolf {
51501fe1ca9SVladimir Sementsov-Ogievskiy     progress_set_remaining(&job->progress, remaining);
51630a5c887SKevin Wolf }
51730a5c887SKevin Wolf 
51862f13600SMax Reitz void job_progress_increase_remaining(Job *job, uint64_t delta)
51962f13600SMax Reitz {
52001fe1ca9SVladimir Sementsov-Ogievskiy     progress_increase_remaining(&job->progress, delta);
52162f13600SMax Reitz }
52262f13600SMax Reitz 
523544f4d52SEmanuele Giuseppe Esposito /**
524544f4d52SEmanuele Giuseppe Esposito  * To be called when a cancelled job is finalised.
525afe1e8a7SEmanuele Giuseppe Esposito  * Called with job_mutex held.
526544f4d52SEmanuele Giuseppe Esposito  */
527afe1e8a7SEmanuele Giuseppe Esposito static void job_event_cancelled_locked(Job *job)
528139a9f02SKevin Wolf {
529139a9f02SKevin Wolf     notifier_list_notify(&job->on_finalize_cancelled, job);
530139a9f02SKevin Wolf }
531139a9f02SKevin Wolf 
532544f4d52SEmanuele Giuseppe Esposito /**
533544f4d52SEmanuele Giuseppe Esposito  * To be called when a successfully completed job is finalised.
534afe1e8a7SEmanuele Giuseppe Esposito  * Called with job_mutex held.
535544f4d52SEmanuele Giuseppe Esposito  */
536afe1e8a7SEmanuele Giuseppe Esposito static void job_event_completed_locked(Job *job)
537139a9f02SKevin Wolf {
538139a9f02SKevin Wolf     notifier_list_notify(&job->on_finalize_completed, job);
539139a9f02SKevin Wolf }
540139a9f02SKevin Wolf 
541afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
542afe1e8a7SEmanuele Giuseppe Esposito static void job_event_pending_locked(Job *job)
543139a9f02SKevin Wolf {
544139a9f02SKevin Wolf     notifier_list_notify(&job->on_pending, job);
545139a9f02SKevin Wolf }
546139a9f02SKevin Wolf 
547afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
548afe1e8a7SEmanuele Giuseppe Esposito static void job_event_ready_locked(Job *job)
5492e1795b5SKevin Wolf {
5502e1795b5SKevin Wolf     notifier_list_notify(&job->on_ready, job);
5512e1795b5SKevin Wolf }
5522e1795b5SKevin Wolf 
553afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
554afe1e8a7SEmanuele Giuseppe Esposito static void job_event_idle_locked(Job *job)
55534dc97b9SKevin Wolf {
55634dc97b9SKevin Wolf     notifier_list_notify(&job->on_idle, job);
55734dc97b9SKevin Wolf }
55834dc97b9SKevin Wolf 
559afe1e8a7SEmanuele Giuseppe Esposito void job_enter_cond_locked(Job *job, bool(*fn)(Job *job))
560da01ff7fSKevin Wolf {
561afe1e8a7SEmanuele Giuseppe Esposito     if (!job_started_locked(job)) {
562da01ff7fSKevin Wolf         return;
563da01ff7fSKevin Wolf     }
564da01ff7fSKevin Wolf     if (job->deferred_to_main_loop) {
565da01ff7fSKevin Wolf         return;
566da01ff7fSKevin Wolf     }
567da01ff7fSKevin Wolf 
568da01ff7fSKevin Wolf     if (job->busy) {
569da01ff7fSKevin Wolf         return;
570da01ff7fSKevin Wolf     }
571da01ff7fSKevin Wolf 
572da01ff7fSKevin Wolf     if (fn && !fn(job)) {
573da01ff7fSKevin Wolf         return;
574da01ff7fSKevin Wolf     }
575da01ff7fSKevin Wolf 
576da01ff7fSKevin Wolf     assert(!job->deferred_to_main_loop);
577da01ff7fSKevin Wolf     timer_del(&job->sleep_timer);
578da01ff7fSKevin Wolf     job->busy = true;
579afe1e8a7SEmanuele Giuseppe Esposito     job_unlock();
580ef02dac2SPaolo Bonzini     aio_co_wake(job->co);
581afe1e8a7SEmanuele Giuseppe Esposito     job_lock();
582afe1e8a7SEmanuele Giuseppe Esposito }
583afe1e8a7SEmanuele Giuseppe Esposito 
584afe1e8a7SEmanuele Giuseppe Esposito void job_enter_cond(Job *job, bool(*fn)(Job *job))
585afe1e8a7SEmanuele Giuseppe Esposito {
586afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
587afe1e8a7SEmanuele Giuseppe Esposito     job_enter_cond_locked(job, fn);
588da01ff7fSKevin Wolf }
589da01ff7fSKevin Wolf 
5905d43e86eSKevin Wolf void job_enter(Job *job)
5915d43e86eSKevin Wolf {
592afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
593afe1e8a7SEmanuele Giuseppe Esposito     job_enter_cond_locked(job, NULL);
5945d43e86eSKevin Wolf }
5955d43e86eSKevin Wolf 
596da01ff7fSKevin Wolf /* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds.
5973d70ff53SKevin Wolf  * Reentering the job coroutine with job_enter() before the timer has expired
5983d70ff53SKevin Wolf  * is allowed and cancels the timer.
599da01ff7fSKevin Wolf  *
6003d70ff53SKevin Wolf  * If @ns is (uint64_t) -1, no timer is scheduled and job_enter() must be
601afe1e8a7SEmanuele Giuseppe Esposito  * called explicitly.
602afe1e8a7SEmanuele Giuseppe Esposito  *
603afe1e8a7SEmanuele Giuseppe Esposito  * Called with job_mutex held, but releases it temporarily.
604afe1e8a7SEmanuele Giuseppe Esposito  */
605afe1e8a7SEmanuele Giuseppe Esposito static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns)
606da01ff7fSKevin Wolf {
607ef02dac2SPaolo Bonzini     AioContext *next_aio_context;
608ef02dac2SPaolo Bonzini 
609da01ff7fSKevin Wolf     if (ns != -1) {
610da01ff7fSKevin Wolf         timer_mod(&job->sleep_timer, ns);
611da01ff7fSKevin Wolf     }
612da01ff7fSKevin Wolf     job->busy = false;
613afe1e8a7SEmanuele Giuseppe Esposito     job_event_idle_locked(job);
614afe1e8a7SEmanuele Giuseppe Esposito     job_unlock();
615da01ff7fSKevin Wolf     qemu_coroutine_yield();
616afe1e8a7SEmanuele Giuseppe Esposito     job_lock();
617da01ff7fSKevin Wolf 
618ef02dac2SPaolo Bonzini     next_aio_context = job->aio_context;
619ef02dac2SPaolo Bonzini     /*
620ef02dac2SPaolo Bonzini      * Coroutine has resumed, but in the meanwhile the job AioContext
621ef02dac2SPaolo Bonzini      * might have changed via bdrv_try_set_aio_context(), so we need to move
622ef02dac2SPaolo Bonzini      * the coroutine too in the new aiocontext.
623ef02dac2SPaolo Bonzini      */
624ef02dac2SPaolo Bonzini     while (qemu_get_current_aio_context() != next_aio_context) {
625ef02dac2SPaolo Bonzini         job_unlock();
626ef02dac2SPaolo Bonzini         aio_co_reschedule_self(next_aio_context);
627ef02dac2SPaolo Bonzini         job_lock();
628ef02dac2SPaolo Bonzini         next_aio_context = job->aio_context;
629ef02dac2SPaolo Bonzini     }
630ef02dac2SPaolo Bonzini 
631ef02dac2SPaolo Bonzini     /* Set by job_enter_cond_locked() before re-entering the coroutine.  */
632da01ff7fSKevin Wolf     assert(job->busy);
633da01ff7fSKevin Wolf }
634da01ff7fSKevin Wolf 
635afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held, but releases it temporarily. */
636afe1e8a7SEmanuele Giuseppe Esposito static void coroutine_fn job_pause_point_locked(Job *job)
637da01ff7fSKevin Wolf {
638afe1e8a7SEmanuele Giuseppe Esposito     assert(job && job_started_locked(job));
639da01ff7fSKevin Wolf 
640afe1e8a7SEmanuele Giuseppe Esposito     if (!job_should_pause_locked(job)) {
641da01ff7fSKevin Wolf         return;
642da01ff7fSKevin Wolf     }
643afe1e8a7SEmanuele Giuseppe Esposito     if (job_is_cancelled_locked(job)) {
644da01ff7fSKevin Wolf         return;
645da01ff7fSKevin Wolf     }
646da01ff7fSKevin Wolf 
647da01ff7fSKevin Wolf     if (job->driver->pause) {
648afe1e8a7SEmanuele Giuseppe Esposito         job_unlock();
649da01ff7fSKevin Wolf         job->driver->pause(job);
650afe1e8a7SEmanuele Giuseppe Esposito         job_lock();
651da01ff7fSKevin Wolf     }
652da01ff7fSKevin Wolf 
653afe1e8a7SEmanuele Giuseppe Esposito     if (job_should_pause_locked(job) && !job_is_cancelled_locked(job)) {
654da01ff7fSKevin Wolf         JobStatus status = job->status;
655afe1e8a7SEmanuele Giuseppe Esposito         job_state_transition_locked(job, status == JOB_STATUS_READY
656da01ff7fSKevin Wolf                                     ? JOB_STATUS_STANDBY
657da01ff7fSKevin Wolf                                     : JOB_STATUS_PAUSED);
658da01ff7fSKevin Wolf         job->paused = true;
659afe1e8a7SEmanuele Giuseppe Esposito         job_do_yield_locked(job, -1);
660da01ff7fSKevin Wolf         job->paused = false;
661afe1e8a7SEmanuele Giuseppe Esposito         job_state_transition_locked(job, status);
662da01ff7fSKevin Wolf     }
663da01ff7fSKevin Wolf 
664da01ff7fSKevin Wolf     if (job->driver->resume) {
665afe1e8a7SEmanuele Giuseppe Esposito         job_unlock();
666da01ff7fSKevin Wolf         job->driver->resume(job);
667afe1e8a7SEmanuele Giuseppe Esposito         job_lock();
668da01ff7fSKevin Wolf     }
669da01ff7fSKevin Wolf }
670da01ff7fSKevin Wolf 
671afe1e8a7SEmanuele Giuseppe Esposito void coroutine_fn job_pause_point(Job *job)
672afe1e8a7SEmanuele Giuseppe Esposito {
673afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
674afe1e8a7SEmanuele Giuseppe Esposito     job_pause_point_locked(job);
675afe1e8a7SEmanuele Giuseppe Esposito }
676afe1e8a7SEmanuele Giuseppe Esposito 
677afe1e8a7SEmanuele Giuseppe Esposito static void coroutine_fn job_yield_locked(Job *job)
678afe1e8a7SEmanuele Giuseppe Esposito {
679afe1e8a7SEmanuele Giuseppe Esposito     assert(job->busy);
680afe1e8a7SEmanuele Giuseppe Esposito 
681afe1e8a7SEmanuele Giuseppe Esposito     /* Check cancellation *before* setting busy = false, too!  */
682afe1e8a7SEmanuele Giuseppe Esposito     if (job_is_cancelled_locked(job)) {
683afe1e8a7SEmanuele Giuseppe Esposito         return;
684afe1e8a7SEmanuele Giuseppe Esposito     }
685afe1e8a7SEmanuele Giuseppe Esposito 
686afe1e8a7SEmanuele Giuseppe Esposito     if (!job_should_pause_locked(job)) {
687afe1e8a7SEmanuele Giuseppe Esposito         job_do_yield_locked(job, -1);
688afe1e8a7SEmanuele Giuseppe Esposito     }
689afe1e8a7SEmanuele Giuseppe Esposito 
690afe1e8a7SEmanuele Giuseppe Esposito     job_pause_point_locked(job);
691afe1e8a7SEmanuele Giuseppe Esposito }
692afe1e8a7SEmanuele Giuseppe Esposito 
69306753a07SPaolo Bonzini void coroutine_fn job_yield(Job *job)
694198c49ccSKevin Wolf {
695afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
696afe1e8a7SEmanuele Giuseppe Esposito     job_yield_locked(job);
697198c49ccSKevin Wolf }
698198c49ccSKevin Wolf 
6995d43e86eSKevin Wolf void coroutine_fn job_sleep_ns(Job *job, int64_t ns)
7005d43e86eSKevin Wolf {
701afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
7025d43e86eSKevin Wolf     assert(job->busy);
7035d43e86eSKevin Wolf 
7045d43e86eSKevin Wolf     /* Check cancellation *before* setting busy = false, too!  */
705afe1e8a7SEmanuele Giuseppe Esposito     if (job_is_cancelled_locked(job)) {
7065d43e86eSKevin Wolf         return;
7075d43e86eSKevin Wolf     }
7085d43e86eSKevin Wolf 
709afe1e8a7SEmanuele Giuseppe Esposito     if (!job_should_pause_locked(job)) {
710afe1e8a7SEmanuele Giuseppe Esposito         job_do_yield_locked(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns);
7115d43e86eSKevin Wolf     }
7125d43e86eSKevin Wolf 
713afe1e8a7SEmanuele Giuseppe Esposito     job_pause_point_locked(job);
7145d43e86eSKevin Wolf }
7155d43e86eSKevin Wolf 
716afe1e8a7SEmanuele Giuseppe Esposito /* Assumes the job_mutex is held */
717afe1e8a7SEmanuele Giuseppe Esposito static bool job_timer_not_pending_locked(Job *job)
718b15de828SKevin Wolf {
719b15de828SKevin Wolf     return !timer_pending(&job->sleep_timer);
720b15de828SKevin Wolf }
721b15de828SKevin Wolf 
722afe1e8a7SEmanuele Giuseppe Esposito void job_pause_locked(Job *job)
723b15de828SKevin Wolf {
724b15de828SKevin Wolf     job->pause_count++;
7253ee1483bSVladimir Sementsov-Ogievskiy     if (!job->paused) {
726afe1e8a7SEmanuele Giuseppe Esposito         job_enter_cond_locked(job, NULL);
7273ee1483bSVladimir Sementsov-Ogievskiy     }
728b15de828SKevin Wolf }
729b15de828SKevin Wolf 
730afe1e8a7SEmanuele Giuseppe Esposito void job_pause(Job *job)
731afe1e8a7SEmanuele Giuseppe Esposito {
732afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
733afe1e8a7SEmanuele Giuseppe Esposito     job_pause_locked(job);
734afe1e8a7SEmanuele Giuseppe Esposito }
735afe1e8a7SEmanuele Giuseppe Esposito 
736afe1e8a7SEmanuele Giuseppe Esposito void job_resume_locked(Job *job)
737b15de828SKevin Wolf {
738b15de828SKevin Wolf     assert(job->pause_count > 0);
739b15de828SKevin Wolf     job->pause_count--;
740b15de828SKevin Wolf     if (job->pause_count) {
741b15de828SKevin Wolf         return;
742b15de828SKevin Wolf     }
743b15de828SKevin Wolf 
744b15de828SKevin Wolf     /* kick only if no timer is pending */
745afe1e8a7SEmanuele Giuseppe Esposito     job_enter_cond_locked(job, job_timer_not_pending_locked);
746b15de828SKevin Wolf }
747b15de828SKevin Wolf 
748afe1e8a7SEmanuele Giuseppe Esposito void job_resume(Job *job)
749b15de828SKevin Wolf {
750afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
751afe1e8a7SEmanuele Giuseppe Esposito     job_resume_locked(job);
752afe1e8a7SEmanuele Giuseppe Esposito }
753afe1e8a7SEmanuele Giuseppe Esposito 
754afe1e8a7SEmanuele Giuseppe Esposito void job_user_pause_locked(Job *job, Error **errp)
755afe1e8a7SEmanuele Giuseppe Esposito {
756afe1e8a7SEmanuele Giuseppe Esposito     if (job_apply_verb_locked(job, JOB_VERB_PAUSE, errp)) {
757b15de828SKevin Wolf         return;
758b15de828SKevin Wolf     }
759b15de828SKevin Wolf     if (job->user_paused) {
760b15de828SKevin Wolf         error_setg(errp, "Job is already paused");
761b15de828SKevin Wolf         return;
762b15de828SKevin Wolf     }
763b15de828SKevin Wolf     job->user_paused = true;
764afe1e8a7SEmanuele Giuseppe Esposito     job_pause_locked(job);
765b15de828SKevin Wolf }
766b15de828SKevin Wolf 
767afe1e8a7SEmanuele Giuseppe Esposito void job_user_pause(Job *job, Error **errp)
768afe1e8a7SEmanuele Giuseppe Esposito {
769afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
770afe1e8a7SEmanuele Giuseppe Esposito     job_user_pause_locked(job, errp);
771afe1e8a7SEmanuele Giuseppe Esposito }
772afe1e8a7SEmanuele Giuseppe Esposito 
773afe1e8a7SEmanuele Giuseppe Esposito bool job_user_paused_locked(Job *job)
774b15de828SKevin Wolf {
775b15de828SKevin Wolf     return job->user_paused;
776b15de828SKevin Wolf }
777b15de828SKevin Wolf 
778afe1e8a7SEmanuele Giuseppe Esposito bool job_user_paused(Job *job)
779afe1e8a7SEmanuele Giuseppe Esposito {
780afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
781afe1e8a7SEmanuele Giuseppe Esposito     return job_user_paused_locked(job);
782afe1e8a7SEmanuele Giuseppe Esposito }
783afe1e8a7SEmanuele Giuseppe Esposito 
784afe1e8a7SEmanuele Giuseppe Esposito void job_user_resume_locked(Job *job, Error **errp)
785b15de828SKevin Wolf {
786b15de828SKevin Wolf     assert(job);
787c70b8031SEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
788b15de828SKevin Wolf     if (!job->user_paused || job->pause_count <= 0) {
789b15de828SKevin Wolf         error_setg(errp, "Can't resume a job that was not paused");
790b15de828SKevin Wolf         return;
791b15de828SKevin Wolf     }
792afe1e8a7SEmanuele Giuseppe Esposito     if (job_apply_verb_locked(job, JOB_VERB_RESUME, errp)) {
793b15de828SKevin Wolf         return;
794b15de828SKevin Wolf     }
795b15de828SKevin Wolf     if (job->driver->user_resume) {
796afe1e8a7SEmanuele Giuseppe Esposito         job_unlock();
797b15de828SKevin Wolf         job->driver->user_resume(job);
798afe1e8a7SEmanuele Giuseppe Esposito         job_lock();
799b15de828SKevin Wolf     }
800b15de828SKevin Wolf     job->user_paused = false;
801afe1e8a7SEmanuele Giuseppe Esposito     job_resume_locked(job);
802b15de828SKevin Wolf }
803b15de828SKevin Wolf 
804afe1e8a7SEmanuele Giuseppe Esposito void job_user_resume(Job *job, Error **errp)
805afe1e8a7SEmanuele Giuseppe Esposito {
806afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
807afe1e8a7SEmanuele Giuseppe Esposito     job_user_resume_locked(job, errp);
808afe1e8a7SEmanuele Giuseppe Esposito }
809afe1e8a7SEmanuele Giuseppe Esposito 
810afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held, but releases it temporarily. */
811afe1e8a7SEmanuele Giuseppe Esposito static void job_do_dismiss_locked(Job *job)
8124ad35181SKevin Wolf {
8134ad35181SKevin Wolf     assert(job);
8144ad35181SKevin Wolf     job->busy = false;
8154ad35181SKevin Wolf     job->paused = false;
8164ad35181SKevin Wolf     job->deferred_to_main_loop = true;
8174ad35181SKevin Wolf 
818afe1e8a7SEmanuele Giuseppe Esposito     job_txn_del_job_locked(job);
8194ad35181SKevin Wolf 
820afe1e8a7SEmanuele Giuseppe Esposito     job_state_transition_locked(job, JOB_STATUS_NULL);
821afe1e8a7SEmanuele Giuseppe Esposito     job_unref_locked(job);
8224ad35181SKevin Wolf }
8234ad35181SKevin Wolf 
824afe1e8a7SEmanuele Giuseppe Esposito void job_dismiss_locked(Job **jobptr, Error **errp)
8255f9a6a08SKevin Wolf {
8265f9a6a08SKevin Wolf     Job *job = *jobptr;
8275f9a6a08SKevin Wolf     /* similarly to _complete, this is QMP-interface only. */
8285f9a6a08SKevin Wolf     assert(job->id);
829afe1e8a7SEmanuele Giuseppe Esposito     if (job_apply_verb_locked(job, JOB_VERB_DISMISS, errp)) {
8305f9a6a08SKevin Wolf         return;
8315f9a6a08SKevin Wolf     }
8325f9a6a08SKevin Wolf 
833afe1e8a7SEmanuele Giuseppe Esposito     job_do_dismiss_locked(job);
8345f9a6a08SKevin Wolf     *jobptr = NULL;
8355f9a6a08SKevin Wolf }
8365f9a6a08SKevin Wolf 
837afe1e8a7SEmanuele Giuseppe Esposito void job_dismiss(Job **jobptr, Error **errp)
838afe1e8a7SEmanuele Giuseppe Esposito {
839afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
840afe1e8a7SEmanuele Giuseppe Esposito     job_dismiss_locked(jobptr, errp);
841afe1e8a7SEmanuele Giuseppe Esposito }
842afe1e8a7SEmanuele Giuseppe Esposito 
8434ad35181SKevin Wolf void job_early_fail(Job *job)
8444ad35181SKevin Wolf {
845afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
8464ad35181SKevin Wolf     assert(job->status == JOB_STATUS_CREATED);
847afe1e8a7SEmanuele Giuseppe Esposito     job_do_dismiss_locked(job);
8484ad35181SKevin Wolf }
8494ad35181SKevin Wolf 
850afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
851afe1e8a7SEmanuele Giuseppe Esposito static void job_conclude_locked(Job *job)
8524ad35181SKevin Wolf {
853afe1e8a7SEmanuele Giuseppe Esposito     job_state_transition_locked(job, JOB_STATUS_CONCLUDED);
854afe1e8a7SEmanuele Giuseppe Esposito     if (job->auto_dismiss || !job_started_locked(job)) {
855afe1e8a7SEmanuele Giuseppe Esposito         job_do_dismiss_locked(job);
8564ad35181SKevin Wolf     }
8574ad35181SKevin Wolf }
8584ad35181SKevin Wolf 
859afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
860afe1e8a7SEmanuele Giuseppe Esposito static void job_update_rc_locked(Job *job)
8614ad35181SKevin Wolf {
862afe1e8a7SEmanuele Giuseppe Esposito     if (!job->ret && job_is_cancelled_locked(job)) {
8634ad35181SKevin Wolf         job->ret = -ECANCELED;
8644ad35181SKevin Wolf     }
8654ad35181SKevin Wolf     if (job->ret) {
8663d1f8b07SJohn Snow         if (!job->err) {
8673d1f8b07SJohn Snow             error_setg(&job->err, "%s", strerror(-job->ret));
8681266c9b9SKevin Wolf         }
869afe1e8a7SEmanuele Giuseppe Esposito         job_state_transition_locked(job, JOB_STATUS_ABORTING);
8704ad35181SKevin Wolf     }
8714ad35181SKevin Wolf }
8724ad35181SKevin Wolf 
8734ad35181SKevin Wolf static void job_commit(Job *job)
8744ad35181SKevin Wolf {
8754ad35181SKevin Wolf     assert(!job->ret);
876c70b8031SEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
8774ad35181SKevin Wolf     if (job->driver->commit) {
8784ad35181SKevin Wolf         job->driver->commit(job);
8794ad35181SKevin Wolf     }
8804ad35181SKevin Wolf }
8814ad35181SKevin Wolf 
8824ad35181SKevin Wolf static void job_abort(Job *job)
8834ad35181SKevin Wolf {
8844ad35181SKevin Wolf     assert(job->ret);
885c70b8031SEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
8864ad35181SKevin Wolf     if (job->driver->abort) {
8874ad35181SKevin Wolf         job->driver->abort(job);
8884ad35181SKevin Wolf     }
8894ad35181SKevin Wolf }
8904ad35181SKevin Wolf 
8914ad35181SKevin Wolf static void job_clean(Job *job)
8924ad35181SKevin Wolf {
893c70b8031SEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
8944ad35181SKevin Wolf     if (job->driver->clean) {
8954ad35181SKevin Wolf         job->driver->clean(job);
8964ad35181SKevin Wolf     }
8974ad35181SKevin Wolf }
8984ad35181SKevin Wolf 
8996f592e5aSEmanuele Giuseppe Esposito /*
9006f592e5aSEmanuele Giuseppe Esposito  * Called with job_mutex held, but releases it temporarily.
9016f592e5aSEmanuele Giuseppe Esposito  * Takes AioContext lock internally to invoke a job->driver callback.
9026f592e5aSEmanuele Giuseppe Esposito  */
903afe1e8a7SEmanuele Giuseppe Esposito static int job_finalize_single_locked(Job *job)
9044ad35181SKevin Wolf {
905afe1e8a7SEmanuele Giuseppe Esposito     int job_ret;
9066f592e5aSEmanuele Giuseppe Esposito     AioContext *ctx = job->aio_context;
907afe1e8a7SEmanuele Giuseppe Esposito 
908afe1e8a7SEmanuele Giuseppe Esposito     assert(job_is_completed_locked(job));
9094ad35181SKevin Wolf 
9104ad35181SKevin Wolf     /* Ensure abort is called for late-transactional failures */
911afe1e8a7SEmanuele Giuseppe Esposito     job_update_rc_locked(job);
9124ad35181SKevin Wolf 
913afe1e8a7SEmanuele Giuseppe Esposito     job_ret = job->ret;
914afe1e8a7SEmanuele Giuseppe Esposito     job_unlock();
9156f592e5aSEmanuele Giuseppe Esposito     aio_context_acquire(ctx);
916afe1e8a7SEmanuele Giuseppe Esposito 
917afe1e8a7SEmanuele Giuseppe Esposito     if (!job_ret) {
9184ad35181SKevin Wolf         job_commit(job);
9194ad35181SKevin Wolf     } else {
9204ad35181SKevin Wolf         job_abort(job);
9214ad35181SKevin Wolf     }
9224ad35181SKevin Wolf     job_clean(job);
9234ad35181SKevin Wolf 
9244ad35181SKevin Wolf     if (job->cb) {
925afe1e8a7SEmanuele Giuseppe Esposito         job->cb(job->opaque, job_ret);
9264ad35181SKevin Wolf     }
9274ad35181SKevin Wolf 
9286f592e5aSEmanuele Giuseppe Esposito     aio_context_release(ctx);
9296f592e5aSEmanuele Giuseppe Esposito     job_lock();
9306f592e5aSEmanuele Giuseppe Esposito 
9314ad35181SKevin Wolf     /* Emit events only if we actually started */
932afe1e8a7SEmanuele Giuseppe Esposito     if (job_started_locked(job)) {
933afe1e8a7SEmanuele Giuseppe Esposito         if (job_is_cancelled_locked(job)) {
934afe1e8a7SEmanuele Giuseppe Esposito             job_event_cancelled_locked(job);
9354ad35181SKevin Wolf         } else {
936afe1e8a7SEmanuele Giuseppe Esposito             job_event_completed_locked(job);
9374ad35181SKevin Wolf         }
9384ad35181SKevin Wolf     }
9394ad35181SKevin Wolf 
940afe1e8a7SEmanuele Giuseppe Esposito     job_txn_del_job_locked(job);
941afe1e8a7SEmanuele Giuseppe Esposito     job_conclude_locked(job);
9424ad35181SKevin Wolf     return 0;
9434ad35181SKevin Wolf }
9444ad35181SKevin Wolf 
9456f592e5aSEmanuele Giuseppe Esposito /*
9466f592e5aSEmanuele Giuseppe Esposito  * Called with job_mutex held, but releases it temporarily.
9476f592e5aSEmanuele Giuseppe Esposito  * Takes AioContext lock internally to invoke a job->driver callback.
9486f592e5aSEmanuele Giuseppe Esposito  */
949afe1e8a7SEmanuele Giuseppe Esposito static void job_cancel_async_locked(Job *job, bool force)
9507eaa8fb5SKevin Wolf {
9516f592e5aSEmanuele Giuseppe Esposito     AioContext *ctx = job->aio_context;
952c70b8031SEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
9539820933bSVladimir Sementsov-Ogievskiy     if (job->driver->cancel) {
954afe1e8a7SEmanuele Giuseppe Esposito         job_unlock();
9556f592e5aSEmanuele Giuseppe Esposito         aio_context_acquire(ctx);
95673895f38SHanna Reitz         force = job->driver->cancel(job, force);
9576f592e5aSEmanuele Giuseppe Esposito         aio_context_release(ctx);
958afe1e8a7SEmanuele Giuseppe Esposito         job_lock();
95973895f38SHanna Reitz     } else {
96073895f38SHanna Reitz         /* No .cancel() means the job will behave as if force-cancelled */
96173895f38SHanna Reitz         force = true;
9629820933bSVladimir Sementsov-Ogievskiy     }
96373895f38SHanna Reitz 
9647eaa8fb5SKevin Wolf     if (job->user_paused) {
9657eaa8fb5SKevin Wolf         /* Do not call job_enter here, the caller will handle it.  */
9667eaa8fb5SKevin Wolf         if (job->driver->user_resume) {
967afe1e8a7SEmanuele Giuseppe Esposito             job_unlock();
9687eaa8fb5SKevin Wolf             job->driver->user_resume(job);
969afe1e8a7SEmanuele Giuseppe Esposito             job_lock();
9707eaa8fb5SKevin Wolf         }
971e321c059SJeff Cody         job->user_paused = false;
9727eaa8fb5SKevin Wolf         assert(job->pause_count > 0);
9737eaa8fb5SKevin Wolf         job->pause_count--;
9747eaa8fb5SKevin Wolf     }
975401dd096SHanna Reitz 
976401dd096SHanna Reitz     /*
977401dd096SHanna Reitz      * Ignore soft cancel requests after the job is already done
978401dd096SHanna Reitz      * (We will still invoke job->driver->cancel() above, but if the
979401dd096SHanna Reitz      * job driver supports soft cancelling and the job is done, that
980401dd096SHanna Reitz      * should be a no-op, too.  We still call it so it can override
981401dd096SHanna Reitz      * @force.)
982401dd096SHanna Reitz      */
983401dd096SHanna Reitz     if (force || !job->deferred_to_main_loop) {
9847eaa8fb5SKevin Wolf         job->cancelled = true;
9857eaa8fb5SKevin Wolf         /* To prevent 'force == false' overriding a previous 'force == true' */
9867eaa8fb5SKevin Wolf         job->force_cancel |= force;
9877eaa8fb5SKevin Wolf     }
988401dd096SHanna Reitz }
9897eaa8fb5SKevin Wolf 
9906f592e5aSEmanuele Giuseppe Esposito /*
9916f592e5aSEmanuele Giuseppe Esposito  * Called with job_mutex held, but releases it temporarily.
9926f592e5aSEmanuele Giuseppe Esposito  * Takes AioContext lock internally to invoke a job->driver callback.
9936f592e5aSEmanuele Giuseppe Esposito  */
994afe1e8a7SEmanuele Giuseppe Esposito static void job_completed_txn_abort_locked(Job *job)
9957eaa8fb5SKevin Wolf {
9967eaa8fb5SKevin Wolf     JobTxn *txn = job->txn;
9977eaa8fb5SKevin Wolf     Job *other_job;
9987eaa8fb5SKevin Wolf 
9997eaa8fb5SKevin Wolf     if (txn->aborting) {
10007eaa8fb5SKevin Wolf         /*
10017eaa8fb5SKevin Wolf          * We are cancelled by another job, which will handle everything.
10027eaa8fb5SKevin Wolf          */
10037eaa8fb5SKevin Wolf         return;
10047eaa8fb5SKevin Wolf     }
10057eaa8fb5SKevin Wolf     txn->aborting = true;
1006afe1e8a7SEmanuele Giuseppe Esposito     job_txn_ref_locked(txn);
10077eaa8fb5SKevin Wolf 
1008afe1e8a7SEmanuele Giuseppe Esposito     job_ref_locked(job);
10097eaa8fb5SKevin Wolf 
10107eaa8fb5SKevin Wolf     /* Other jobs are effectively cancelled by us, set the status for
10117eaa8fb5SKevin Wolf      * them; this job, however, may or may not be cancelled, depending
10127eaa8fb5SKevin Wolf      * on the caller, so leave it. */
10137eaa8fb5SKevin Wolf     QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
10147eaa8fb5SKevin Wolf         if (other_job != job) {
10151d4a43e9SHanna Reitz             /*
10161d4a43e9SHanna Reitz              * This is a transaction: If one job failed, no result will matter.
10171d4a43e9SHanna Reitz              * Therefore, pass force=true to terminate all other jobs as quickly
10181d4a43e9SHanna Reitz              * as possible.
10191d4a43e9SHanna Reitz              */
1020afe1e8a7SEmanuele Giuseppe Esposito             job_cancel_async_locked(other_job, true);
10217eaa8fb5SKevin Wolf         }
10227eaa8fb5SKevin Wolf     }
10237eaa8fb5SKevin Wolf     while (!QLIST_EMPTY(&txn->jobs)) {
10247eaa8fb5SKevin Wolf         other_job = QLIST_FIRST(&txn->jobs);
1025afe1e8a7SEmanuele Giuseppe Esposito         if (!job_is_completed_locked(other_job)) {
1026afe1e8a7SEmanuele Giuseppe Esposito             assert(job_cancel_requested_locked(other_job));
1027afe1e8a7SEmanuele Giuseppe Esposito             job_finish_sync_locked(other_job, NULL, NULL);
10287eaa8fb5SKevin Wolf         }
1029afe1e8a7SEmanuele Giuseppe Esposito         job_finalize_single_locked(other_job);
10307eaa8fb5SKevin Wolf     }
10317eaa8fb5SKevin Wolf 
1032afe1e8a7SEmanuele Giuseppe Esposito     job_unref_locked(job);
1033afe1e8a7SEmanuele Giuseppe Esposito     job_txn_unref_locked(txn);
10347eaa8fb5SKevin Wolf }
10357eaa8fb5SKevin Wolf 
1036afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held, but releases it temporarily */
1037afe1e8a7SEmanuele Giuseppe Esposito static int job_prepare_locked(Job *job)
10387eaa8fb5SKevin Wolf {
1039afe1e8a7SEmanuele Giuseppe Esposito     int ret;
10406f592e5aSEmanuele Giuseppe Esposito     AioContext *ctx = job->aio_context;
1041afe1e8a7SEmanuele Giuseppe Esposito 
1042c70b8031SEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
10436f592e5aSEmanuele Giuseppe Esposito 
10447eaa8fb5SKevin Wolf     if (job->ret == 0 && job->driver->prepare) {
1045afe1e8a7SEmanuele Giuseppe Esposito         job_unlock();
10466f592e5aSEmanuele Giuseppe Esposito         aio_context_acquire(ctx);
1047afe1e8a7SEmanuele Giuseppe Esposito         ret = job->driver->prepare(job);
10486f592e5aSEmanuele Giuseppe Esposito         aio_context_release(ctx);
1049afe1e8a7SEmanuele Giuseppe Esposito         job_lock();
1050afe1e8a7SEmanuele Giuseppe Esposito         job->ret = ret;
1051afe1e8a7SEmanuele Giuseppe Esposito         job_update_rc_locked(job);
10527eaa8fb5SKevin Wolf     }
10536f592e5aSEmanuele Giuseppe Esposito 
10547eaa8fb5SKevin Wolf     return job->ret;
10557eaa8fb5SKevin Wolf }
10567eaa8fb5SKevin Wolf 
1057afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held */
1058afe1e8a7SEmanuele Giuseppe Esposito static int job_needs_finalize_locked(Job *job)
10597eaa8fb5SKevin Wolf {
10607eaa8fb5SKevin Wolf     return !job->auto_finalize;
10617eaa8fb5SKevin Wolf }
10627eaa8fb5SKevin Wolf 
1063afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held */
1064afe1e8a7SEmanuele Giuseppe Esposito static void job_do_finalize_locked(Job *job)
10657eaa8fb5SKevin Wolf {
10667eaa8fb5SKevin Wolf     int rc;
10677eaa8fb5SKevin Wolf     assert(job && job->txn);
10687eaa8fb5SKevin Wolf 
10697eaa8fb5SKevin Wolf     /* prepare the transaction to complete */
1070afe1e8a7SEmanuele Giuseppe Esposito     rc = job_txn_apply_locked(job, job_prepare_locked);
10717eaa8fb5SKevin Wolf     if (rc) {
1072afe1e8a7SEmanuele Giuseppe Esposito         job_completed_txn_abort_locked(job);
10737eaa8fb5SKevin Wolf     } else {
1074afe1e8a7SEmanuele Giuseppe Esposito         job_txn_apply_locked(job, job_finalize_single_locked);
10757eaa8fb5SKevin Wolf     }
10767eaa8fb5SKevin Wolf }
10777eaa8fb5SKevin Wolf 
1078afe1e8a7SEmanuele Giuseppe Esposito void job_finalize_locked(Job *job, Error **errp)
1079afe1e8a7SEmanuele Giuseppe Esposito {
1080afe1e8a7SEmanuele Giuseppe Esposito     assert(job && job->id);
1081afe1e8a7SEmanuele Giuseppe Esposito     if (job_apply_verb_locked(job, JOB_VERB_FINALIZE, errp)) {
1082afe1e8a7SEmanuele Giuseppe Esposito         return;
1083afe1e8a7SEmanuele Giuseppe Esposito     }
1084afe1e8a7SEmanuele Giuseppe Esposito     job_do_finalize_locked(job);
1085afe1e8a7SEmanuele Giuseppe Esposito }
1086afe1e8a7SEmanuele Giuseppe Esposito 
10877eaa8fb5SKevin Wolf void job_finalize(Job *job, Error **errp)
10887eaa8fb5SKevin Wolf {
1089afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
1090afe1e8a7SEmanuele Giuseppe Esposito     job_finalize_locked(job, errp);
10917eaa8fb5SKevin Wolf }
10927eaa8fb5SKevin Wolf 
1093afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
1094afe1e8a7SEmanuele Giuseppe Esposito static int job_transition_to_pending_locked(Job *job)
10957eaa8fb5SKevin Wolf {
1096afe1e8a7SEmanuele Giuseppe Esposito     job_state_transition_locked(job, JOB_STATUS_PENDING);
10977eaa8fb5SKevin Wolf     if (!job->auto_finalize) {
1098afe1e8a7SEmanuele Giuseppe Esposito         job_event_pending_locked(job);
10997eaa8fb5SKevin Wolf     }
11007eaa8fb5SKevin Wolf     return 0;
11017eaa8fb5SKevin Wolf }
11027eaa8fb5SKevin Wolf 
11032e1795b5SKevin Wolf void job_transition_to_ready(Job *job)
11042e1795b5SKevin Wolf {
1105afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
1106afe1e8a7SEmanuele Giuseppe Esposito     job_state_transition_locked(job, JOB_STATUS_READY);
1107afe1e8a7SEmanuele Giuseppe Esposito     job_event_ready_locked(job);
11082e1795b5SKevin Wolf }
11092e1795b5SKevin Wolf 
1110afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
1111afe1e8a7SEmanuele Giuseppe Esposito static void job_completed_txn_success_locked(Job *job)
11127eaa8fb5SKevin Wolf {
11137eaa8fb5SKevin Wolf     JobTxn *txn = job->txn;
11147eaa8fb5SKevin Wolf     Job *other_job;
11157eaa8fb5SKevin Wolf 
1116afe1e8a7SEmanuele Giuseppe Esposito     job_state_transition_locked(job, JOB_STATUS_WAITING);
11177eaa8fb5SKevin Wolf 
11187eaa8fb5SKevin Wolf     /*
11197eaa8fb5SKevin Wolf      * Successful completion, see if there are other running jobs in this
11207eaa8fb5SKevin Wolf      * txn.
11217eaa8fb5SKevin Wolf      */
11227eaa8fb5SKevin Wolf     QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
1123afe1e8a7SEmanuele Giuseppe Esposito         if (!job_is_completed_locked(other_job)) {
11247eaa8fb5SKevin Wolf             return;
11257eaa8fb5SKevin Wolf         }
11267eaa8fb5SKevin Wolf         assert(other_job->ret == 0);
11277eaa8fb5SKevin Wolf     }
11287eaa8fb5SKevin Wolf 
1129afe1e8a7SEmanuele Giuseppe Esposito     job_txn_apply_locked(job, job_transition_to_pending_locked);
11307eaa8fb5SKevin Wolf 
11317eaa8fb5SKevin Wolf     /* If no jobs need manual finalization, automatically do so */
1132afe1e8a7SEmanuele Giuseppe Esposito     if (job_txn_apply_locked(job, job_needs_finalize_locked) == 0) {
1133afe1e8a7SEmanuele Giuseppe Esposito         job_do_finalize_locked(job);
11347eaa8fb5SKevin Wolf     }
11357eaa8fb5SKevin Wolf }
11367eaa8fb5SKevin Wolf 
1137afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */
1138afe1e8a7SEmanuele Giuseppe Esposito static void job_completed_locked(Job *job)
11393d70ff53SKevin Wolf {
1140afe1e8a7SEmanuele Giuseppe Esposito     assert(job && job->txn && !job_is_completed_locked(job));
11411266c9b9SKevin Wolf 
1142afe1e8a7SEmanuele Giuseppe Esposito     job_update_rc_locked(job);
1143404ff28dSJohn Snow     trace_job_completed(job, job->ret);
11443d70ff53SKevin Wolf     if (job->ret) {
1145afe1e8a7SEmanuele Giuseppe Esposito         job_completed_txn_abort_locked(job);
11463d70ff53SKevin Wolf     } else {
1147afe1e8a7SEmanuele Giuseppe Esposito         job_completed_txn_success_locked(job);
11483d70ff53SKevin Wolf     }
11493d70ff53SKevin Wolf }
11503d70ff53SKevin Wolf 
1151afe1e8a7SEmanuele Giuseppe Esposito /**
1152afe1e8a7SEmanuele Giuseppe Esposito  * Useful only as a type shim for aio_bh_schedule_oneshot.
1153afe1e8a7SEmanuele Giuseppe Esposito  * Called with job_mutex *not* held.
1154afe1e8a7SEmanuele Giuseppe Esposito  */
1155ccbfb331SJohn Snow static void job_exit(void *opaque)
1156ccbfb331SJohn Snow {
1157ccbfb331SJohn Snow     Job *job = (Job *)opaque;
1158afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
1159afe1e8a7SEmanuele Giuseppe Esposito     job_ref_locked(job);
1160b5a7a057SKevin Wolf 
1161b5a7a057SKevin Wolf     /* This is a lie, we're not quiescent, but still doing the completion
1162b5a7a057SKevin Wolf      * callbacks. However, completion callbacks tend to involve operations that
1163b5a7a057SKevin Wolf      * drain block nodes, and if .drained_poll still returned true, we would
1164b5a7a057SKevin Wolf      * deadlock. */
1165b5a7a057SKevin Wolf     job->busy = false;
1166afe1e8a7SEmanuele Giuseppe Esposito     job_event_idle_locked(job);
1167b5a7a057SKevin Wolf 
1168afe1e8a7SEmanuele Giuseppe Esposito     job_completed_locked(job);
1169afe1e8a7SEmanuele Giuseppe Esposito     job_unref_locked(job);
1170ccbfb331SJohn Snow }
1171ccbfb331SJohn Snow 
1172ccbfb331SJohn Snow /**
1173ccbfb331SJohn Snow  * All jobs must allow a pause point before entering their job proper. This
1174ccbfb331SJohn Snow  * ensures that jobs can be paused prior to being started, then resumed later.
1175ccbfb331SJohn Snow  */
1176ccbfb331SJohn Snow static void coroutine_fn job_co_entry(void *opaque)
1177ccbfb331SJohn Snow {
1178ccbfb331SJohn Snow     Job *job = opaque;
1179afe1e8a7SEmanuele Giuseppe Esposito     int ret;
1180ccbfb331SJohn Snow 
1181ccbfb331SJohn Snow     assert(job && job->driver && job->driver->run);
1182afe1e8a7SEmanuele Giuseppe Esposito     WITH_JOB_LOCK_GUARD() {
1183c70b8031SEmanuele Giuseppe Esposito         assert(job->aio_context == qemu_get_current_aio_context());
1184afe1e8a7SEmanuele Giuseppe Esposito         job_pause_point_locked(job);
1185afe1e8a7SEmanuele Giuseppe Esposito     }
1186afe1e8a7SEmanuele Giuseppe Esposito     ret = job->driver->run(job, &job->err);
1187afe1e8a7SEmanuele Giuseppe Esposito     WITH_JOB_LOCK_GUARD() {
1188afe1e8a7SEmanuele Giuseppe Esposito         job->ret = ret;
1189ccbfb331SJohn Snow         job->deferred_to_main_loop = true;
1190b5a7a057SKevin Wolf         job->busy = true;
1191afe1e8a7SEmanuele Giuseppe Esposito     }
1192ccbfb331SJohn Snow     aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job);
1193ccbfb331SJohn Snow }
1194ccbfb331SJohn Snow 
1195ccbfb331SJohn Snow void job_start(Job *job)
1196ccbfb331SJohn Snow {
1197afe1e8a7SEmanuele Giuseppe Esposito     assert(qemu_in_main_thread());
1198afe1e8a7SEmanuele Giuseppe Esposito 
1199afe1e8a7SEmanuele Giuseppe Esposito     WITH_JOB_LOCK_GUARD() {
1200afe1e8a7SEmanuele Giuseppe Esposito         assert(job && !job_started_locked(job) && job->paused &&
1201ccbfb331SJohn Snow             job->driver && job->driver->run);
1202ccbfb331SJohn Snow         job->co = qemu_coroutine_create(job_co_entry, job);
1203ccbfb331SJohn Snow         job->pause_count--;
1204ccbfb331SJohn Snow         job->busy = true;
1205ccbfb331SJohn Snow         job->paused = false;
1206afe1e8a7SEmanuele Giuseppe Esposito         job_state_transition_locked(job, JOB_STATUS_RUNNING);
1207afe1e8a7SEmanuele Giuseppe Esposito     }
1208ccbfb331SJohn Snow     aio_co_enter(job->aio_context, job->co);
1209ccbfb331SJohn Snow }
1210ccbfb331SJohn Snow 
1211afe1e8a7SEmanuele Giuseppe Esposito void job_cancel_locked(Job *job, bool force)
12123d70ff53SKevin Wolf {
12133d70ff53SKevin Wolf     if (job->status == JOB_STATUS_CONCLUDED) {
1214afe1e8a7SEmanuele Giuseppe Esposito         job_do_dismiss_locked(job);
12153d70ff53SKevin Wolf         return;
12163d70ff53SKevin Wolf     }
1217afe1e8a7SEmanuele Giuseppe Esposito     job_cancel_async_locked(job, force);
1218afe1e8a7SEmanuele Giuseppe Esposito     if (!job_started_locked(job)) {
1219afe1e8a7SEmanuele Giuseppe Esposito         job_completed_locked(job);
12203d70ff53SKevin Wolf     } else if (job->deferred_to_main_loop) {
1221401dd096SHanna Reitz         /*
1222401dd096SHanna Reitz          * job_cancel_async() ignores soft-cancel requests for jobs
1223401dd096SHanna Reitz          * that are already done (i.e. deferred to the main loop).  We
1224401dd096SHanna Reitz          * have to check again whether the job is really cancelled.
122508b83bffSHanna Reitz          * (job_cancel_requested() and job_is_cancelled() are equivalent
122608b83bffSHanna Reitz          * here, because job_cancel_async() will make soft-cancel
122708b83bffSHanna Reitz          * requests no-ops when deferred_to_main_loop is true.  We
122808b83bffSHanna Reitz          * choose to call job_is_cancelled() to show that we invoke
122908b83bffSHanna Reitz          * job_completed_txn_abort() only for force-cancelled jobs.)
1230401dd096SHanna Reitz          */
1231afe1e8a7SEmanuele Giuseppe Esposito         if (job_is_cancelled_locked(job)) {
1232afe1e8a7SEmanuele Giuseppe Esposito             job_completed_txn_abort_locked(job);
1233401dd096SHanna Reitz         }
12343d70ff53SKevin Wolf     } else {
1235afe1e8a7SEmanuele Giuseppe Esposito         job_enter_cond_locked(job, NULL);
12363d70ff53SKevin Wolf     }
12373d70ff53SKevin Wolf }
12383d70ff53SKevin Wolf 
1239afe1e8a7SEmanuele Giuseppe Esposito void job_cancel(Job *job, bool force)
1240afe1e8a7SEmanuele Giuseppe Esposito {
1241afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
1242afe1e8a7SEmanuele Giuseppe Esposito     job_cancel_locked(job, force);
1243afe1e8a7SEmanuele Giuseppe Esposito }
1244afe1e8a7SEmanuele Giuseppe Esposito 
1245afe1e8a7SEmanuele Giuseppe Esposito void job_user_cancel_locked(Job *job, bool force, Error **errp)
1246afe1e8a7SEmanuele Giuseppe Esposito {
1247afe1e8a7SEmanuele Giuseppe Esposito     if (job_apply_verb_locked(job, JOB_VERB_CANCEL, errp)) {
1248afe1e8a7SEmanuele Giuseppe Esposito         return;
1249afe1e8a7SEmanuele Giuseppe Esposito     }
1250afe1e8a7SEmanuele Giuseppe Esposito     job_cancel_locked(job, force);
1251afe1e8a7SEmanuele Giuseppe Esposito }
1252afe1e8a7SEmanuele Giuseppe Esposito 
12533d70ff53SKevin Wolf void job_user_cancel(Job *job, bool force, Error **errp)
12543d70ff53SKevin Wolf {
1255afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
1256afe1e8a7SEmanuele Giuseppe Esposito     job_user_cancel_locked(job, force, errp);
12573d70ff53SKevin Wolf }
12583d70ff53SKevin Wolf 
12593d70ff53SKevin Wolf /* A wrapper around job_cancel() taking an Error ** parameter so it may be
12603d70ff53SKevin Wolf  * used with job_finish_sync() without the need for (rather nasty) function
1261afe1e8a7SEmanuele Giuseppe Esposito  * pointer casts there.
1262afe1e8a7SEmanuele Giuseppe Esposito  *
1263afe1e8a7SEmanuele Giuseppe Esposito  * Called with job_mutex held.
1264afe1e8a7SEmanuele Giuseppe Esposito  */
1265afe1e8a7SEmanuele Giuseppe Esposito static void job_cancel_err_locked(Job *job, Error **errp)
12663d70ff53SKevin Wolf {
1267afe1e8a7SEmanuele Giuseppe Esposito     job_cancel_locked(job, false);
12683d70ff53SKevin Wolf }
12693d70ff53SKevin Wolf 
12704cfb3f05SHanna Reitz /**
12714cfb3f05SHanna Reitz  * Same as job_cancel_err(), but force-cancel.
1272afe1e8a7SEmanuele Giuseppe Esposito  * Called with job_mutex held.
12734cfb3f05SHanna Reitz  */
1274afe1e8a7SEmanuele Giuseppe Esposito static void job_force_cancel_err_locked(Job *job, Error **errp)
12753d70ff53SKevin Wolf {
1276afe1e8a7SEmanuele Giuseppe Esposito     job_cancel_locked(job, true);
1277afe1e8a7SEmanuele Giuseppe Esposito }
1278afe1e8a7SEmanuele Giuseppe Esposito 
1279afe1e8a7SEmanuele Giuseppe Esposito int job_cancel_sync_locked(Job *job, bool force)
1280afe1e8a7SEmanuele Giuseppe Esposito {
1281afe1e8a7SEmanuele Giuseppe Esposito     if (force) {
1282afe1e8a7SEmanuele Giuseppe Esposito         return job_finish_sync_locked(job, &job_force_cancel_err_locked, NULL);
1283afe1e8a7SEmanuele Giuseppe Esposito     } else {
1284afe1e8a7SEmanuele Giuseppe Esposito         return job_finish_sync_locked(job, &job_cancel_err_locked, NULL);
1285afe1e8a7SEmanuele Giuseppe Esposito     }
12864cfb3f05SHanna Reitz }
12874cfb3f05SHanna Reitz 
12884cfb3f05SHanna Reitz int job_cancel_sync(Job *job, bool force)
12894cfb3f05SHanna Reitz {
1290afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
1291afe1e8a7SEmanuele Giuseppe Esposito     return job_cancel_sync_locked(job, force);
12924cfb3f05SHanna Reitz }
12933d70ff53SKevin Wolf 
12943d70ff53SKevin Wolf void job_cancel_sync_all(void)
12953d70ff53SKevin Wolf {
12963d70ff53SKevin Wolf     Job *job;
1297afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
12983d70ff53SKevin Wolf 
1299afe1e8a7SEmanuele Giuseppe Esposito     while ((job = job_next_locked(NULL))) {
1300afe1e8a7SEmanuele Giuseppe Esposito         job_cancel_sync_locked(job, true);
13013d70ff53SKevin Wolf     }
13023d70ff53SKevin Wolf }
13033d70ff53SKevin Wolf 
1304afe1e8a7SEmanuele Giuseppe Esposito int job_complete_sync_locked(Job *job, Error **errp)
13053d70ff53SKevin Wolf {
1306afe1e8a7SEmanuele Giuseppe Esposito     return job_finish_sync_locked(job, job_complete_locked, errp);
13073d70ff53SKevin Wolf }
13083d70ff53SKevin Wolf 
1309afe1e8a7SEmanuele Giuseppe Esposito int job_complete_sync(Job *job, Error **errp)
1310afe1e8a7SEmanuele Giuseppe Esposito {
1311afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
1312afe1e8a7SEmanuele Giuseppe Esposito     return job_complete_sync_locked(job, errp);
1313afe1e8a7SEmanuele Giuseppe Esposito }
1314afe1e8a7SEmanuele Giuseppe Esposito 
1315afe1e8a7SEmanuele Giuseppe Esposito void job_complete_locked(Job *job, Error **errp)
13163453d972SKevin Wolf {
13173453d972SKevin Wolf     /* Should not be reachable via external interface for internal jobs */
13183453d972SKevin Wolf     assert(job->id);
1319c70b8031SEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
1320afe1e8a7SEmanuele Giuseppe Esposito     if (job_apply_verb_locked(job, JOB_VERB_COMPLETE, errp)) {
13213453d972SKevin Wolf         return;
13223453d972SKevin Wolf     }
1323afe1e8a7SEmanuele Giuseppe Esposito     if (job_cancel_requested_locked(job) || !job->driver->complete) {
13243453d972SKevin Wolf         error_setg(errp, "The active block job '%s' cannot be completed",
13253453d972SKevin Wolf                    job->id);
13263453d972SKevin Wolf         return;
13273453d972SKevin Wolf     }
13283453d972SKevin Wolf 
1329afe1e8a7SEmanuele Giuseppe Esposito     job_unlock();
13303453d972SKevin Wolf     job->driver->complete(job, errp);
1331afe1e8a7SEmanuele Giuseppe Esposito     job_lock();
13323453d972SKevin Wolf }
13333453d972SKevin Wolf 
1334afe1e8a7SEmanuele Giuseppe Esposito void job_complete(Job *job, Error **errp)
1335afe1e8a7SEmanuele Giuseppe Esposito {
1336afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
1337afe1e8a7SEmanuele Giuseppe Esposito     job_complete_locked(job, errp);
1338afe1e8a7SEmanuele Giuseppe Esposito }
1339afe1e8a7SEmanuele Giuseppe Esposito 
1340afe1e8a7SEmanuele Giuseppe Esposito int job_finish_sync_locked(Job *job,
1341afe1e8a7SEmanuele Giuseppe Esposito                            void (*finish)(Job *, Error **errp),
1342afe1e8a7SEmanuele Giuseppe Esposito                            Error **errp)
13436a74c075SKevin Wolf {
13446a74c075SKevin Wolf     Error *local_err = NULL;
13456a74c075SKevin Wolf     int ret;
13463ed4f708SEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
13476a74c075SKevin Wolf 
1348afe1e8a7SEmanuele Giuseppe Esposito     job_ref_locked(job);
13496a74c075SKevin Wolf 
13506a74c075SKevin Wolf     if (finish) {
13516a74c075SKevin Wolf         finish(job, &local_err);
13526a74c075SKevin Wolf     }
13536a74c075SKevin Wolf     if (local_err) {
13546a74c075SKevin Wolf         error_propagate(errp, local_err);
1355afe1e8a7SEmanuele Giuseppe Esposito         job_unref_locked(job);
13566a74c075SKevin Wolf         return -EBUSY;
13576a74c075SKevin Wolf     }
1358de0fbe64SKevin Wolf 
1359afe1e8a7SEmanuele Giuseppe Esposito     job_unlock();
13606f592e5aSEmanuele Giuseppe Esposito     AIO_WAIT_WHILE_UNLOCKED(job->aio_context,
1361bb0c9409SVladimir Sementsov-Ogievskiy                             (job_enter(job), !job_is_completed(job)));
1362afe1e8a7SEmanuele Giuseppe Esposito     job_lock();
1363de0fbe64SKevin Wolf 
1364afe1e8a7SEmanuele Giuseppe Esposito     ret = (job_is_cancelled_locked(job) && job->ret == 0)
1365afe1e8a7SEmanuele Giuseppe Esposito           ? -ECANCELED : job->ret;
1366afe1e8a7SEmanuele Giuseppe Esposito     job_unref_locked(job);
13676a74c075SKevin Wolf     return ret;
13686a74c075SKevin Wolf }
1369afe1e8a7SEmanuele Giuseppe Esposito 
1370afe1e8a7SEmanuele Giuseppe Esposito int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp)
1371afe1e8a7SEmanuele Giuseppe Esposito {
1372afe1e8a7SEmanuele Giuseppe Esposito     JOB_LOCK_GUARD();
1373afe1e8a7SEmanuele Giuseppe Esposito     return job_finish_sync_locked(job, finish, errp);
1374afe1e8a7SEmanuele Giuseppe Esposito }
1375