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 * TODO Actually make this true 49bf61c583SEmanuele Giuseppe Esposito */ 50bf61c583SEmanuele Giuseppe Esposito 51bf61c583SEmanuele Giuseppe Esposito /* 5255c5a25aSEmanuele Giuseppe Esposito * job_mutex protects the jobs list, but also makes the 5355c5a25aSEmanuele Giuseppe Esposito * struct job fields thread-safe. 5455c5a25aSEmanuele Giuseppe Esposito */ 5555c5a25aSEmanuele Giuseppe Esposito QemuMutex job_mutex; 5655c5a25aSEmanuele Giuseppe Esposito 57afe1e8a7SEmanuele Giuseppe Esposito /* Protected by job_mutex */ 58e7c1d78bSKevin Wolf static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs); 59e7c1d78bSKevin Wolf 60a50c2ab8SKevin Wolf /* Job State Transition Table */ 61a50c2ab8SKevin Wolf bool JobSTT[JOB_STATUS__MAX][JOB_STATUS__MAX] = { 62a50c2ab8SKevin Wolf /* U, C, R, P, Y, S, W, D, X, E, N */ 63a50c2ab8SKevin Wolf /* U: */ [JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 64a50c2ab8SKevin Wolf /* C: */ [JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1}, 65a50c2ab8SKevin Wolf /* R: */ [JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0}, 66a50c2ab8SKevin Wolf /* P: */ [JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, 67a50c2ab8SKevin Wolf /* Y: */ [JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0}, 68a50c2ab8SKevin Wolf /* S: */ [JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, 69a50c2ab8SKevin Wolf /* W: */ [JOB_STATUS_WAITING] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, 70a50c2ab8SKevin Wolf /* D: */ [JOB_STATUS_PENDING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}, 71a50c2ab8SKevin Wolf /* X: */ [JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}, 72a50c2ab8SKevin Wolf /* E: */ [JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 73a50c2ab8SKevin Wolf /* N: */ [JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 74a50c2ab8SKevin Wolf }; 75a50c2ab8SKevin Wolf 76a50c2ab8SKevin Wolf bool JobVerbTable[JOB_VERB__MAX][JOB_STATUS__MAX] = { 77a50c2ab8SKevin Wolf /* U, C, R, P, Y, S, W, D, X, E, N */ 78a50c2ab8SKevin Wolf [JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}, 79a50c2ab8SKevin Wolf [JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, 80a50c2ab8SKevin Wolf [JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, 81a50c2ab8SKevin Wolf [JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, 8253ddb9c8SMax Reitz [JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, 83a50c2ab8SKevin Wolf [JOB_VERB_FINALIZE] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, 84a50c2ab8SKevin Wolf [JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, 85a50c2ab8SKevin Wolf }; 86a50c2ab8SKevin Wolf 877eaa8fb5SKevin Wolf /* Transactional group of jobs */ 887eaa8fb5SKevin Wolf struct JobTxn { 897eaa8fb5SKevin Wolf 907eaa8fb5SKevin Wolf /* Is this txn being cancelled? */ 917eaa8fb5SKevin Wolf bool aborting; 927eaa8fb5SKevin Wolf 937eaa8fb5SKevin Wolf /* List of jobs */ 947eaa8fb5SKevin Wolf QLIST_HEAD(, Job) jobs; 957eaa8fb5SKevin Wolf 967eaa8fb5SKevin Wolf /* Reference count */ 977eaa8fb5SKevin Wolf int refcnt; 987eaa8fb5SKevin Wolf }; 997eaa8fb5SKevin Wolf 10055c5a25aSEmanuele Giuseppe Esposito void job_lock(void) 10155c5a25aSEmanuele Giuseppe Esposito { 10255c5a25aSEmanuele Giuseppe Esposito /* nop */ 10355c5a25aSEmanuele Giuseppe Esposito } 104da01ff7fSKevin Wolf 10555c5a25aSEmanuele Giuseppe Esposito void job_unlock(void) 10655c5a25aSEmanuele Giuseppe Esposito { 10755c5a25aSEmanuele Giuseppe Esposito /* nop */ 10855c5a25aSEmanuele Giuseppe Esposito } 10955c5a25aSEmanuele Giuseppe Esposito 11055c5a25aSEmanuele Giuseppe Esposito static void real_job_lock(void) 111da01ff7fSKevin Wolf { 112da01ff7fSKevin Wolf qemu_mutex_lock(&job_mutex); 113da01ff7fSKevin Wolf } 114da01ff7fSKevin Wolf 11555c5a25aSEmanuele Giuseppe Esposito static void real_job_unlock(void) 116da01ff7fSKevin Wolf { 117da01ff7fSKevin Wolf qemu_mutex_unlock(&job_mutex); 118da01ff7fSKevin Wolf } 119da01ff7fSKevin Wolf 120da01ff7fSKevin Wolf static void __attribute__((__constructor__)) job_init(void) 121da01ff7fSKevin Wolf { 122da01ff7fSKevin Wolf qemu_mutex_init(&job_mutex); 123da01ff7fSKevin Wolf } 124da01ff7fSKevin Wolf 1257eaa8fb5SKevin Wolf JobTxn *job_txn_new(void) 1267eaa8fb5SKevin Wolf { 1277eaa8fb5SKevin Wolf JobTxn *txn = g_new0(JobTxn, 1); 1287eaa8fb5SKevin Wolf QLIST_INIT(&txn->jobs); 1297eaa8fb5SKevin Wolf txn->refcnt = 1; 1307eaa8fb5SKevin Wolf return txn; 1317eaa8fb5SKevin Wolf } 1327eaa8fb5SKevin Wolf 133afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 134afe1e8a7SEmanuele Giuseppe Esposito static void job_txn_ref_locked(JobTxn *txn) 1357eaa8fb5SKevin Wolf { 1367eaa8fb5SKevin Wolf txn->refcnt++; 1377eaa8fb5SKevin Wolf } 1387eaa8fb5SKevin Wolf 139afe1e8a7SEmanuele Giuseppe Esposito void job_txn_unref_locked(JobTxn *txn) 1407eaa8fb5SKevin Wolf { 1417eaa8fb5SKevin Wolf if (txn && --txn->refcnt == 0) { 1427eaa8fb5SKevin Wolf g_free(txn); 1437eaa8fb5SKevin Wolf } 1447eaa8fb5SKevin Wolf } 1457eaa8fb5SKevin Wolf 146afe1e8a7SEmanuele Giuseppe Esposito void job_txn_unref(JobTxn *txn) 147afe1e8a7SEmanuele Giuseppe Esposito { 148afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 149afe1e8a7SEmanuele Giuseppe Esposito job_txn_unref_locked(txn); 150afe1e8a7SEmanuele Giuseppe Esposito } 151afe1e8a7SEmanuele Giuseppe Esposito 152544f4d52SEmanuele Giuseppe Esposito /** 153544f4d52SEmanuele Giuseppe Esposito * @txn: The transaction (may be NULL) 154544f4d52SEmanuele Giuseppe Esposito * @job: Job to add to the transaction 155544f4d52SEmanuele Giuseppe Esposito * 156544f4d52SEmanuele Giuseppe Esposito * Add @job to the transaction. The @job must not already be in a transaction. 157544f4d52SEmanuele Giuseppe Esposito * The caller must call either job_txn_unref() or job_completed() to release 158544f4d52SEmanuele Giuseppe Esposito * the reference that is automatically grabbed here. 159544f4d52SEmanuele Giuseppe Esposito * 160544f4d52SEmanuele Giuseppe Esposito * If @txn is NULL, the function does nothing. 161afe1e8a7SEmanuele Giuseppe Esposito * 162afe1e8a7SEmanuele Giuseppe Esposito * Called with job_mutex held. 163544f4d52SEmanuele Giuseppe Esposito */ 164afe1e8a7SEmanuele Giuseppe Esposito static void job_txn_add_job_locked(JobTxn *txn, Job *job) 1657eaa8fb5SKevin Wolf { 1667eaa8fb5SKevin Wolf if (!txn) { 1677eaa8fb5SKevin Wolf return; 1687eaa8fb5SKevin Wolf } 1697eaa8fb5SKevin Wolf 1707eaa8fb5SKevin Wolf assert(!job->txn); 1717eaa8fb5SKevin Wolf job->txn = txn; 1727eaa8fb5SKevin Wolf 1737eaa8fb5SKevin Wolf QLIST_INSERT_HEAD(&txn->jobs, job, txn_list); 174afe1e8a7SEmanuele Giuseppe Esposito job_txn_ref_locked(txn); 1757eaa8fb5SKevin Wolf } 1767eaa8fb5SKevin Wolf 177afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 178afe1e8a7SEmanuele Giuseppe Esposito static void job_txn_del_job_locked(Job *job) 1797eaa8fb5SKevin Wolf { 1807eaa8fb5SKevin Wolf if (job->txn) { 1817eaa8fb5SKevin Wolf QLIST_REMOVE(job, txn_list); 182afe1e8a7SEmanuele Giuseppe Esposito job_txn_unref_locked(job->txn); 1837eaa8fb5SKevin Wolf job->txn = NULL; 1847eaa8fb5SKevin Wolf } 1857eaa8fb5SKevin Wolf } 1867eaa8fb5SKevin Wolf 187afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held, but releases it temporarily. */ 188afe1e8a7SEmanuele Giuseppe Esposito static int job_txn_apply_locked(Job *job, int fn(Job *)) 1897eaa8fb5SKevin Wolf { 190b660a84bSStefan Reiter AioContext *inner_ctx; 191b660a84bSStefan Reiter Job *other_job, *next; 192b660a84bSStefan Reiter JobTxn *txn = job->txn; 1937eaa8fb5SKevin Wolf int rc = 0; 1947eaa8fb5SKevin Wolf 195b660a84bSStefan Reiter /* 196b660a84bSStefan Reiter * Similar to job_completed_txn_abort, we take each job's lock before 197b660a84bSStefan Reiter * applying fn, but since we assume that outer_ctx is held by the caller, 198b660a84bSStefan Reiter * we need to release it here to avoid holding the lock twice - which would 199b660a84bSStefan Reiter * break AIO_WAIT_WHILE from within fn. 200b660a84bSStefan Reiter */ 201afe1e8a7SEmanuele Giuseppe Esposito job_ref_locked(job); 202b660a84bSStefan Reiter aio_context_release(job->aio_context); 203b660a84bSStefan Reiter 204b660a84bSStefan Reiter QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) { 205b660a84bSStefan Reiter inner_ctx = other_job->aio_context; 206b660a84bSStefan Reiter aio_context_acquire(inner_ctx); 207b660a84bSStefan Reiter rc = fn(other_job); 208b660a84bSStefan Reiter aio_context_release(inner_ctx); 2097eaa8fb5SKevin Wolf if (rc) { 2107eaa8fb5SKevin Wolf break; 2117eaa8fb5SKevin Wolf } 2127eaa8fb5SKevin Wolf } 213b660a84bSStefan Reiter 214b660a84bSStefan Reiter /* 215b660a84bSStefan Reiter * Note that job->aio_context might have been changed by calling fn, so we 216b660a84bSStefan Reiter * can't use a local variable to cache it. 217b660a84bSStefan Reiter */ 218b660a84bSStefan Reiter aio_context_acquire(job->aio_context); 219afe1e8a7SEmanuele Giuseppe Esposito job_unref_locked(job); 2207eaa8fb5SKevin Wolf return rc; 2217eaa8fb5SKevin Wolf } 2227eaa8fb5SKevin Wolf 223456273b0SKevin Wolf bool job_is_internal(Job *job) 2241dac83f1SKevin Wolf { 2251dac83f1SKevin Wolf return (job->id == NULL); 2261dac83f1SKevin Wolf } 2271dac83f1SKevin Wolf 228afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 229afe1e8a7SEmanuele Giuseppe Esposito static void job_state_transition_locked(Job *job, JobStatus s1) 230a50c2ab8SKevin Wolf { 231a50c2ab8SKevin Wolf JobStatus s0 = job->status; 232c2032289SLiam Merwick assert(s1 >= 0 && s1 < JOB_STATUS__MAX); 2334ad35181SKevin Wolf trace_job_state_transition(job, job->ret, 234a50c2ab8SKevin Wolf JobSTT[s0][s1] ? "allowed" : "disallowed", 235a50c2ab8SKevin Wolf JobStatus_str(s0), JobStatus_str(s1)); 236a50c2ab8SKevin Wolf assert(JobSTT[s0][s1]); 237a50c2ab8SKevin Wolf job->status = s1; 2381dac83f1SKevin Wolf 2391dac83f1SKevin Wolf if (!job_is_internal(job) && s1 != s0) { 2403ab72385SPeter Xu qapi_event_send_job_status_change(job->id, job->status); 2411dac83f1SKevin Wolf } 242a50c2ab8SKevin Wolf } 243a50c2ab8SKevin Wolf 244afe1e8a7SEmanuele Giuseppe Esposito int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp) 245a50c2ab8SKevin Wolf { 246a50c2ab8SKevin Wolf JobStatus s0 = job->status; 247c2032289SLiam Merwick assert(verb >= 0 && verb < JOB_VERB__MAX); 248a50c2ab8SKevin Wolf trace_job_apply_verb(job, JobStatus_str(s0), JobVerb_str(verb), 249a50c2ab8SKevin Wolf JobVerbTable[verb][s0] ? "allowed" : "prohibited"); 250a50c2ab8SKevin Wolf if (JobVerbTable[verb][s0]) { 251a50c2ab8SKevin Wolf return 0; 252a50c2ab8SKevin Wolf } 253a50c2ab8SKevin Wolf error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%s'", 254a50c2ab8SKevin Wolf job->id, JobStatus_str(s0), JobVerb_str(verb)); 255a50c2ab8SKevin Wolf return -EPERM; 256a50c2ab8SKevin Wolf } 257a50c2ab8SKevin Wolf 258afe1e8a7SEmanuele Giuseppe Esposito int job_apply_verb(Job *job, JobVerb verb, Error **errp) 259afe1e8a7SEmanuele Giuseppe Esposito { 260afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 261afe1e8a7SEmanuele Giuseppe Esposito return job_apply_verb_locked(job, verb, errp); 262afe1e8a7SEmanuele Giuseppe Esposito } 263afe1e8a7SEmanuele Giuseppe Esposito 264252291eaSKevin Wolf JobType job_type(const Job *job) 265252291eaSKevin Wolf { 266252291eaSKevin Wolf return job->driver->job_type; 267252291eaSKevin Wolf } 268252291eaSKevin Wolf 269252291eaSKevin Wolf const char *job_type_str(const Job *job) 270252291eaSKevin Wolf { 271252291eaSKevin Wolf return JobType_str(job_type(job)); 272252291eaSKevin Wolf } 273252291eaSKevin Wolf 274afe1e8a7SEmanuele Giuseppe Esposito bool job_is_cancelled_locked(Job *job) 275daa7f2f9SKevin Wolf { 276a640fa0eSHanna Reitz /* force_cancel may be true only if cancelled is true, too */ 277a640fa0eSHanna Reitz assert(job->cancelled || !job->force_cancel); 278a640fa0eSHanna Reitz return job->force_cancel; 27908b83bffSHanna Reitz } 28008b83bffSHanna Reitz 281afe1e8a7SEmanuele Giuseppe Esposito bool job_is_cancelled(Job *job) 282afe1e8a7SEmanuele Giuseppe Esposito { 283afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 284afe1e8a7SEmanuele Giuseppe Esposito return job_is_cancelled_locked(job); 285afe1e8a7SEmanuele Giuseppe Esposito } 286afe1e8a7SEmanuele Giuseppe Esposito 287afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 288afe1e8a7SEmanuele Giuseppe Esposito static bool job_cancel_requested_locked(Job *job) 28908b83bffSHanna Reitz { 290daa7f2f9SKevin Wolf return job->cancelled; 291daa7f2f9SKevin Wolf } 292daa7f2f9SKevin Wolf 293afe1e8a7SEmanuele Giuseppe Esposito bool job_cancel_requested(Job *job) 294afe1e8a7SEmanuele Giuseppe Esposito { 295afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 296afe1e8a7SEmanuele Giuseppe Esposito return job_cancel_requested_locked(job); 297afe1e8a7SEmanuele Giuseppe Esposito } 298afe1e8a7SEmanuele Giuseppe Esposito 299afe1e8a7SEmanuele Giuseppe Esposito bool job_is_ready_locked(Job *job) 300df956ae2SKevin Wolf { 301df956ae2SKevin Wolf switch (job->status) { 302df956ae2SKevin Wolf case JOB_STATUS_UNDEFINED: 303df956ae2SKevin Wolf case JOB_STATUS_CREATED: 304df956ae2SKevin Wolf case JOB_STATUS_RUNNING: 305df956ae2SKevin Wolf case JOB_STATUS_PAUSED: 306df956ae2SKevin Wolf case JOB_STATUS_WAITING: 307df956ae2SKevin Wolf case JOB_STATUS_PENDING: 308df956ae2SKevin Wolf case JOB_STATUS_ABORTING: 309df956ae2SKevin Wolf case JOB_STATUS_CONCLUDED: 310df956ae2SKevin Wolf case JOB_STATUS_NULL: 311df956ae2SKevin Wolf return false; 312df956ae2SKevin Wolf case JOB_STATUS_READY: 313df956ae2SKevin Wolf case JOB_STATUS_STANDBY: 314df956ae2SKevin Wolf return true; 315df956ae2SKevin Wolf default: 316df956ae2SKevin Wolf g_assert_not_reached(); 317df956ae2SKevin Wolf } 318df956ae2SKevin Wolf return false; 319df956ae2SKevin Wolf } 320df956ae2SKevin Wolf 321afe1e8a7SEmanuele Giuseppe Esposito bool job_is_ready(Job *job) 322afe1e8a7SEmanuele Giuseppe Esposito { 323afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 324afe1e8a7SEmanuele Giuseppe Esposito return job_is_ready_locked(job); 325afe1e8a7SEmanuele Giuseppe Esposito } 326afe1e8a7SEmanuele Giuseppe Esposito 327afe1e8a7SEmanuele Giuseppe Esposito bool job_is_completed_locked(Job *job) 328afe1e8a7SEmanuele Giuseppe Esposito { 329afe1e8a7SEmanuele Giuseppe Esposito switch (job->status) { 330afe1e8a7SEmanuele Giuseppe Esposito case JOB_STATUS_UNDEFINED: 331afe1e8a7SEmanuele Giuseppe Esposito case JOB_STATUS_CREATED: 332afe1e8a7SEmanuele Giuseppe Esposito case JOB_STATUS_RUNNING: 333afe1e8a7SEmanuele Giuseppe Esposito case JOB_STATUS_PAUSED: 334afe1e8a7SEmanuele Giuseppe Esposito case JOB_STATUS_READY: 335afe1e8a7SEmanuele Giuseppe Esposito case JOB_STATUS_STANDBY: 336afe1e8a7SEmanuele Giuseppe Esposito return false; 337afe1e8a7SEmanuele Giuseppe Esposito case JOB_STATUS_WAITING: 338afe1e8a7SEmanuele Giuseppe Esposito case JOB_STATUS_PENDING: 339afe1e8a7SEmanuele Giuseppe Esposito case JOB_STATUS_ABORTING: 340afe1e8a7SEmanuele Giuseppe Esposito case JOB_STATUS_CONCLUDED: 341afe1e8a7SEmanuele Giuseppe Esposito case JOB_STATUS_NULL: 342afe1e8a7SEmanuele Giuseppe Esposito return true; 343afe1e8a7SEmanuele Giuseppe Esposito default: 344afe1e8a7SEmanuele Giuseppe Esposito g_assert_not_reached(); 345afe1e8a7SEmanuele Giuseppe Esposito } 346afe1e8a7SEmanuele Giuseppe Esposito return false; 347afe1e8a7SEmanuele Giuseppe Esposito } 348afe1e8a7SEmanuele Giuseppe Esposito 349dbe5e6c1SKevin Wolf bool job_is_completed(Job *job) 350dbe5e6c1SKevin Wolf { 351afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 352afe1e8a7SEmanuele Giuseppe Esposito return job_is_completed_locked(job); 353dbe5e6c1SKevin Wolf } 354dbe5e6c1SKevin Wolf 355afe1e8a7SEmanuele Giuseppe Esposito static bool job_started_locked(Job *job) 356da01ff7fSKevin Wolf { 357da01ff7fSKevin Wolf return job->co; 358da01ff7fSKevin Wolf } 359da01ff7fSKevin Wolf 360afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 361afe1e8a7SEmanuele Giuseppe Esposito static bool job_should_pause_locked(Job *job) 362da01ff7fSKevin Wolf { 363da01ff7fSKevin Wolf return job->pause_count > 0; 364da01ff7fSKevin Wolf } 365da01ff7fSKevin Wolf 366afe1e8a7SEmanuele Giuseppe Esposito Job *job_next_locked(Job *job) 367e7c1d78bSKevin Wolf { 368e7c1d78bSKevin Wolf if (!job) { 369e7c1d78bSKevin Wolf return QLIST_FIRST(&jobs); 370e7c1d78bSKevin Wolf } 371e7c1d78bSKevin Wolf return QLIST_NEXT(job, job_list); 372e7c1d78bSKevin Wolf } 373e7c1d78bSKevin Wolf 374afe1e8a7SEmanuele Giuseppe Esposito Job *job_next(Job *job) 375afe1e8a7SEmanuele Giuseppe Esposito { 376afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 377afe1e8a7SEmanuele Giuseppe Esposito return job_next_locked(job); 378afe1e8a7SEmanuele Giuseppe Esposito } 379afe1e8a7SEmanuele Giuseppe Esposito 380afe1e8a7SEmanuele Giuseppe Esposito Job *job_get_locked(const char *id) 381e7c1d78bSKevin Wolf { 382e7c1d78bSKevin Wolf Job *job; 383e7c1d78bSKevin Wolf 384e7c1d78bSKevin Wolf QLIST_FOREACH(job, &jobs, job_list) { 385e7c1d78bSKevin Wolf if (job->id && !strcmp(id, job->id)) { 386e7c1d78bSKevin Wolf return job; 387e7c1d78bSKevin Wolf } 388e7c1d78bSKevin Wolf } 389e7c1d78bSKevin Wolf 390e7c1d78bSKevin Wolf return NULL; 391e7c1d78bSKevin Wolf } 392e7c1d78bSKevin Wolf 393afe1e8a7SEmanuele Giuseppe Esposito Job *job_get(const char *id) 394afe1e8a7SEmanuele Giuseppe Esposito { 395afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 396afe1e8a7SEmanuele Giuseppe Esposito return job_get_locked(id); 397afe1e8a7SEmanuele Giuseppe Esposito } 398afe1e8a7SEmanuele Giuseppe Esposito 399afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex *not* held. */ 4005d43e86eSKevin Wolf static void job_sleep_timer_cb(void *opaque) 4015d43e86eSKevin Wolf { 4025d43e86eSKevin Wolf Job *job = opaque; 4035d43e86eSKevin Wolf 4045d43e86eSKevin Wolf job_enter(job); 4055d43e86eSKevin Wolf } 4065d43e86eSKevin Wolf 4077eaa8fb5SKevin Wolf void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, 4087eaa8fb5SKevin Wolf AioContext *ctx, int flags, BlockCompletionFunc *cb, 4097eaa8fb5SKevin Wolf void *opaque, Error **errp) 41033e9e9bdSKevin Wolf { 41133e9e9bdSKevin Wolf Job *job; 41233e9e9bdSKevin Wolf 413afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 414afe1e8a7SEmanuele Giuseppe Esposito 41533e9e9bdSKevin Wolf if (job_id) { 416bb02b65cSKevin Wolf if (flags & JOB_INTERNAL) { 417bb02b65cSKevin Wolf error_setg(errp, "Cannot specify job ID for internal job"); 418bb02b65cSKevin Wolf return NULL; 419bb02b65cSKevin Wolf } 42033e9e9bdSKevin Wolf if (!id_wellformed(job_id)) { 42133e9e9bdSKevin Wolf error_setg(errp, "Invalid job ID '%s'", job_id); 42233e9e9bdSKevin Wolf return NULL; 42333e9e9bdSKevin Wolf } 424afe1e8a7SEmanuele Giuseppe Esposito if (job_get_locked(job_id)) { 425e7c1d78bSKevin Wolf error_setg(errp, "Job ID '%s' already in use", job_id); 426e7c1d78bSKevin Wolf return NULL; 427e7c1d78bSKevin Wolf } 428bb02b65cSKevin Wolf } else if (!(flags & JOB_INTERNAL)) { 429bb02b65cSKevin Wolf error_setg(errp, "An explicit job ID is required"); 430bb02b65cSKevin Wolf return NULL; 43133e9e9bdSKevin Wolf } 43233e9e9bdSKevin Wolf 43333e9e9bdSKevin Wolf job = g_malloc0(driver->instance_size); 43433e9e9bdSKevin Wolf job->driver = driver; 43533e9e9bdSKevin Wolf job->id = g_strdup(job_id); 43680fa2c75SKevin Wolf job->refcnt = 1; 43708be6fe2SKevin Wolf job->aio_context = ctx; 438da01ff7fSKevin Wolf job->busy = false; 439da01ff7fSKevin Wolf job->paused = true; 440da01ff7fSKevin Wolf job->pause_count = 1; 441bb02b65cSKevin Wolf job->auto_finalize = !(flags & JOB_MANUAL_FINALIZE); 442bb02b65cSKevin Wolf job->auto_dismiss = !(flags & JOB_MANUAL_DISMISS); 4434ad35181SKevin Wolf job->cb = cb; 4444ad35181SKevin Wolf job->opaque = opaque; 44533e9e9bdSKevin Wolf 446a7b4f8fcSEmanuele Giuseppe Esposito progress_init(&job->progress); 447a7b4f8fcSEmanuele Giuseppe Esposito 448139a9f02SKevin Wolf notifier_list_init(&job->on_finalize_cancelled); 449139a9f02SKevin Wolf notifier_list_init(&job->on_finalize_completed); 450139a9f02SKevin Wolf notifier_list_init(&job->on_pending); 4512e1795b5SKevin Wolf notifier_list_init(&job->on_ready); 452252f4091SEmanuele Giuseppe Esposito notifier_list_init(&job->on_idle); 453139a9f02SKevin Wolf 454afe1e8a7SEmanuele Giuseppe Esposito job_state_transition_locked(job, JOB_STATUS_CREATED); 4555d43e86eSKevin Wolf aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, 4565d43e86eSKevin Wolf QEMU_CLOCK_REALTIME, SCALE_NS, 4575d43e86eSKevin Wolf job_sleep_timer_cb, job); 458a50c2ab8SKevin Wolf 459e7c1d78bSKevin Wolf QLIST_INSERT_HEAD(&jobs, job, job_list); 460e7c1d78bSKevin Wolf 4617eaa8fb5SKevin Wolf /* Single jobs are modeled as single-job transactions for sake of 4627eaa8fb5SKevin Wolf * consolidating the job management logic */ 4637eaa8fb5SKevin Wolf if (!txn) { 4647eaa8fb5SKevin Wolf txn = job_txn_new(); 465afe1e8a7SEmanuele Giuseppe Esposito job_txn_add_job_locked(txn, job); 466afe1e8a7SEmanuele Giuseppe Esposito job_txn_unref_locked(txn); 4677eaa8fb5SKevin Wolf } else { 468afe1e8a7SEmanuele Giuseppe Esposito job_txn_add_job_locked(txn, job); 4697eaa8fb5SKevin Wolf } 4707eaa8fb5SKevin Wolf 47133e9e9bdSKevin Wolf return job; 47233e9e9bdSKevin Wolf } 473fd61a701SKevin Wolf 474afe1e8a7SEmanuele Giuseppe Esposito void job_ref_locked(Job *job) 475fd61a701SKevin Wolf { 47680fa2c75SKevin Wolf ++job->refcnt; 47780fa2c75SKevin Wolf } 47880fa2c75SKevin Wolf 479afe1e8a7SEmanuele Giuseppe Esposito void job_ref(Job *job) 480afe1e8a7SEmanuele Giuseppe Esposito { 481afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 482afe1e8a7SEmanuele Giuseppe Esposito job_ref_locked(job); 483afe1e8a7SEmanuele Giuseppe Esposito } 484afe1e8a7SEmanuele Giuseppe Esposito 485afe1e8a7SEmanuele Giuseppe Esposito void job_unref_locked(Job *job) 48680fa2c75SKevin Wolf { 487c70b8031SEmanuele Giuseppe Esposito GLOBAL_STATE_CODE(); 488c70b8031SEmanuele Giuseppe Esposito 48980fa2c75SKevin Wolf if (--job->refcnt == 0) { 49080fa2c75SKevin Wolf assert(job->status == JOB_STATUS_NULL); 4915d43e86eSKevin Wolf assert(!timer_pending(&job->sleep_timer)); 4927eaa8fb5SKevin Wolf assert(!job->txn); 49380fa2c75SKevin Wolf 49480fa2c75SKevin Wolf if (job->driver->free) { 495afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 49680fa2c75SKevin Wolf job->driver->free(job); 497afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 49880fa2c75SKevin Wolf } 49980fa2c75SKevin Wolf 500e7c1d78bSKevin Wolf QLIST_REMOVE(job, job_list); 501e7c1d78bSKevin Wolf 502a7b4f8fcSEmanuele Giuseppe Esposito progress_destroy(&job->progress); 5033d1f8b07SJohn Snow error_free(job->err); 504fd61a701SKevin Wolf g_free(job->id); 505fd61a701SKevin Wolf g_free(job); 506fd61a701SKevin Wolf } 50780fa2c75SKevin Wolf } 5081908a559SKevin Wolf 509afe1e8a7SEmanuele Giuseppe Esposito void job_unref(Job *job) 510afe1e8a7SEmanuele Giuseppe Esposito { 511afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 512afe1e8a7SEmanuele Giuseppe Esposito job_unref_locked(job); 513afe1e8a7SEmanuele Giuseppe Esposito } 514afe1e8a7SEmanuele Giuseppe Esposito 51530a5c887SKevin Wolf void job_progress_update(Job *job, uint64_t done) 51630a5c887SKevin Wolf { 51701fe1ca9SVladimir Sementsov-Ogievskiy progress_work_done(&job->progress, done); 51830a5c887SKevin Wolf } 51930a5c887SKevin Wolf 52030a5c887SKevin Wolf void job_progress_set_remaining(Job *job, uint64_t remaining) 52130a5c887SKevin Wolf { 52201fe1ca9SVladimir Sementsov-Ogievskiy progress_set_remaining(&job->progress, remaining); 52330a5c887SKevin Wolf } 52430a5c887SKevin Wolf 52562f13600SMax Reitz void job_progress_increase_remaining(Job *job, uint64_t delta) 52662f13600SMax Reitz { 52701fe1ca9SVladimir Sementsov-Ogievskiy progress_increase_remaining(&job->progress, delta); 52862f13600SMax Reitz } 52962f13600SMax Reitz 530544f4d52SEmanuele Giuseppe Esposito /** 531544f4d52SEmanuele Giuseppe Esposito * To be called when a cancelled job is finalised. 532afe1e8a7SEmanuele Giuseppe Esposito * Called with job_mutex held. 533544f4d52SEmanuele Giuseppe Esposito */ 534afe1e8a7SEmanuele Giuseppe Esposito static void job_event_cancelled_locked(Job *job) 535139a9f02SKevin Wolf { 536139a9f02SKevin Wolf notifier_list_notify(&job->on_finalize_cancelled, job); 537139a9f02SKevin Wolf } 538139a9f02SKevin Wolf 539544f4d52SEmanuele Giuseppe Esposito /** 540544f4d52SEmanuele Giuseppe Esposito * To be called when a successfully completed job is finalised. 541afe1e8a7SEmanuele Giuseppe Esposito * Called with job_mutex held. 542544f4d52SEmanuele Giuseppe Esposito */ 543afe1e8a7SEmanuele Giuseppe Esposito static void job_event_completed_locked(Job *job) 544139a9f02SKevin Wolf { 545139a9f02SKevin Wolf notifier_list_notify(&job->on_finalize_completed, job); 546139a9f02SKevin Wolf } 547139a9f02SKevin Wolf 548afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 549afe1e8a7SEmanuele Giuseppe Esposito static void job_event_pending_locked(Job *job) 550139a9f02SKevin Wolf { 551139a9f02SKevin Wolf notifier_list_notify(&job->on_pending, job); 552139a9f02SKevin Wolf } 553139a9f02SKevin Wolf 554afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 555afe1e8a7SEmanuele Giuseppe Esposito static void job_event_ready_locked(Job *job) 5562e1795b5SKevin Wolf { 5572e1795b5SKevin Wolf notifier_list_notify(&job->on_ready, job); 5582e1795b5SKevin Wolf } 5592e1795b5SKevin Wolf 560afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 561afe1e8a7SEmanuele Giuseppe Esposito static void job_event_idle_locked(Job *job) 56234dc97b9SKevin Wolf { 56334dc97b9SKevin Wolf notifier_list_notify(&job->on_idle, job); 56434dc97b9SKevin Wolf } 56534dc97b9SKevin Wolf 566afe1e8a7SEmanuele Giuseppe Esposito void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)) 567da01ff7fSKevin Wolf { 568afe1e8a7SEmanuele Giuseppe Esposito if (!job_started_locked(job)) { 569da01ff7fSKevin Wolf return; 570da01ff7fSKevin Wolf } 571da01ff7fSKevin Wolf if (job->deferred_to_main_loop) { 572da01ff7fSKevin Wolf return; 573da01ff7fSKevin Wolf } 574da01ff7fSKevin Wolf 57555c5a25aSEmanuele Giuseppe Esposito real_job_lock(); 576da01ff7fSKevin Wolf if (job->busy) { 57755c5a25aSEmanuele Giuseppe Esposito real_job_unlock(); 578da01ff7fSKevin Wolf return; 579da01ff7fSKevin Wolf } 580da01ff7fSKevin Wolf 581da01ff7fSKevin Wolf if (fn && !fn(job)) { 58255c5a25aSEmanuele Giuseppe Esposito real_job_unlock(); 583da01ff7fSKevin Wolf return; 584da01ff7fSKevin Wolf } 585da01ff7fSKevin Wolf 586da01ff7fSKevin Wolf assert(!job->deferred_to_main_loop); 587da01ff7fSKevin Wolf timer_del(&job->sleep_timer); 588da01ff7fSKevin Wolf job->busy = true; 58955c5a25aSEmanuele Giuseppe Esposito real_job_unlock(); 590afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 591ef02dac2SPaolo Bonzini aio_co_wake(job->co); 592afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 593afe1e8a7SEmanuele Giuseppe Esposito } 594afe1e8a7SEmanuele Giuseppe Esposito 595afe1e8a7SEmanuele Giuseppe Esposito void job_enter_cond(Job *job, bool(*fn)(Job *job)) 596afe1e8a7SEmanuele Giuseppe Esposito { 597afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 598afe1e8a7SEmanuele Giuseppe Esposito job_enter_cond_locked(job, fn); 599da01ff7fSKevin Wolf } 600da01ff7fSKevin Wolf 6015d43e86eSKevin Wolf void job_enter(Job *job) 6025d43e86eSKevin Wolf { 603afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 604afe1e8a7SEmanuele Giuseppe Esposito job_enter_cond_locked(job, NULL); 6055d43e86eSKevin Wolf } 6065d43e86eSKevin Wolf 607da01ff7fSKevin Wolf /* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds. 6083d70ff53SKevin Wolf * Reentering the job coroutine with job_enter() before the timer has expired 6093d70ff53SKevin Wolf * is allowed and cancels the timer. 610da01ff7fSKevin Wolf * 6113d70ff53SKevin Wolf * If @ns is (uint64_t) -1, no timer is scheduled and job_enter() must be 612afe1e8a7SEmanuele Giuseppe Esposito * called explicitly. 613afe1e8a7SEmanuele Giuseppe Esposito * 614afe1e8a7SEmanuele Giuseppe Esposito * Called with job_mutex held, but releases it temporarily. 615afe1e8a7SEmanuele Giuseppe Esposito */ 616afe1e8a7SEmanuele Giuseppe Esposito static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns) 617da01ff7fSKevin Wolf { 618ef02dac2SPaolo Bonzini AioContext *next_aio_context; 619ef02dac2SPaolo Bonzini 62055c5a25aSEmanuele Giuseppe Esposito real_job_lock(); 621da01ff7fSKevin Wolf if (ns != -1) { 622da01ff7fSKevin Wolf timer_mod(&job->sleep_timer, ns); 623da01ff7fSKevin Wolf } 624da01ff7fSKevin Wolf job->busy = false; 625afe1e8a7SEmanuele Giuseppe Esposito job_event_idle_locked(job); 62655c5a25aSEmanuele Giuseppe Esposito real_job_unlock(); 627afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 628da01ff7fSKevin Wolf qemu_coroutine_yield(); 629afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 630da01ff7fSKevin Wolf 631ef02dac2SPaolo Bonzini next_aio_context = job->aio_context; 632ef02dac2SPaolo Bonzini /* 633ef02dac2SPaolo Bonzini * Coroutine has resumed, but in the meanwhile the job AioContext 634ef02dac2SPaolo Bonzini * might have changed via bdrv_try_set_aio_context(), so we need to move 635ef02dac2SPaolo Bonzini * the coroutine too in the new aiocontext. 636ef02dac2SPaolo Bonzini */ 637ef02dac2SPaolo Bonzini while (qemu_get_current_aio_context() != next_aio_context) { 638ef02dac2SPaolo Bonzini job_unlock(); 639ef02dac2SPaolo Bonzini aio_co_reschedule_self(next_aio_context); 640ef02dac2SPaolo Bonzini job_lock(); 641ef02dac2SPaolo Bonzini next_aio_context = job->aio_context; 642ef02dac2SPaolo Bonzini } 643ef02dac2SPaolo Bonzini 644ef02dac2SPaolo Bonzini /* Set by job_enter_cond_locked() before re-entering the coroutine. */ 645da01ff7fSKevin Wolf assert(job->busy); 646da01ff7fSKevin Wolf } 647da01ff7fSKevin Wolf 648afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held, but releases it temporarily. */ 649afe1e8a7SEmanuele Giuseppe Esposito static void coroutine_fn job_pause_point_locked(Job *job) 650da01ff7fSKevin Wolf { 651afe1e8a7SEmanuele Giuseppe Esposito assert(job && job_started_locked(job)); 652da01ff7fSKevin Wolf 653afe1e8a7SEmanuele Giuseppe Esposito if (!job_should_pause_locked(job)) { 654da01ff7fSKevin Wolf return; 655da01ff7fSKevin Wolf } 656afe1e8a7SEmanuele Giuseppe Esposito if (job_is_cancelled_locked(job)) { 657da01ff7fSKevin Wolf return; 658da01ff7fSKevin Wolf } 659da01ff7fSKevin Wolf 660da01ff7fSKevin Wolf if (job->driver->pause) { 661afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 662da01ff7fSKevin Wolf job->driver->pause(job); 663afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 664da01ff7fSKevin Wolf } 665da01ff7fSKevin Wolf 666afe1e8a7SEmanuele Giuseppe Esposito if (job_should_pause_locked(job) && !job_is_cancelled_locked(job)) { 667da01ff7fSKevin Wolf JobStatus status = job->status; 668afe1e8a7SEmanuele Giuseppe Esposito job_state_transition_locked(job, status == JOB_STATUS_READY 669da01ff7fSKevin Wolf ? JOB_STATUS_STANDBY 670da01ff7fSKevin Wolf : JOB_STATUS_PAUSED); 671da01ff7fSKevin Wolf job->paused = true; 672afe1e8a7SEmanuele Giuseppe Esposito job_do_yield_locked(job, -1); 673da01ff7fSKevin Wolf job->paused = false; 674afe1e8a7SEmanuele Giuseppe Esposito job_state_transition_locked(job, status); 675da01ff7fSKevin Wolf } 676da01ff7fSKevin Wolf 677da01ff7fSKevin Wolf if (job->driver->resume) { 678afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 679da01ff7fSKevin Wolf job->driver->resume(job); 680afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 681da01ff7fSKevin Wolf } 682da01ff7fSKevin Wolf } 683da01ff7fSKevin Wolf 684afe1e8a7SEmanuele Giuseppe Esposito void coroutine_fn job_pause_point(Job *job) 685afe1e8a7SEmanuele Giuseppe Esposito { 686afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 687afe1e8a7SEmanuele Giuseppe Esposito job_pause_point_locked(job); 688afe1e8a7SEmanuele Giuseppe Esposito } 689afe1e8a7SEmanuele Giuseppe Esposito 690afe1e8a7SEmanuele Giuseppe Esposito static void coroutine_fn job_yield_locked(Job *job) 691afe1e8a7SEmanuele Giuseppe Esposito { 692afe1e8a7SEmanuele Giuseppe Esposito assert(job->busy); 693afe1e8a7SEmanuele Giuseppe Esposito 694afe1e8a7SEmanuele Giuseppe Esposito /* Check cancellation *before* setting busy = false, too! */ 695afe1e8a7SEmanuele Giuseppe Esposito if (job_is_cancelled_locked(job)) { 696afe1e8a7SEmanuele Giuseppe Esposito return; 697afe1e8a7SEmanuele Giuseppe Esposito } 698afe1e8a7SEmanuele Giuseppe Esposito 699afe1e8a7SEmanuele Giuseppe Esposito if (!job_should_pause_locked(job)) { 700afe1e8a7SEmanuele Giuseppe Esposito job_do_yield_locked(job, -1); 701afe1e8a7SEmanuele Giuseppe Esposito } 702afe1e8a7SEmanuele Giuseppe Esposito 703afe1e8a7SEmanuele Giuseppe Esposito job_pause_point_locked(job); 704afe1e8a7SEmanuele Giuseppe Esposito } 705afe1e8a7SEmanuele Giuseppe Esposito 70606753a07SPaolo Bonzini void coroutine_fn job_yield(Job *job) 707198c49ccSKevin Wolf { 708afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 709afe1e8a7SEmanuele Giuseppe Esposito job_yield_locked(job); 710198c49ccSKevin Wolf } 711198c49ccSKevin Wolf 7125d43e86eSKevin Wolf void coroutine_fn job_sleep_ns(Job *job, int64_t ns) 7135d43e86eSKevin Wolf { 714afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 7155d43e86eSKevin Wolf assert(job->busy); 7165d43e86eSKevin Wolf 7175d43e86eSKevin Wolf /* Check cancellation *before* setting busy = false, too! */ 718afe1e8a7SEmanuele Giuseppe Esposito if (job_is_cancelled_locked(job)) { 7195d43e86eSKevin Wolf return; 7205d43e86eSKevin Wolf } 7215d43e86eSKevin Wolf 722afe1e8a7SEmanuele Giuseppe Esposito if (!job_should_pause_locked(job)) { 723afe1e8a7SEmanuele Giuseppe Esposito job_do_yield_locked(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); 7245d43e86eSKevin Wolf } 7255d43e86eSKevin Wolf 726afe1e8a7SEmanuele Giuseppe Esposito job_pause_point_locked(job); 7275d43e86eSKevin Wolf } 7285d43e86eSKevin Wolf 729afe1e8a7SEmanuele Giuseppe Esposito /* Assumes the job_mutex is held */ 730afe1e8a7SEmanuele Giuseppe Esposito static bool job_timer_not_pending_locked(Job *job) 731b15de828SKevin Wolf { 732b15de828SKevin Wolf return !timer_pending(&job->sleep_timer); 733b15de828SKevin Wolf } 734b15de828SKevin Wolf 735afe1e8a7SEmanuele Giuseppe Esposito void job_pause_locked(Job *job) 736b15de828SKevin Wolf { 737b15de828SKevin Wolf job->pause_count++; 7383ee1483bSVladimir Sementsov-Ogievskiy if (!job->paused) { 739afe1e8a7SEmanuele Giuseppe Esposito job_enter_cond_locked(job, NULL); 7403ee1483bSVladimir Sementsov-Ogievskiy } 741b15de828SKevin Wolf } 742b15de828SKevin Wolf 743afe1e8a7SEmanuele Giuseppe Esposito void job_pause(Job *job) 744afe1e8a7SEmanuele Giuseppe Esposito { 745afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 746afe1e8a7SEmanuele Giuseppe Esposito job_pause_locked(job); 747afe1e8a7SEmanuele Giuseppe Esposito } 748afe1e8a7SEmanuele Giuseppe Esposito 749afe1e8a7SEmanuele Giuseppe Esposito void job_resume_locked(Job *job) 750b15de828SKevin Wolf { 751b15de828SKevin Wolf assert(job->pause_count > 0); 752b15de828SKevin Wolf job->pause_count--; 753b15de828SKevin Wolf if (job->pause_count) { 754b15de828SKevin Wolf return; 755b15de828SKevin Wolf } 756b15de828SKevin Wolf 757b15de828SKevin Wolf /* kick only if no timer is pending */ 758afe1e8a7SEmanuele Giuseppe Esposito job_enter_cond_locked(job, job_timer_not_pending_locked); 759b15de828SKevin Wolf } 760b15de828SKevin Wolf 761afe1e8a7SEmanuele Giuseppe Esposito void job_resume(Job *job) 762b15de828SKevin Wolf { 763afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 764afe1e8a7SEmanuele Giuseppe Esposito job_resume_locked(job); 765afe1e8a7SEmanuele Giuseppe Esposito } 766afe1e8a7SEmanuele Giuseppe Esposito 767afe1e8a7SEmanuele Giuseppe Esposito void job_user_pause_locked(Job *job, Error **errp) 768afe1e8a7SEmanuele Giuseppe Esposito { 769afe1e8a7SEmanuele Giuseppe Esposito if (job_apply_verb_locked(job, JOB_VERB_PAUSE, errp)) { 770b15de828SKevin Wolf return; 771b15de828SKevin Wolf } 772b15de828SKevin Wolf if (job->user_paused) { 773b15de828SKevin Wolf error_setg(errp, "Job is already paused"); 774b15de828SKevin Wolf return; 775b15de828SKevin Wolf } 776b15de828SKevin Wolf job->user_paused = true; 777afe1e8a7SEmanuele Giuseppe Esposito job_pause_locked(job); 778b15de828SKevin Wolf } 779b15de828SKevin Wolf 780afe1e8a7SEmanuele Giuseppe Esposito void job_user_pause(Job *job, Error **errp) 781afe1e8a7SEmanuele Giuseppe Esposito { 782afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 783afe1e8a7SEmanuele Giuseppe Esposito job_user_pause_locked(job, errp); 784afe1e8a7SEmanuele Giuseppe Esposito } 785afe1e8a7SEmanuele Giuseppe Esposito 786afe1e8a7SEmanuele Giuseppe Esposito bool job_user_paused_locked(Job *job) 787b15de828SKevin Wolf { 788b15de828SKevin Wolf return job->user_paused; 789b15de828SKevin Wolf } 790b15de828SKevin Wolf 791afe1e8a7SEmanuele Giuseppe Esposito bool job_user_paused(Job *job) 792afe1e8a7SEmanuele Giuseppe Esposito { 793afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 794afe1e8a7SEmanuele Giuseppe Esposito return job_user_paused_locked(job); 795afe1e8a7SEmanuele Giuseppe Esposito } 796afe1e8a7SEmanuele Giuseppe Esposito 797afe1e8a7SEmanuele Giuseppe Esposito void job_user_resume_locked(Job *job, Error **errp) 798b15de828SKevin Wolf { 799b15de828SKevin Wolf assert(job); 800c70b8031SEmanuele Giuseppe Esposito GLOBAL_STATE_CODE(); 801b15de828SKevin Wolf if (!job->user_paused || job->pause_count <= 0) { 802b15de828SKevin Wolf error_setg(errp, "Can't resume a job that was not paused"); 803b15de828SKevin Wolf return; 804b15de828SKevin Wolf } 805afe1e8a7SEmanuele Giuseppe Esposito if (job_apply_verb_locked(job, JOB_VERB_RESUME, errp)) { 806b15de828SKevin Wolf return; 807b15de828SKevin Wolf } 808b15de828SKevin Wolf if (job->driver->user_resume) { 809afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 810b15de828SKevin Wolf job->driver->user_resume(job); 811afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 812b15de828SKevin Wolf } 813b15de828SKevin Wolf job->user_paused = false; 814afe1e8a7SEmanuele Giuseppe Esposito job_resume_locked(job); 815b15de828SKevin Wolf } 816b15de828SKevin Wolf 817afe1e8a7SEmanuele Giuseppe Esposito void job_user_resume(Job *job, Error **errp) 818afe1e8a7SEmanuele Giuseppe Esposito { 819afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 820afe1e8a7SEmanuele Giuseppe Esposito job_user_resume_locked(job, errp); 821afe1e8a7SEmanuele Giuseppe Esposito } 822afe1e8a7SEmanuele Giuseppe Esposito 823afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held, but releases it temporarily. */ 824afe1e8a7SEmanuele Giuseppe Esposito static void job_do_dismiss_locked(Job *job) 8254ad35181SKevin Wolf { 8264ad35181SKevin Wolf assert(job); 8274ad35181SKevin Wolf job->busy = false; 8284ad35181SKevin Wolf job->paused = false; 8294ad35181SKevin Wolf job->deferred_to_main_loop = true; 8304ad35181SKevin Wolf 831afe1e8a7SEmanuele Giuseppe Esposito job_txn_del_job_locked(job); 8324ad35181SKevin Wolf 833afe1e8a7SEmanuele Giuseppe Esposito job_state_transition_locked(job, JOB_STATUS_NULL); 834afe1e8a7SEmanuele Giuseppe Esposito job_unref_locked(job); 8354ad35181SKevin Wolf } 8364ad35181SKevin Wolf 837afe1e8a7SEmanuele Giuseppe Esposito void job_dismiss_locked(Job **jobptr, Error **errp) 8385f9a6a08SKevin Wolf { 8395f9a6a08SKevin Wolf Job *job = *jobptr; 8405f9a6a08SKevin Wolf /* similarly to _complete, this is QMP-interface only. */ 8415f9a6a08SKevin Wolf assert(job->id); 842afe1e8a7SEmanuele Giuseppe Esposito if (job_apply_verb_locked(job, JOB_VERB_DISMISS, errp)) { 8435f9a6a08SKevin Wolf return; 8445f9a6a08SKevin Wolf } 8455f9a6a08SKevin Wolf 846afe1e8a7SEmanuele Giuseppe Esposito job_do_dismiss_locked(job); 8475f9a6a08SKevin Wolf *jobptr = NULL; 8485f9a6a08SKevin Wolf } 8495f9a6a08SKevin Wolf 850afe1e8a7SEmanuele Giuseppe Esposito void job_dismiss(Job **jobptr, Error **errp) 851afe1e8a7SEmanuele Giuseppe Esposito { 852afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 853afe1e8a7SEmanuele Giuseppe Esposito job_dismiss_locked(jobptr, errp); 854afe1e8a7SEmanuele Giuseppe Esposito } 855afe1e8a7SEmanuele Giuseppe Esposito 8564ad35181SKevin Wolf void job_early_fail(Job *job) 8574ad35181SKevin Wolf { 858afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 8594ad35181SKevin Wolf assert(job->status == JOB_STATUS_CREATED); 860afe1e8a7SEmanuele Giuseppe Esposito job_do_dismiss_locked(job); 8614ad35181SKevin Wolf } 8624ad35181SKevin Wolf 863afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 864afe1e8a7SEmanuele Giuseppe Esposito static void job_conclude_locked(Job *job) 8654ad35181SKevin Wolf { 866afe1e8a7SEmanuele Giuseppe Esposito job_state_transition_locked(job, JOB_STATUS_CONCLUDED); 867afe1e8a7SEmanuele Giuseppe Esposito if (job->auto_dismiss || !job_started_locked(job)) { 868afe1e8a7SEmanuele Giuseppe Esposito job_do_dismiss_locked(job); 8694ad35181SKevin Wolf } 8704ad35181SKevin Wolf } 8714ad35181SKevin Wolf 872afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 873afe1e8a7SEmanuele Giuseppe Esposito static void job_update_rc_locked(Job *job) 8744ad35181SKevin Wolf { 875afe1e8a7SEmanuele Giuseppe Esposito if (!job->ret && job_is_cancelled_locked(job)) { 8764ad35181SKevin Wolf job->ret = -ECANCELED; 8774ad35181SKevin Wolf } 8784ad35181SKevin Wolf if (job->ret) { 8793d1f8b07SJohn Snow if (!job->err) { 8803d1f8b07SJohn Snow error_setg(&job->err, "%s", strerror(-job->ret)); 8811266c9b9SKevin Wolf } 882afe1e8a7SEmanuele Giuseppe Esposito job_state_transition_locked(job, JOB_STATUS_ABORTING); 8834ad35181SKevin Wolf } 8844ad35181SKevin Wolf } 8854ad35181SKevin Wolf 8864ad35181SKevin Wolf static void job_commit(Job *job) 8874ad35181SKevin Wolf { 8884ad35181SKevin Wolf assert(!job->ret); 889c70b8031SEmanuele Giuseppe Esposito GLOBAL_STATE_CODE(); 8904ad35181SKevin Wolf if (job->driver->commit) { 8914ad35181SKevin Wolf job->driver->commit(job); 8924ad35181SKevin Wolf } 8934ad35181SKevin Wolf } 8944ad35181SKevin Wolf 8954ad35181SKevin Wolf static void job_abort(Job *job) 8964ad35181SKevin Wolf { 8974ad35181SKevin Wolf assert(job->ret); 898c70b8031SEmanuele Giuseppe Esposito GLOBAL_STATE_CODE(); 8994ad35181SKevin Wolf if (job->driver->abort) { 9004ad35181SKevin Wolf job->driver->abort(job); 9014ad35181SKevin Wolf } 9024ad35181SKevin Wolf } 9034ad35181SKevin Wolf 9044ad35181SKevin Wolf static void job_clean(Job *job) 9054ad35181SKevin Wolf { 906c70b8031SEmanuele Giuseppe Esposito GLOBAL_STATE_CODE(); 9074ad35181SKevin Wolf if (job->driver->clean) { 9084ad35181SKevin Wolf job->driver->clean(job); 9094ad35181SKevin Wolf } 9104ad35181SKevin Wolf } 9114ad35181SKevin Wolf 912afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held, but releases it temporarily */ 913afe1e8a7SEmanuele Giuseppe Esposito static int job_finalize_single_locked(Job *job) 9144ad35181SKevin Wolf { 915afe1e8a7SEmanuele Giuseppe Esposito int job_ret; 916afe1e8a7SEmanuele Giuseppe Esposito 917afe1e8a7SEmanuele Giuseppe Esposito assert(job_is_completed_locked(job)); 9184ad35181SKevin Wolf 9194ad35181SKevin Wolf /* Ensure abort is called for late-transactional failures */ 920afe1e8a7SEmanuele Giuseppe Esposito job_update_rc_locked(job); 9214ad35181SKevin Wolf 922afe1e8a7SEmanuele Giuseppe Esposito job_ret = job->ret; 923afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 924afe1e8a7SEmanuele Giuseppe Esposito 925afe1e8a7SEmanuele Giuseppe Esposito if (!job_ret) { 9264ad35181SKevin Wolf job_commit(job); 9274ad35181SKevin Wolf } else { 9284ad35181SKevin Wolf job_abort(job); 9294ad35181SKevin Wolf } 9304ad35181SKevin Wolf job_clean(job); 9314ad35181SKevin Wolf 932afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 933afe1e8a7SEmanuele Giuseppe Esposito 9344ad35181SKevin Wolf if (job->cb) { 935afe1e8a7SEmanuele Giuseppe Esposito job_ret = job->ret; 936afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 937afe1e8a7SEmanuele Giuseppe Esposito job->cb(job->opaque, job_ret); 938afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 9394ad35181SKevin Wolf } 9404ad35181SKevin Wolf 9414ad35181SKevin Wolf /* Emit events only if we actually started */ 942afe1e8a7SEmanuele Giuseppe Esposito if (job_started_locked(job)) { 943afe1e8a7SEmanuele Giuseppe Esposito if (job_is_cancelled_locked(job)) { 944afe1e8a7SEmanuele Giuseppe Esposito job_event_cancelled_locked(job); 9454ad35181SKevin Wolf } else { 946afe1e8a7SEmanuele Giuseppe Esposito job_event_completed_locked(job); 9474ad35181SKevin Wolf } 9484ad35181SKevin Wolf } 9494ad35181SKevin Wolf 950afe1e8a7SEmanuele Giuseppe Esposito job_txn_del_job_locked(job); 951afe1e8a7SEmanuele Giuseppe Esposito job_conclude_locked(job); 9524ad35181SKevin Wolf return 0; 9534ad35181SKevin Wolf } 9544ad35181SKevin Wolf 955afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held, but releases it temporarily */ 956afe1e8a7SEmanuele Giuseppe Esposito static void job_cancel_async_locked(Job *job, bool force) 9577eaa8fb5SKevin Wolf { 958c70b8031SEmanuele Giuseppe Esposito GLOBAL_STATE_CODE(); 9599820933bSVladimir Sementsov-Ogievskiy if (job->driver->cancel) { 960afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 96173895f38SHanna Reitz force = job->driver->cancel(job, force); 962afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 96373895f38SHanna Reitz } else { 96473895f38SHanna Reitz /* No .cancel() means the job will behave as if force-cancelled */ 96573895f38SHanna Reitz force = true; 9669820933bSVladimir Sementsov-Ogievskiy } 96773895f38SHanna Reitz 9687eaa8fb5SKevin Wolf if (job->user_paused) { 9697eaa8fb5SKevin Wolf /* Do not call job_enter here, the caller will handle it. */ 9707eaa8fb5SKevin Wolf if (job->driver->user_resume) { 971afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 9727eaa8fb5SKevin Wolf job->driver->user_resume(job); 973afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 9747eaa8fb5SKevin Wolf } 975e321c059SJeff Cody job->user_paused = false; 9767eaa8fb5SKevin Wolf assert(job->pause_count > 0); 9777eaa8fb5SKevin Wolf job->pause_count--; 9787eaa8fb5SKevin Wolf } 979401dd096SHanna Reitz 980401dd096SHanna Reitz /* 981401dd096SHanna Reitz * Ignore soft cancel requests after the job is already done 982401dd096SHanna Reitz * (We will still invoke job->driver->cancel() above, but if the 983401dd096SHanna Reitz * job driver supports soft cancelling and the job is done, that 984401dd096SHanna Reitz * should be a no-op, too. We still call it so it can override 985401dd096SHanna Reitz * @force.) 986401dd096SHanna Reitz */ 987401dd096SHanna Reitz if (force || !job->deferred_to_main_loop) { 9887eaa8fb5SKevin Wolf job->cancelled = true; 9897eaa8fb5SKevin Wolf /* To prevent 'force == false' overriding a previous 'force == true' */ 9907eaa8fb5SKevin Wolf job->force_cancel |= force; 9917eaa8fb5SKevin Wolf } 992401dd096SHanna Reitz } 9937eaa8fb5SKevin Wolf 994afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held, but releases it temporarily. */ 995afe1e8a7SEmanuele Giuseppe Esposito static void job_completed_txn_abort_locked(Job *job) 9967eaa8fb5SKevin Wolf { 9977eaa8fb5SKevin Wolf AioContext *ctx; 9987eaa8fb5SKevin Wolf JobTxn *txn = job->txn; 9997eaa8fb5SKevin Wolf Job *other_job; 10007eaa8fb5SKevin Wolf 10017eaa8fb5SKevin Wolf if (txn->aborting) { 10027eaa8fb5SKevin Wolf /* 10037eaa8fb5SKevin Wolf * We are cancelled by another job, which will handle everything. 10047eaa8fb5SKevin Wolf */ 10057eaa8fb5SKevin Wolf return; 10067eaa8fb5SKevin Wolf } 10077eaa8fb5SKevin Wolf txn->aborting = true; 1008afe1e8a7SEmanuele Giuseppe Esposito job_txn_ref_locked(txn); 10097eaa8fb5SKevin Wolf 1010d4311314SHanna Reitz /* 1011d4311314SHanna Reitz * We can only hold the single job's AioContext lock while calling 1012644f3a29SKevin Wolf * job_finalize_single() because the finalization callbacks can involve 1013d4311314SHanna Reitz * calls of AIO_WAIT_WHILE(), which could deadlock otherwise. 1014d4311314SHanna Reitz * Note that the job's AioContext may change when it is finalized. 1015d4311314SHanna Reitz */ 1016afe1e8a7SEmanuele Giuseppe Esposito job_ref_locked(job); 1017d4311314SHanna Reitz aio_context_release(job->aio_context); 10187eaa8fb5SKevin Wolf 10197eaa8fb5SKevin Wolf /* Other jobs are effectively cancelled by us, set the status for 10207eaa8fb5SKevin Wolf * them; this job, however, may or may not be cancelled, depending 10217eaa8fb5SKevin Wolf * on the caller, so leave it. */ 10227eaa8fb5SKevin Wolf QLIST_FOREACH(other_job, &txn->jobs, txn_list) { 10237eaa8fb5SKevin Wolf if (other_job != job) { 1024644f3a29SKevin Wolf ctx = other_job->aio_context; 1025644f3a29SKevin Wolf aio_context_acquire(ctx); 10261d4a43e9SHanna Reitz /* 10271d4a43e9SHanna Reitz * This is a transaction: If one job failed, no result will matter. 10281d4a43e9SHanna Reitz * Therefore, pass force=true to terminate all other jobs as quickly 10291d4a43e9SHanna Reitz * as possible. 10301d4a43e9SHanna Reitz */ 1031afe1e8a7SEmanuele Giuseppe Esposito job_cancel_async_locked(other_job, true); 1032644f3a29SKevin Wolf aio_context_release(ctx); 10337eaa8fb5SKevin Wolf } 10347eaa8fb5SKevin Wolf } 10357eaa8fb5SKevin Wolf while (!QLIST_EMPTY(&txn->jobs)) { 10367eaa8fb5SKevin Wolf other_job = QLIST_FIRST(&txn->jobs); 1037d4311314SHanna Reitz /* 1038d4311314SHanna Reitz * The job's AioContext may change, so store it in @ctx so we 1039d4311314SHanna Reitz * release the same context that we have acquired before. 1040d4311314SHanna Reitz */ 10417eaa8fb5SKevin Wolf ctx = other_job->aio_context; 1042644f3a29SKevin Wolf aio_context_acquire(ctx); 1043afe1e8a7SEmanuele Giuseppe Esposito if (!job_is_completed_locked(other_job)) { 1044afe1e8a7SEmanuele Giuseppe Esposito assert(job_cancel_requested_locked(other_job)); 1045afe1e8a7SEmanuele Giuseppe Esposito job_finish_sync_locked(other_job, NULL, NULL); 10467eaa8fb5SKevin Wolf } 1047afe1e8a7SEmanuele Giuseppe Esposito job_finalize_single_locked(other_job); 10487eaa8fb5SKevin Wolf aio_context_release(ctx); 10497eaa8fb5SKevin Wolf } 10507eaa8fb5SKevin Wolf 1051d4311314SHanna Reitz /* 1052d4311314SHanna Reitz * Use job_ref()/job_unref() so we can read the AioContext here 1053d4311314SHanna Reitz * even if the job went away during job_finalize_single(). 1054d4311314SHanna Reitz */ 1055d4311314SHanna Reitz aio_context_acquire(job->aio_context); 1056afe1e8a7SEmanuele Giuseppe Esposito job_unref_locked(job); 1057644f3a29SKevin Wolf 1058afe1e8a7SEmanuele Giuseppe Esposito job_txn_unref_locked(txn); 10597eaa8fb5SKevin Wolf } 10607eaa8fb5SKevin Wolf 1061afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held, but releases it temporarily */ 1062afe1e8a7SEmanuele Giuseppe Esposito static int job_prepare_locked(Job *job) 10637eaa8fb5SKevin Wolf { 1064afe1e8a7SEmanuele Giuseppe Esposito int ret; 1065afe1e8a7SEmanuele Giuseppe Esposito 1066c70b8031SEmanuele Giuseppe Esposito GLOBAL_STATE_CODE(); 10677eaa8fb5SKevin Wolf if (job->ret == 0 && job->driver->prepare) { 1068afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 1069afe1e8a7SEmanuele Giuseppe Esposito ret = job->driver->prepare(job); 1070afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 1071afe1e8a7SEmanuele Giuseppe Esposito job->ret = ret; 1072afe1e8a7SEmanuele Giuseppe Esposito job_update_rc_locked(job); 10737eaa8fb5SKevin Wolf } 10747eaa8fb5SKevin Wolf return job->ret; 10757eaa8fb5SKevin Wolf } 10767eaa8fb5SKevin Wolf 1077afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held */ 1078afe1e8a7SEmanuele Giuseppe Esposito static int job_needs_finalize_locked(Job *job) 10797eaa8fb5SKevin Wolf { 10807eaa8fb5SKevin Wolf return !job->auto_finalize; 10817eaa8fb5SKevin Wolf } 10827eaa8fb5SKevin Wolf 1083afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held */ 1084afe1e8a7SEmanuele Giuseppe Esposito static void job_do_finalize_locked(Job *job) 10857eaa8fb5SKevin Wolf { 10867eaa8fb5SKevin Wolf int rc; 10877eaa8fb5SKevin Wolf assert(job && job->txn); 10887eaa8fb5SKevin Wolf 10897eaa8fb5SKevin Wolf /* prepare the transaction to complete */ 1090afe1e8a7SEmanuele Giuseppe Esposito rc = job_txn_apply_locked(job, job_prepare_locked); 10917eaa8fb5SKevin Wolf if (rc) { 1092afe1e8a7SEmanuele Giuseppe Esposito job_completed_txn_abort_locked(job); 10937eaa8fb5SKevin Wolf } else { 1094afe1e8a7SEmanuele Giuseppe Esposito job_txn_apply_locked(job, job_finalize_single_locked); 10957eaa8fb5SKevin Wolf } 10967eaa8fb5SKevin Wolf } 10977eaa8fb5SKevin Wolf 1098afe1e8a7SEmanuele Giuseppe Esposito void job_finalize_locked(Job *job, Error **errp) 1099afe1e8a7SEmanuele Giuseppe Esposito { 1100afe1e8a7SEmanuele Giuseppe Esposito assert(job && job->id); 1101afe1e8a7SEmanuele Giuseppe Esposito if (job_apply_verb_locked(job, JOB_VERB_FINALIZE, errp)) { 1102afe1e8a7SEmanuele Giuseppe Esposito return; 1103afe1e8a7SEmanuele Giuseppe Esposito } 1104afe1e8a7SEmanuele Giuseppe Esposito job_do_finalize_locked(job); 1105afe1e8a7SEmanuele Giuseppe Esposito } 1106afe1e8a7SEmanuele Giuseppe Esposito 11077eaa8fb5SKevin Wolf void job_finalize(Job *job, Error **errp) 11087eaa8fb5SKevin Wolf { 1109afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 1110afe1e8a7SEmanuele Giuseppe Esposito job_finalize_locked(job, errp); 11117eaa8fb5SKevin Wolf } 11127eaa8fb5SKevin Wolf 1113afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 1114afe1e8a7SEmanuele Giuseppe Esposito static int job_transition_to_pending_locked(Job *job) 11157eaa8fb5SKevin Wolf { 1116afe1e8a7SEmanuele Giuseppe Esposito job_state_transition_locked(job, JOB_STATUS_PENDING); 11177eaa8fb5SKevin Wolf if (!job->auto_finalize) { 1118afe1e8a7SEmanuele Giuseppe Esposito job_event_pending_locked(job); 11197eaa8fb5SKevin Wolf } 11207eaa8fb5SKevin Wolf return 0; 11217eaa8fb5SKevin Wolf } 11227eaa8fb5SKevin Wolf 11232e1795b5SKevin Wolf void job_transition_to_ready(Job *job) 11242e1795b5SKevin Wolf { 1125afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 1126afe1e8a7SEmanuele Giuseppe Esposito job_state_transition_locked(job, JOB_STATUS_READY); 1127afe1e8a7SEmanuele Giuseppe Esposito job_event_ready_locked(job); 11282e1795b5SKevin Wolf } 11292e1795b5SKevin Wolf 1130afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 1131afe1e8a7SEmanuele Giuseppe Esposito static void job_completed_txn_success_locked(Job *job) 11327eaa8fb5SKevin Wolf { 11337eaa8fb5SKevin Wolf JobTxn *txn = job->txn; 11347eaa8fb5SKevin Wolf Job *other_job; 11357eaa8fb5SKevin Wolf 1136afe1e8a7SEmanuele Giuseppe Esposito job_state_transition_locked(job, JOB_STATUS_WAITING); 11377eaa8fb5SKevin Wolf 11387eaa8fb5SKevin Wolf /* 11397eaa8fb5SKevin Wolf * Successful completion, see if there are other running jobs in this 11407eaa8fb5SKevin Wolf * txn. 11417eaa8fb5SKevin Wolf */ 11427eaa8fb5SKevin Wolf QLIST_FOREACH(other_job, &txn->jobs, txn_list) { 1143afe1e8a7SEmanuele Giuseppe Esposito if (!job_is_completed_locked(other_job)) { 11447eaa8fb5SKevin Wolf return; 11457eaa8fb5SKevin Wolf } 11467eaa8fb5SKevin Wolf assert(other_job->ret == 0); 11477eaa8fb5SKevin Wolf } 11487eaa8fb5SKevin Wolf 1149afe1e8a7SEmanuele Giuseppe Esposito job_txn_apply_locked(job, job_transition_to_pending_locked); 11507eaa8fb5SKevin Wolf 11517eaa8fb5SKevin Wolf /* If no jobs need manual finalization, automatically do so */ 1152afe1e8a7SEmanuele Giuseppe Esposito if (job_txn_apply_locked(job, job_needs_finalize_locked) == 0) { 1153afe1e8a7SEmanuele Giuseppe Esposito job_do_finalize_locked(job); 11547eaa8fb5SKevin Wolf } 11557eaa8fb5SKevin Wolf } 11567eaa8fb5SKevin Wolf 1157afe1e8a7SEmanuele Giuseppe Esposito /* Called with job_mutex held. */ 1158afe1e8a7SEmanuele Giuseppe Esposito static void job_completed_locked(Job *job) 11593d70ff53SKevin Wolf { 1160afe1e8a7SEmanuele Giuseppe Esposito assert(job && job->txn && !job_is_completed_locked(job)); 11611266c9b9SKevin Wolf 1162afe1e8a7SEmanuele Giuseppe Esposito job_update_rc_locked(job); 1163404ff28dSJohn Snow trace_job_completed(job, job->ret); 11643d70ff53SKevin Wolf if (job->ret) { 1165afe1e8a7SEmanuele Giuseppe Esposito job_completed_txn_abort_locked(job); 11663d70ff53SKevin Wolf } else { 1167afe1e8a7SEmanuele Giuseppe Esposito job_completed_txn_success_locked(job); 11683d70ff53SKevin Wolf } 11693d70ff53SKevin Wolf } 11703d70ff53SKevin Wolf 1171afe1e8a7SEmanuele Giuseppe Esposito /** 1172afe1e8a7SEmanuele Giuseppe Esposito * Useful only as a type shim for aio_bh_schedule_oneshot. 1173afe1e8a7SEmanuele Giuseppe Esposito * Called with job_mutex *not* held. 1174afe1e8a7SEmanuele Giuseppe Esposito */ 1175ccbfb331SJohn Snow static void job_exit(void *opaque) 1176ccbfb331SJohn Snow { 1177ccbfb331SJohn Snow Job *job = (Job *)opaque; 1178b660a84bSStefan Reiter AioContext *ctx; 1179afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 1180d1756c78SKevin Wolf 1181afe1e8a7SEmanuele Giuseppe Esposito job_ref_locked(job); 1182b660a84bSStefan Reiter aio_context_acquire(job->aio_context); 1183b5a7a057SKevin Wolf 1184b5a7a057SKevin Wolf /* This is a lie, we're not quiescent, but still doing the completion 1185b5a7a057SKevin Wolf * callbacks. However, completion callbacks tend to involve operations that 1186b5a7a057SKevin Wolf * drain block nodes, and if .drained_poll still returned true, we would 1187b5a7a057SKevin Wolf * deadlock. */ 1188b5a7a057SKevin Wolf job->busy = false; 1189afe1e8a7SEmanuele Giuseppe Esposito job_event_idle_locked(job); 1190b5a7a057SKevin Wolf 1191afe1e8a7SEmanuele Giuseppe Esposito job_completed_locked(job); 1192b5a7a057SKevin Wolf 1193b660a84bSStefan Reiter /* 1194b660a84bSStefan Reiter * Note that calling job_completed can move the job to a different 1195b660a84bSStefan Reiter * aio_context, so we cannot cache from above. job_txn_apply takes care of 1196b660a84bSStefan Reiter * acquiring the new lock, and we ref/unref to avoid job_completed freeing 1197b660a84bSStefan Reiter * the job underneath us. 1198b660a84bSStefan Reiter */ 1199b660a84bSStefan Reiter ctx = job->aio_context; 1200afe1e8a7SEmanuele Giuseppe Esposito job_unref_locked(job); 1201d1756c78SKevin Wolf aio_context_release(ctx); 1202ccbfb331SJohn Snow } 1203ccbfb331SJohn Snow 1204ccbfb331SJohn Snow /** 1205ccbfb331SJohn Snow * All jobs must allow a pause point before entering their job proper. This 1206ccbfb331SJohn Snow * ensures that jobs can be paused prior to being started, then resumed later. 1207ccbfb331SJohn Snow */ 1208ccbfb331SJohn Snow static void coroutine_fn job_co_entry(void *opaque) 1209ccbfb331SJohn Snow { 1210ccbfb331SJohn Snow Job *job = opaque; 1211afe1e8a7SEmanuele Giuseppe Esposito int ret; 1212ccbfb331SJohn Snow 1213ccbfb331SJohn Snow assert(job && job->driver && job->driver->run); 1214afe1e8a7SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 1215c70b8031SEmanuele Giuseppe Esposito assert(job->aio_context == qemu_get_current_aio_context()); 1216afe1e8a7SEmanuele Giuseppe Esposito job_pause_point_locked(job); 1217afe1e8a7SEmanuele Giuseppe Esposito } 1218afe1e8a7SEmanuele Giuseppe Esposito ret = job->driver->run(job, &job->err); 1219afe1e8a7SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 1220afe1e8a7SEmanuele Giuseppe Esposito job->ret = ret; 1221ccbfb331SJohn Snow job->deferred_to_main_loop = true; 1222b5a7a057SKevin Wolf job->busy = true; 1223afe1e8a7SEmanuele Giuseppe Esposito } 1224ccbfb331SJohn Snow aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job); 1225ccbfb331SJohn Snow } 1226ccbfb331SJohn Snow 1227ccbfb331SJohn Snow void job_start(Job *job) 1228ccbfb331SJohn Snow { 1229afe1e8a7SEmanuele Giuseppe Esposito assert(qemu_in_main_thread()); 1230afe1e8a7SEmanuele Giuseppe Esposito 1231afe1e8a7SEmanuele Giuseppe Esposito WITH_JOB_LOCK_GUARD() { 1232afe1e8a7SEmanuele Giuseppe Esposito assert(job && !job_started_locked(job) && job->paused && 1233ccbfb331SJohn Snow job->driver && job->driver->run); 1234ccbfb331SJohn Snow job->co = qemu_coroutine_create(job_co_entry, job); 1235ccbfb331SJohn Snow job->pause_count--; 1236ccbfb331SJohn Snow job->busy = true; 1237ccbfb331SJohn Snow job->paused = false; 1238afe1e8a7SEmanuele Giuseppe Esposito job_state_transition_locked(job, JOB_STATUS_RUNNING); 1239afe1e8a7SEmanuele Giuseppe Esposito } 1240ccbfb331SJohn Snow aio_co_enter(job->aio_context, job->co); 1241ccbfb331SJohn Snow } 1242ccbfb331SJohn Snow 1243afe1e8a7SEmanuele Giuseppe Esposito void job_cancel_locked(Job *job, bool force) 12443d70ff53SKevin Wolf { 12453d70ff53SKevin Wolf if (job->status == JOB_STATUS_CONCLUDED) { 1246afe1e8a7SEmanuele Giuseppe Esposito job_do_dismiss_locked(job); 12473d70ff53SKevin Wolf return; 12483d70ff53SKevin Wolf } 1249afe1e8a7SEmanuele Giuseppe Esposito job_cancel_async_locked(job, force); 1250afe1e8a7SEmanuele Giuseppe Esposito if (!job_started_locked(job)) { 1251afe1e8a7SEmanuele Giuseppe Esposito job_completed_locked(job); 12523d70ff53SKevin Wolf } else if (job->deferred_to_main_loop) { 1253401dd096SHanna Reitz /* 1254401dd096SHanna Reitz * job_cancel_async() ignores soft-cancel requests for jobs 1255401dd096SHanna Reitz * that are already done (i.e. deferred to the main loop). We 1256401dd096SHanna Reitz * have to check again whether the job is really cancelled. 125708b83bffSHanna Reitz * (job_cancel_requested() and job_is_cancelled() are equivalent 125808b83bffSHanna Reitz * here, because job_cancel_async() will make soft-cancel 125908b83bffSHanna Reitz * requests no-ops when deferred_to_main_loop is true. We 126008b83bffSHanna Reitz * choose to call job_is_cancelled() to show that we invoke 126108b83bffSHanna Reitz * job_completed_txn_abort() only for force-cancelled jobs.) 1262401dd096SHanna Reitz */ 1263afe1e8a7SEmanuele Giuseppe Esposito if (job_is_cancelled_locked(job)) { 1264afe1e8a7SEmanuele Giuseppe Esposito job_completed_txn_abort_locked(job); 1265401dd096SHanna Reitz } 12663d70ff53SKevin Wolf } else { 1267afe1e8a7SEmanuele Giuseppe Esposito job_enter_cond_locked(job, NULL); 12683d70ff53SKevin Wolf } 12693d70ff53SKevin Wolf } 12703d70ff53SKevin Wolf 1271afe1e8a7SEmanuele Giuseppe Esposito void job_cancel(Job *job, bool force) 1272afe1e8a7SEmanuele Giuseppe Esposito { 1273afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 1274afe1e8a7SEmanuele Giuseppe Esposito job_cancel_locked(job, force); 1275afe1e8a7SEmanuele Giuseppe Esposito } 1276afe1e8a7SEmanuele Giuseppe Esposito 1277afe1e8a7SEmanuele Giuseppe Esposito void job_user_cancel_locked(Job *job, bool force, Error **errp) 1278afe1e8a7SEmanuele Giuseppe Esposito { 1279afe1e8a7SEmanuele Giuseppe Esposito if (job_apply_verb_locked(job, JOB_VERB_CANCEL, errp)) { 1280afe1e8a7SEmanuele Giuseppe Esposito return; 1281afe1e8a7SEmanuele Giuseppe Esposito } 1282afe1e8a7SEmanuele Giuseppe Esposito job_cancel_locked(job, force); 1283afe1e8a7SEmanuele Giuseppe Esposito } 1284afe1e8a7SEmanuele Giuseppe Esposito 12853d70ff53SKevin Wolf void job_user_cancel(Job *job, bool force, Error **errp) 12863d70ff53SKevin Wolf { 1287afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 1288afe1e8a7SEmanuele Giuseppe Esposito job_user_cancel_locked(job, force, errp); 12893d70ff53SKevin Wolf } 12903d70ff53SKevin Wolf 12913d70ff53SKevin Wolf /* A wrapper around job_cancel() taking an Error ** parameter so it may be 12923d70ff53SKevin Wolf * used with job_finish_sync() without the need for (rather nasty) function 1293afe1e8a7SEmanuele Giuseppe Esposito * pointer casts there. 1294afe1e8a7SEmanuele Giuseppe Esposito * 1295afe1e8a7SEmanuele Giuseppe Esposito * Called with job_mutex held. 1296afe1e8a7SEmanuele Giuseppe Esposito */ 1297afe1e8a7SEmanuele Giuseppe Esposito static void job_cancel_err_locked(Job *job, Error **errp) 12983d70ff53SKevin Wolf { 1299afe1e8a7SEmanuele Giuseppe Esposito job_cancel_locked(job, false); 13003d70ff53SKevin Wolf } 13013d70ff53SKevin Wolf 13024cfb3f05SHanna Reitz /** 13034cfb3f05SHanna Reitz * Same as job_cancel_err(), but force-cancel. 1304afe1e8a7SEmanuele Giuseppe Esposito * Called with job_mutex held. 13054cfb3f05SHanna Reitz */ 1306afe1e8a7SEmanuele Giuseppe Esposito static void job_force_cancel_err_locked(Job *job, Error **errp) 13073d70ff53SKevin Wolf { 1308afe1e8a7SEmanuele Giuseppe Esposito job_cancel_locked(job, true); 1309afe1e8a7SEmanuele Giuseppe Esposito } 1310afe1e8a7SEmanuele Giuseppe Esposito 1311afe1e8a7SEmanuele Giuseppe Esposito int job_cancel_sync_locked(Job *job, bool force) 1312afe1e8a7SEmanuele Giuseppe Esposito { 1313afe1e8a7SEmanuele Giuseppe Esposito if (force) { 1314afe1e8a7SEmanuele Giuseppe Esposito return job_finish_sync_locked(job, &job_force_cancel_err_locked, NULL); 1315afe1e8a7SEmanuele Giuseppe Esposito } else { 1316afe1e8a7SEmanuele Giuseppe Esposito return job_finish_sync_locked(job, &job_cancel_err_locked, NULL); 1317afe1e8a7SEmanuele Giuseppe Esposito } 13184cfb3f05SHanna Reitz } 13194cfb3f05SHanna Reitz 13204cfb3f05SHanna Reitz int job_cancel_sync(Job *job, bool force) 13214cfb3f05SHanna Reitz { 1322afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 1323afe1e8a7SEmanuele Giuseppe Esposito return job_cancel_sync_locked(job, force); 13244cfb3f05SHanna Reitz } 13253d70ff53SKevin Wolf 13263d70ff53SKevin Wolf void job_cancel_sync_all(void) 13273d70ff53SKevin Wolf { 13283d70ff53SKevin Wolf Job *job; 13293d70ff53SKevin Wolf AioContext *aio_context; 1330afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 13313d70ff53SKevin Wolf 1332afe1e8a7SEmanuele Giuseppe Esposito while ((job = job_next_locked(NULL))) { 13333d70ff53SKevin Wolf aio_context = job->aio_context; 13343d70ff53SKevin Wolf aio_context_acquire(aio_context); 1335afe1e8a7SEmanuele Giuseppe Esposito job_cancel_sync_locked(job, true); 13363d70ff53SKevin Wolf aio_context_release(aio_context); 13373d70ff53SKevin Wolf } 13383d70ff53SKevin Wolf } 13393d70ff53SKevin Wolf 1340afe1e8a7SEmanuele Giuseppe Esposito int job_complete_sync_locked(Job *job, Error **errp) 13413d70ff53SKevin Wolf { 1342afe1e8a7SEmanuele Giuseppe Esposito return job_finish_sync_locked(job, job_complete_locked, errp); 13433d70ff53SKevin Wolf } 13443d70ff53SKevin Wolf 1345afe1e8a7SEmanuele Giuseppe Esposito int job_complete_sync(Job *job, Error **errp) 1346afe1e8a7SEmanuele Giuseppe Esposito { 1347afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 1348afe1e8a7SEmanuele Giuseppe Esposito return job_complete_sync_locked(job, errp); 1349afe1e8a7SEmanuele Giuseppe Esposito } 1350afe1e8a7SEmanuele Giuseppe Esposito 1351afe1e8a7SEmanuele Giuseppe Esposito void job_complete_locked(Job *job, Error **errp) 13523453d972SKevin Wolf { 13533453d972SKevin Wolf /* Should not be reachable via external interface for internal jobs */ 13543453d972SKevin Wolf assert(job->id); 1355c70b8031SEmanuele Giuseppe Esposito GLOBAL_STATE_CODE(); 1356afe1e8a7SEmanuele Giuseppe Esposito if (job_apply_verb_locked(job, JOB_VERB_COMPLETE, errp)) { 13573453d972SKevin Wolf return; 13583453d972SKevin Wolf } 1359afe1e8a7SEmanuele Giuseppe Esposito if (job_cancel_requested_locked(job) || !job->driver->complete) { 13603453d972SKevin Wolf error_setg(errp, "The active block job '%s' cannot be completed", 13613453d972SKevin Wolf job->id); 13623453d972SKevin Wolf return; 13633453d972SKevin Wolf } 13643453d972SKevin Wolf 1365afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 13663453d972SKevin Wolf job->driver->complete(job, errp); 1367afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 13683453d972SKevin Wolf } 13693453d972SKevin Wolf 1370afe1e8a7SEmanuele Giuseppe Esposito void job_complete(Job *job, Error **errp) 1371afe1e8a7SEmanuele Giuseppe Esposito { 1372afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 1373afe1e8a7SEmanuele Giuseppe Esposito job_complete_locked(job, errp); 1374afe1e8a7SEmanuele Giuseppe Esposito } 1375afe1e8a7SEmanuele Giuseppe Esposito 1376afe1e8a7SEmanuele Giuseppe Esposito int job_finish_sync_locked(Job *job, 1377afe1e8a7SEmanuele Giuseppe Esposito void (*finish)(Job *, Error **errp), 1378afe1e8a7SEmanuele Giuseppe Esposito Error **errp) 13796a74c075SKevin Wolf { 13806a74c075SKevin Wolf Error *local_err = NULL; 13816a74c075SKevin Wolf int ret; 13826a74c075SKevin Wolf 1383afe1e8a7SEmanuele Giuseppe Esposito job_ref_locked(job); 13846a74c075SKevin Wolf 13856a74c075SKevin Wolf if (finish) { 13866a74c075SKevin Wolf finish(job, &local_err); 13876a74c075SKevin Wolf } 13886a74c075SKevin Wolf if (local_err) { 13896a74c075SKevin Wolf error_propagate(errp, local_err); 1390afe1e8a7SEmanuele Giuseppe Esposito job_unref_locked(job); 13916a74c075SKevin Wolf return -EBUSY; 13926a74c075SKevin Wolf } 1393de0fbe64SKevin Wolf 1394afe1e8a7SEmanuele Giuseppe Esposito job_unlock(); 1395cfe29d82SKevin Wolf AIO_WAIT_WHILE(job->aio_context, 1396bb0c9409SVladimir Sementsov-Ogievskiy (job_enter(job), !job_is_completed(job))); 1397afe1e8a7SEmanuele Giuseppe Esposito job_lock(); 1398de0fbe64SKevin Wolf 1399afe1e8a7SEmanuele Giuseppe Esposito ret = (job_is_cancelled_locked(job) && job->ret == 0) 1400afe1e8a7SEmanuele Giuseppe Esposito ? -ECANCELED : job->ret; 1401afe1e8a7SEmanuele Giuseppe Esposito job_unref_locked(job); 14026a74c075SKevin Wolf return ret; 14036a74c075SKevin Wolf } 1404afe1e8a7SEmanuele Giuseppe Esposito 1405afe1e8a7SEmanuele Giuseppe Esposito int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) 1406afe1e8a7SEmanuele Giuseppe Esposito { 1407afe1e8a7SEmanuele Giuseppe Esposito JOB_LOCK_GUARD(); 1408afe1e8a7SEmanuele Giuseppe Esposito return job_finish_sync_locked(job, finish, errp); 1409afe1e8a7SEmanuele Giuseppe Esposito } 1410