12f0c9fe6SPaolo Bonzini /* 22f0c9fe6SPaolo Bonzini * QEMU System Emulator block driver 32f0c9fe6SPaolo Bonzini * 42f0c9fe6SPaolo Bonzini * Copyright (c) 2011 IBM Corp. 52f0c9fe6SPaolo Bonzini * Copyright (c) 2012 Red Hat, Inc. 62f0c9fe6SPaolo Bonzini * 72f0c9fe6SPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 82f0c9fe6SPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 92f0c9fe6SPaolo Bonzini * in the Software without restriction, including without limitation the rights 102f0c9fe6SPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 112f0c9fe6SPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 122f0c9fe6SPaolo Bonzini * furnished to do so, subject to the following conditions: 132f0c9fe6SPaolo Bonzini * 142f0c9fe6SPaolo Bonzini * The above copyright notice and this permission notice shall be included in 152f0c9fe6SPaolo Bonzini * all copies or substantial portions of the Software. 162f0c9fe6SPaolo Bonzini * 172f0c9fe6SPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 182f0c9fe6SPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 192f0c9fe6SPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 202f0c9fe6SPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 212f0c9fe6SPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 222f0c9fe6SPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 232f0c9fe6SPaolo Bonzini * THE SOFTWARE. 242f0c9fe6SPaolo Bonzini */ 252f0c9fe6SPaolo Bonzini 26d38ea87aSPeter Maydell #include "qemu/osdep.h" 272f0c9fe6SPaolo Bonzini #include "qemu-common.h" 28737e150eSPaolo Bonzini #include "block/block.h" 29c87621eaSJohn Snow #include "block/blockjob_int.h" 30737e150eSPaolo Bonzini #include "block/block_int.h" 31373340b2SMax Reitz #include "sysemu/block-backend.h" 32cc7a8ea7SMarkus Armbruster #include "qapi/qmp/qerror.h" 337b1b5d19SPaolo Bonzini #include "qapi/qmp/qjson.h" 3410817bf0SDaniel P. Berrange #include "qemu/coroutine.h" 357f0317cfSAlberto Garcia #include "qemu/id.h" 362f0c9fe6SPaolo Bonzini #include "qmp-commands.h" 371de7afc9SPaolo Bonzini #include "qemu/timer.h" 385a2d2cbdSWenchao Xia #include "qapi-event.h" 392f0c9fe6SPaolo Bonzini 408254b6d9SJohn Snow static void block_job_event_cancelled(BlockJob *job); 418254b6d9SJohn Snow static void block_job_event_completed(BlockJob *job, const char *msg); 428254b6d9SJohn Snow 43c55a832fSFam Zheng /* Transactional group of block jobs */ 44c55a832fSFam Zheng struct BlockJobTxn { 45c55a832fSFam Zheng 46c55a832fSFam Zheng /* Is this txn being cancelled? */ 47c55a832fSFam Zheng bool aborting; 48c55a832fSFam Zheng 49c55a832fSFam Zheng /* List of jobs */ 50c55a832fSFam Zheng QLIST_HEAD(, BlockJob) jobs; 51c55a832fSFam Zheng 52c55a832fSFam Zheng /* Reference count */ 53c55a832fSFam Zheng int refcnt; 54c55a832fSFam Zheng }; 55c55a832fSFam Zheng 56a7112795SAlberto Garcia static QLIST_HEAD(, BlockJob) block_jobs = QLIST_HEAD_INITIALIZER(block_jobs); 57a7112795SAlberto Garcia 5888691b37SPaolo Bonzini /* 5988691b37SPaolo Bonzini * The block job API is composed of two categories of functions. 6088691b37SPaolo Bonzini * 6188691b37SPaolo Bonzini * The first includes functions used by the monitor. The monitor is 6288691b37SPaolo Bonzini * peculiar in that it accesses the block job list with block_job_get, and 6388691b37SPaolo Bonzini * therefore needs consistency across block_job_get and the actual operation 6488691b37SPaolo Bonzini * (e.g. block_job_set_speed). The consistency is achieved with 6588691b37SPaolo Bonzini * aio_context_acquire/release. These functions are declared in blockjob.h. 6688691b37SPaolo Bonzini * 6788691b37SPaolo Bonzini * The second includes functions used by the block job drivers and sometimes 6888691b37SPaolo Bonzini * by the core block layer. These do not care about locking, because the 6988691b37SPaolo Bonzini * whole coroutine runs under the AioContext lock, and are declared in 7088691b37SPaolo Bonzini * blockjob_int.h. 7188691b37SPaolo Bonzini */ 7288691b37SPaolo Bonzini 73a7112795SAlberto Garcia BlockJob *block_job_next(BlockJob *job) 74a7112795SAlberto Garcia { 75a7112795SAlberto Garcia if (!job) { 76a7112795SAlberto Garcia return QLIST_FIRST(&block_jobs); 77a7112795SAlberto Garcia } 78a7112795SAlberto Garcia return QLIST_NEXT(job, job_list); 79a7112795SAlberto Garcia } 80a7112795SAlberto Garcia 81ffb1f10cSAlberto Garcia BlockJob *block_job_get(const char *id) 82ffb1f10cSAlberto Garcia { 83ffb1f10cSAlberto Garcia BlockJob *job; 84ffb1f10cSAlberto Garcia 85ffb1f10cSAlberto Garcia QLIST_FOREACH(job, &block_jobs, job_list) { 86559b935fSJohn Snow if (job->id && !strcmp(id, job->id)) { 87ffb1f10cSAlberto Garcia return job; 88ffb1f10cSAlberto Garcia } 89ffb1f10cSAlberto Garcia } 90ffb1f10cSAlberto Garcia 91ffb1f10cSAlberto Garcia return NULL; 92ffb1f10cSAlberto Garcia } 93ffb1f10cSAlberto Garcia 94c8ab5c2dSPaolo Bonzini BlockJobTxn *block_job_txn_new(void) 95c8ab5c2dSPaolo Bonzini { 96c8ab5c2dSPaolo Bonzini BlockJobTxn *txn = g_new0(BlockJobTxn, 1); 97c8ab5c2dSPaolo Bonzini QLIST_INIT(&txn->jobs); 98c8ab5c2dSPaolo Bonzini txn->refcnt = 1; 99c8ab5c2dSPaolo Bonzini return txn; 100c8ab5c2dSPaolo Bonzini } 101c8ab5c2dSPaolo Bonzini 102c8ab5c2dSPaolo Bonzini static void block_job_txn_ref(BlockJobTxn *txn) 103c8ab5c2dSPaolo Bonzini { 104c8ab5c2dSPaolo Bonzini txn->refcnt++; 105c8ab5c2dSPaolo Bonzini } 106c8ab5c2dSPaolo Bonzini 107c8ab5c2dSPaolo Bonzini void block_job_txn_unref(BlockJobTxn *txn) 108c8ab5c2dSPaolo Bonzini { 109c8ab5c2dSPaolo Bonzini if (txn && --txn->refcnt == 0) { 110c8ab5c2dSPaolo Bonzini g_free(txn); 111c8ab5c2dSPaolo Bonzini } 112c8ab5c2dSPaolo Bonzini } 113c8ab5c2dSPaolo Bonzini 114c8ab5c2dSPaolo Bonzini void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job) 115c8ab5c2dSPaolo Bonzini { 116c8ab5c2dSPaolo Bonzini if (!txn) { 117c8ab5c2dSPaolo Bonzini return; 118c8ab5c2dSPaolo Bonzini } 119c8ab5c2dSPaolo Bonzini 120c8ab5c2dSPaolo Bonzini assert(!job->txn); 121c8ab5c2dSPaolo Bonzini job->txn = txn; 122c8ab5c2dSPaolo Bonzini 123c8ab5c2dSPaolo Bonzini QLIST_INSERT_HEAD(&txn->jobs, job, txn_list); 124c8ab5c2dSPaolo Bonzini block_job_txn_ref(txn); 125c8ab5c2dSPaolo Bonzini } 126c8ab5c2dSPaolo Bonzini 127f321dcb5SPaolo Bonzini static void block_job_pause(BlockJob *job) 128f321dcb5SPaolo Bonzini { 129f321dcb5SPaolo Bonzini job->pause_count++; 130f321dcb5SPaolo Bonzini } 131f321dcb5SPaolo Bonzini 132f321dcb5SPaolo Bonzini static void block_job_resume(BlockJob *job) 133f321dcb5SPaolo Bonzini { 134f321dcb5SPaolo Bonzini assert(job->pause_count > 0); 135f321dcb5SPaolo Bonzini job->pause_count--; 136f321dcb5SPaolo Bonzini if (job->pause_count) { 137f321dcb5SPaolo Bonzini return; 138f321dcb5SPaolo Bonzini } 139f321dcb5SPaolo Bonzini block_job_enter(job); 140f321dcb5SPaolo Bonzini } 141f321dcb5SPaolo Bonzini 14205b0d8e3SPaolo Bonzini static void block_job_ref(BlockJob *job) 14305b0d8e3SPaolo Bonzini { 14405b0d8e3SPaolo Bonzini ++job->refcnt; 14505b0d8e3SPaolo Bonzini } 14605b0d8e3SPaolo Bonzini 14705b0d8e3SPaolo Bonzini static void block_job_attached_aio_context(AioContext *new_context, 14805b0d8e3SPaolo Bonzini void *opaque); 14905b0d8e3SPaolo Bonzini static void block_job_detach_aio_context(void *opaque); 15005b0d8e3SPaolo Bonzini 15105b0d8e3SPaolo Bonzini static void block_job_unref(BlockJob *job) 15205b0d8e3SPaolo Bonzini { 15305b0d8e3SPaolo Bonzini if (--job->refcnt == 0) { 15405b0d8e3SPaolo Bonzini BlockDriverState *bs = blk_bs(job->blk); 15505b0d8e3SPaolo Bonzini bs->job = NULL; 15605b0d8e3SPaolo Bonzini block_job_remove_all_bdrv(job); 15705b0d8e3SPaolo Bonzini blk_remove_aio_context_notifier(job->blk, 15805b0d8e3SPaolo Bonzini block_job_attached_aio_context, 15905b0d8e3SPaolo Bonzini block_job_detach_aio_context, job); 16005b0d8e3SPaolo Bonzini blk_unref(job->blk); 16105b0d8e3SPaolo Bonzini error_free(job->blocker); 16205b0d8e3SPaolo Bonzini g_free(job->id); 16305b0d8e3SPaolo Bonzini QLIST_REMOVE(job, job_list); 16405b0d8e3SPaolo Bonzini g_free(job); 16505b0d8e3SPaolo Bonzini } 16605b0d8e3SPaolo Bonzini } 16705b0d8e3SPaolo Bonzini 168463e0be1SStefan Hajnoczi static void block_job_attached_aio_context(AioContext *new_context, 169463e0be1SStefan Hajnoczi void *opaque) 170463e0be1SStefan Hajnoczi { 171463e0be1SStefan Hajnoczi BlockJob *job = opaque; 172463e0be1SStefan Hajnoczi 173463e0be1SStefan Hajnoczi if (job->driver->attached_aio_context) { 174463e0be1SStefan Hajnoczi job->driver->attached_aio_context(job, new_context); 175463e0be1SStefan Hajnoczi } 176463e0be1SStefan Hajnoczi 177463e0be1SStefan Hajnoczi block_job_resume(job); 178463e0be1SStefan Hajnoczi } 179463e0be1SStefan Hajnoczi 180bae8196dSPaolo Bonzini static void block_job_drain(BlockJob *job) 181bae8196dSPaolo Bonzini { 182bae8196dSPaolo Bonzini /* If job is !job->busy this kicks it into the next pause point. */ 183bae8196dSPaolo Bonzini block_job_enter(job); 184bae8196dSPaolo Bonzini 185bae8196dSPaolo Bonzini blk_drain(job->blk); 186bae8196dSPaolo Bonzini if (job->driver->drain) { 187bae8196dSPaolo Bonzini job->driver->drain(job); 188bae8196dSPaolo Bonzini } 189bae8196dSPaolo Bonzini } 190bae8196dSPaolo Bonzini 191463e0be1SStefan Hajnoczi static void block_job_detach_aio_context(void *opaque) 192463e0be1SStefan Hajnoczi { 193463e0be1SStefan Hajnoczi BlockJob *job = opaque; 194463e0be1SStefan Hajnoczi 195463e0be1SStefan Hajnoczi /* In case the job terminates during aio_poll()... */ 196463e0be1SStefan Hajnoczi block_job_ref(job); 197463e0be1SStefan Hajnoczi 198463e0be1SStefan Hajnoczi block_job_pause(job); 199463e0be1SStefan Hajnoczi 200463e0be1SStefan Hajnoczi while (!job->paused && !job->completed) { 201bae8196dSPaolo Bonzini block_job_drain(job); 202463e0be1SStefan Hajnoczi } 203463e0be1SStefan Hajnoczi 204463e0be1SStefan Hajnoczi block_job_unref(job); 205463e0be1SStefan Hajnoczi } 206463e0be1SStefan Hajnoczi 207f321dcb5SPaolo Bonzini static char *child_job_get_parent_desc(BdrvChild *c) 208f321dcb5SPaolo Bonzini { 209f321dcb5SPaolo Bonzini BlockJob *job = c->opaque; 210f321dcb5SPaolo Bonzini return g_strdup_printf("%s job '%s'", 211f321dcb5SPaolo Bonzini BlockJobType_lookup[job->driver->job_type], 212f321dcb5SPaolo Bonzini job->id); 213f321dcb5SPaolo Bonzini } 214f321dcb5SPaolo Bonzini 215f321dcb5SPaolo Bonzini static const BdrvChildRole child_job = { 216f321dcb5SPaolo Bonzini .get_parent_desc = child_job_get_parent_desc, 217f321dcb5SPaolo Bonzini .stay_at_node = true, 218f321dcb5SPaolo Bonzini }; 219f321dcb5SPaolo Bonzini 220f321dcb5SPaolo Bonzini static void block_job_drained_begin(void *opaque) 221f321dcb5SPaolo Bonzini { 222f321dcb5SPaolo Bonzini BlockJob *job = opaque; 223f321dcb5SPaolo Bonzini block_job_pause(job); 224f321dcb5SPaolo Bonzini } 225f321dcb5SPaolo Bonzini 226f321dcb5SPaolo Bonzini static void block_job_drained_end(void *opaque) 227f321dcb5SPaolo Bonzini { 228f321dcb5SPaolo Bonzini BlockJob *job = opaque; 229f321dcb5SPaolo Bonzini block_job_resume(job); 230f321dcb5SPaolo Bonzini } 231f321dcb5SPaolo Bonzini 232f321dcb5SPaolo Bonzini static const BlockDevOps block_job_dev_ops = { 233f321dcb5SPaolo Bonzini .drained_begin = block_job_drained_begin, 234f321dcb5SPaolo Bonzini .drained_end = block_job_drained_end, 235f321dcb5SPaolo Bonzini }; 236f321dcb5SPaolo Bonzini 237bbc02b90SKevin Wolf void block_job_remove_all_bdrv(BlockJob *job) 238bbc02b90SKevin Wolf { 239bbc02b90SKevin Wolf GSList *l; 240bbc02b90SKevin Wolf for (l = job->nodes; l; l = l->next) { 241bbc02b90SKevin Wolf BdrvChild *c = l->data; 242bbc02b90SKevin Wolf bdrv_op_unblock_all(c->bs, job->blocker); 243bbc02b90SKevin Wolf bdrv_root_unref_child(c); 244bbc02b90SKevin Wolf } 245bbc02b90SKevin Wolf g_slist_free(job->nodes); 246bbc02b90SKevin Wolf job->nodes = NULL; 247bbc02b90SKevin Wolf } 248bbc02b90SKevin Wolf 24976d554e2SKevin Wolf int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, 25076d554e2SKevin Wolf uint64_t perm, uint64_t shared_perm, Error **errp) 25123d402d4SAlberto Garcia { 25276d554e2SKevin Wolf BdrvChild *c; 25376d554e2SKevin Wolf 25476d554e2SKevin Wolf c = bdrv_root_attach_child(bs, name, &child_job, perm, shared_perm, 25576d554e2SKevin Wolf job, errp); 25676d554e2SKevin Wolf if (c == NULL) { 25776d554e2SKevin Wolf return -EPERM; 25876d554e2SKevin Wolf } 25976d554e2SKevin Wolf 26076d554e2SKevin Wolf job->nodes = g_slist_prepend(job->nodes, c); 26123d402d4SAlberto Garcia bdrv_ref(bs); 26223d402d4SAlberto Garcia bdrv_op_block_all(bs, job->blocker); 26376d554e2SKevin Wolf 26476d554e2SKevin Wolf return 0; 26523d402d4SAlberto Garcia } 26623d402d4SAlberto Garcia 267559b935fSJohn Snow bool block_job_is_internal(BlockJob *job) 268559b935fSJohn Snow { 269559b935fSJohn Snow return (job->id == NULL); 270559b935fSJohn Snow } 271559b935fSJohn Snow 2725ccac6f1SJohn Snow static bool block_job_started(BlockJob *job) 2735ccac6f1SJohn Snow { 2745ccac6f1SJohn Snow return job->co; 2755ccac6f1SJohn Snow } 2765ccac6f1SJohn Snow 277e3796a24SJohn Snow /** 278e3796a24SJohn Snow * All jobs must allow a pause point before entering their job proper. This 279e3796a24SJohn Snow * ensures that jobs can be paused prior to being started, then resumed later. 280e3796a24SJohn Snow */ 281e3796a24SJohn Snow static void coroutine_fn block_job_co_entry(void *opaque) 282e3796a24SJohn Snow { 283e3796a24SJohn Snow BlockJob *job = opaque; 284e3796a24SJohn Snow 285e3796a24SJohn Snow assert(job && job->driver && job->driver->start); 286e3796a24SJohn Snow block_job_pause_point(job); 287e3796a24SJohn Snow job->driver->start(job); 288e3796a24SJohn Snow } 289e3796a24SJohn Snow 2905ccac6f1SJohn Snow void block_job_start(BlockJob *job) 2915ccac6f1SJohn Snow { 2925ccac6f1SJohn Snow assert(job && !block_job_started(job) && job->paused && 293e3796a24SJohn Snow job->driver && job->driver->start); 294e3796a24SJohn Snow job->co = qemu_coroutine_create(block_job_co_entry, job); 295e3796a24SJohn Snow job->pause_count--; 2965ccac6f1SJohn Snow job->busy = true; 297e3796a24SJohn Snow job->paused = false; 298aef4278cSFam Zheng bdrv_coroutine_enter(blk_bs(job->blk), job->co); 2995ccac6f1SJohn Snow } 3005ccac6f1SJohn Snow 301c55a832fSFam Zheng static void block_job_completed_single(BlockJob *job) 302c55a832fSFam Zheng { 3034fb588e9SPaolo Bonzini assert(job->completed); 3044fb588e9SPaolo Bonzini 305c55a832fSFam Zheng if (!job->ret) { 306c55a832fSFam Zheng if (job->driver->commit) { 307c55a832fSFam Zheng job->driver->commit(job); 308c55a832fSFam Zheng } 309c55a832fSFam Zheng } else { 310c55a832fSFam Zheng if (job->driver->abort) { 311c55a832fSFam Zheng job->driver->abort(job); 312c55a832fSFam Zheng } 313c55a832fSFam Zheng } 314e8a40bf7SJohn Snow if (job->driver->clean) { 315e8a40bf7SJohn Snow job->driver->clean(job); 316e8a40bf7SJohn Snow } 3178254b6d9SJohn Snow 3188254b6d9SJohn Snow if (job->cb) { 319c55a832fSFam Zheng job->cb(job->opaque, job->ret); 3208254b6d9SJohn Snow } 3215ccac6f1SJohn Snow 3225ccac6f1SJohn Snow /* Emit events only if we actually started */ 3235ccac6f1SJohn Snow if (block_job_started(job)) { 3248254b6d9SJohn Snow if (block_job_is_cancelled(job)) { 3258254b6d9SJohn Snow block_job_event_cancelled(job); 3268254b6d9SJohn Snow } else { 3278254b6d9SJohn Snow const char *msg = NULL; 3288254b6d9SJohn Snow if (job->ret < 0) { 3298254b6d9SJohn Snow msg = strerror(-job->ret); 3308254b6d9SJohn Snow } 3318254b6d9SJohn Snow block_job_event_completed(job, msg); 3328254b6d9SJohn Snow } 3335ccac6f1SJohn Snow } 3348254b6d9SJohn Snow 335c55a832fSFam Zheng if (job->txn) { 3361e93b9fbSVladimir Sementsov-Ogievskiy QLIST_REMOVE(job, txn_list); 337c55a832fSFam Zheng block_job_txn_unref(job->txn); 338c55a832fSFam Zheng } 339c55a832fSFam Zheng block_job_unref(job); 340c55a832fSFam Zheng } 341c55a832fSFam Zheng 3424c241cf5SPaolo Bonzini static void block_job_cancel_async(BlockJob *job) 3434c241cf5SPaolo Bonzini { 3444c241cf5SPaolo Bonzini if (job->iostatus != BLOCK_DEVICE_IO_STATUS_OK) { 3454c241cf5SPaolo Bonzini block_job_iostatus_reset(job); 3464c241cf5SPaolo Bonzini } 3474c241cf5SPaolo Bonzini if (job->user_paused) { 3484c241cf5SPaolo Bonzini /* Do not call block_job_enter here, the caller will handle it. */ 3494c241cf5SPaolo Bonzini job->user_paused = false; 3504c241cf5SPaolo Bonzini job->pause_count--; 3514c241cf5SPaolo Bonzini } 3524c241cf5SPaolo Bonzini job->cancelled = true; 3534c241cf5SPaolo Bonzini } 3544c241cf5SPaolo Bonzini 355c8ab5c2dSPaolo Bonzini static int block_job_finish_sync(BlockJob *job, 356c8ab5c2dSPaolo Bonzini void (*finish)(BlockJob *, Error **errp), 357c8ab5c2dSPaolo Bonzini Error **errp) 358c8ab5c2dSPaolo Bonzini { 359c8ab5c2dSPaolo Bonzini Error *local_err = NULL; 360c8ab5c2dSPaolo Bonzini int ret; 361c8ab5c2dSPaolo Bonzini 362c8ab5c2dSPaolo Bonzini assert(blk_bs(job->blk)->job == job); 363c8ab5c2dSPaolo Bonzini 364c8ab5c2dSPaolo Bonzini block_job_ref(job); 365c8ab5c2dSPaolo Bonzini 3664fb588e9SPaolo Bonzini if (finish) { 367c8ab5c2dSPaolo Bonzini finish(job, &local_err); 3684fb588e9SPaolo Bonzini } 369c8ab5c2dSPaolo Bonzini if (local_err) { 370c8ab5c2dSPaolo Bonzini error_propagate(errp, local_err); 371c8ab5c2dSPaolo Bonzini block_job_unref(job); 372c8ab5c2dSPaolo Bonzini return -EBUSY; 373c8ab5c2dSPaolo Bonzini } 374c8ab5c2dSPaolo Bonzini /* block_job_drain calls block_job_enter, and it should be enough to 375c8ab5c2dSPaolo Bonzini * induce progress until the job completes or moves to the main thread. 376c8ab5c2dSPaolo Bonzini */ 377c8ab5c2dSPaolo Bonzini while (!job->deferred_to_main_loop && !job->completed) { 378c8ab5c2dSPaolo Bonzini block_job_drain(job); 379c8ab5c2dSPaolo Bonzini } 380c8ab5c2dSPaolo Bonzini while (!job->completed) { 381c8ab5c2dSPaolo Bonzini aio_poll(qemu_get_aio_context(), true); 382c8ab5c2dSPaolo Bonzini } 383c8ab5c2dSPaolo Bonzini ret = (job->cancelled && job->ret == 0) ? -ECANCELED : job->ret; 384c8ab5c2dSPaolo Bonzini block_job_unref(job); 385c8ab5c2dSPaolo Bonzini return ret; 386c8ab5c2dSPaolo Bonzini } 387c8ab5c2dSPaolo Bonzini 388c55a832fSFam Zheng static void block_job_completed_txn_abort(BlockJob *job) 389c55a832fSFam Zheng { 390c55a832fSFam Zheng AioContext *ctx; 391c55a832fSFam Zheng BlockJobTxn *txn = job->txn; 3924fb588e9SPaolo Bonzini BlockJob *other_job; 393c55a832fSFam Zheng 394c55a832fSFam Zheng if (txn->aborting) { 395c55a832fSFam Zheng /* 396c55a832fSFam Zheng * We are cancelled by another job, which will handle everything. 397c55a832fSFam Zheng */ 398c55a832fSFam Zheng return; 399c55a832fSFam Zheng } 400c55a832fSFam Zheng txn->aborting = true; 4014fb588e9SPaolo Bonzini block_job_txn_ref(txn); 4024fb588e9SPaolo Bonzini 403c55a832fSFam Zheng /* We are the first failed job. Cancel other jobs. */ 404c55a832fSFam Zheng QLIST_FOREACH(other_job, &txn->jobs, txn_list) { 405b6d2e599SKevin Wolf ctx = blk_get_aio_context(other_job->blk); 406c55a832fSFam Zheng aio_context_acquire(ctx); 407c55a832fSFam Zheng } 4084fb588e9SPaolo Bonzini 4094fb588e9SPaolo Bonzini /* Other jobs are effectively cancelled by us, set the status for 410c55a832fSFam Zheng * them; this job, however, may or may not be cancelled, depending 411c55a832fSFam Zheng * on the caller, so leave it. */ 4124fb588e9SPaolo Bonzini QLIST_FOREACH(other_job, &txn->jobs, txn_list) { 413c55a832fSFam Zheng if (other_job != job) { 4144c241cf5SPaolo Bonzini block_job_cancel_async(other_job); 415c55a832fSFam Zheng } 416c55a832fSFam Zheng } 4174fb588e9SPaolo Bonzini while (!QLIST_EMPTY(&txn->jobs)) { 4184fb588e9SPaolo Bonzini other_job = QLIST_FIRST(&txn->jobs); 419b6d2e599SKevin Wolf ctx = blk_get_aio_context(other_job->blk); 4204fb588e9SPaolo Bonzini if (!other_job->completed) { 4214fb588e9SPaolo Bonzini assert(other_job->cancelled); 4224fb588e9SPaolo Bonzini block_job_finish_sync(other_job, NULL, NULL); 4234fb588e9SPaolo Bonzini } 424c55a832fSFam Zheng block_job_completed_single(other_job); 425c55a832fSFam Zheng aio_context_release(ctx); 426c55a832fSFam Zheng } 4274fb588e9SPaolo Bonzini 4284fb588e9SPaolo Bonzini block_job_txn_unref(txn); 429c55a832fSFam Zheng } 430c55a832fSFam Zheng 431c55a832fSFam Zheng static void block_job_completed_txn_success(BlockJob *job) 432c55a832fSFam Zheng { 433c55a832fSFam Zheng AioContext *ctx; 434c55a832fSFam Zheng BlockJobTxn *txn = job->txn; 435c55a832fSFam Zheng BlockJob *other_job, *next; 436c55a832fSFam Zheng /* 437c55a832fSFam Zheng * Successful completion, see if there are other running jobs in this 438c55a832fSFam Zheng * txn. 439c55a832fSFam Zheng */ 440c55a832fSFam Zheng QLIST_FOREACH(other_job, &txn->jobs, txn_list) { 441c55a832fSFam Zheng if (!other_job->completed) { 442c55a832fSFam Zheng return; 443c55a832fSFam Zheng } 444c55a832fSFam Zheng } 445c55a832fSFam Zheng /* We are the last completed job, commit the transaction. */ 446c55a832fSFam Zheng QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) { 447b6d2e599SKevin Wolf ctx = blk_get_aio_context(other_job->blk); 448c55a832fSFam Zheng aio_context_acquire(ctx); 449c55a832fSFam Zheng assert(other_job->ret == 0); 450c55a832fSFam Zheng block_job_completed_single(other_job); 451c55a832fSFam Zheng aio_context_release(ctx); 452c55a832fSFam Zheng } 453c55a832fSFam Zheng } 454c55a832fSFam Zheng 4552f0c9fe6SPaolo Bonzini void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) 4562f0c9fe6SPaolo Bonzini { 4572f0c9fe6SPaolo Bonzini Error *local_err = NULL; 4582f0c9fe6SPaolo Bonzini 4593fc4b10aSFam Zheng if (!job->driver->set_speed) { 460c6bd8c70SMarkus Armbruster error_setg(errp, QERR_UNSUPPORTED); 4612f0c9fe6SPaolo Bonzini return; 4622f0c9fe6SPaolo Bonzini } 4633fc4b10aSFam Zheng job->driver->set_speed(job, speed, &local_err); 46484d18f06SMarkus Armbruster if (local_err) { 4652f0c9fe6SPaolo Bonzini error_propagate(errp, local_err); 4662f0c9fe6SPaolo Bonzini return; 4672f0c9fe6SPaolo Bonzini } 4682f0c9fe6SPaolo Bonzini 4692f0c9fe6SPaolo Bonzini job->speed = speed; 4702f0c9fe6SPaolo Bonzini } 4712f0c9fe6SPaolo Bonzini 472aeae883bSPaolo Bonzini void block_job_complete(BlockJob *job, Error **errp) 473aeae883bSPaolo Bonzini { 474559b935fSJohn Snow /* Should not be reachable via external interface for internal jobs */ 475559b935fSJohn Snow assert(job->id); 4765ccac6f1SJohn Snow if (job->pause_count || job->cancelled || 4775ccac6f1SJohn Snow !block_job_started(job) || !job->driver->complete) { 4789df229c3SAlberto Garcia error_setg(errp, "The active block job '%s' cannot be completed", 4799df229c3SAlberto Garcia job->id); 480aeae883bSPaolo Bonzini return; 481aeae883bSPaolo Bonzini } 482aeae883bSPaolo Bonzini 4833fc4b10aSFam Zheng job->driver->complete(job, errp); 484aeae883bSPaolo Bonzini } 485aeae883bSPaolo Bonzini 4860df4ba58SJohn Snow void block_job_user_pause(BlockJob *job) 4870df4ba58SJohn Snow { 4880df4ba58SJohn Snow job->user_paused = true; 4890df4ba58SJohn Snow block_job_pause(job); 4900df4ba58SJohn Snow } 4910df4ba58SJohn Snow 4920df4ba58SJohn Snow bool block_job_user_paused(BlockJob *job) 4930df4ba58SJohn Snow { 4946573d9c6SPaolo Bonzini return job->user_paused; 4950df4ba58SJohn Snow } 4960df4ba58SJohn Snow 4970df4ba58SJohn Snow void block_job_user_resume(BlockJob *job) 4980df4ba58SJohn Snow { 4990df4ba58SJohn Snow if (job && job->user_paused && job->pause_count > 0) { 5002caf63a9SPaolo Bonzini block_job_iostatus_reset(job); 5014c241cf5SPaolo Bonzini job->user_paused = false; 5020df4ba58SJohn Snow block_job_resume(job); 5030df4ba58SJohn Snow } 5040df4ba58SJohn Snow } 5050df4ba58SJohn Snow 5068acc72a4SPaolo Bonzini void block_job_cancel(BlockJob *job) 5078acc72a4SPaolo Bonzini { 5085ccac6f1SJohn Snow if (block_job_started(job)) { 5094c241cf5SPaolo Bonzini block_job_cancel_async(job); 510751ebd76SFam Zheng block_job_enter(job); 5115ccac6f1SJohn Snow } else { 5125ccac6f1SJohn Snow block_job_completed(job, -ECANCELED); 5135ccac6f1SJohn Snow } 5148acc72a4SPaolo Bonzini } 5158acc72a4SPaolo Bonzini 516345f9e1bSMax Reitz /* A wrapper around block_job_cancel() taking an Error ** parameter so it may be 517345f9e1bSMax Reitz * used with block_job_finish_sync() without the need for (rather nasty) 518345f9e1bSMax Reitz * function pointer casts there. */ 519345f9e1bSMax Reitz static void block_job_cancel_err(BlockJob *job, Error **errp) 520345f9e1bSMax Reitz { 521345f9e1bSMax Reitz block_job_cancel(job); 522345f9e1bSMax Reitz } 523345f9e1bSMax Reitz 524345f9e1bSMax Reitz int block_job_cancel_sync(BlockJob *job) 525345f9e1bSMax Reitz { 526345f9e1bSMax Reitz return block_job_finish_sync(job, &block_job_cancel_err, NULL); 527345f9e1bSMax Reitz } 528345f9e1bSMax Reitz 529a1a2af07SKevin Wolf void block_job_cancel_sync_all(void) 530a1a2af07SKevin Wolf { 531a1a2af07SKevin Wolf BlockJob *job; 532a1a2af07SKevin Wolf AioContext *aio_context; 533a1a2af07SKevin Wolf 534a1a2af07SKevin Wolf while ((job = QLIST_FIRST(&block_jobs))) { 535b6d2e599SKevin Wolf aio_context = blk_get_aio_context(job->blk); 536a1a2af07SKevin Wolf aio_context_acquire(aio_context); 537a1a2af07SKevin Wolf block_job_cancel_sync(job); 538a1a2af07SKevin Wolf aio_context_release(aio_context); 539a1a2af07SKevin Wolf } 540a1a2af07SKevin Wolf } 541a1a2af07SKevin Wolf 542345f9e1bSMax Reitz int block_job_complete_sync(BlockJob *job, Error **errp) 543345f9e1bSMax Reitz { 544345f9e1bSMax Reitz return block_job_finish_sync(job, &block_job_complete, errp); 545345f9e1bSMax Reitz } 546345f9e1bSMax Reitz 547559b935fSJohn Snow BlockJobInfo *block_job_query(BlockJob *job, Error **errp) 54830e628b7SPaolo Bonzini { 549559b935fSJohn Snow BlockJobInfo *info; 550559b935fSJohn Snow 551559b935fSJohn Snow if (block_job_is_internal(job)) { 552559b935fSJohn Snow error_setg(errp, "Cannot query QEMU internal jobs"); 553559b935fSJohn Snow return NULL; 554559b935fSJohn Snow } 555559b935fSJohn Snow info = g_new0(BlockJobInfo, 1); 55679e14bf7SFam Zheng info->type = g_strdup(BlockJobType_lookup[job->driver->job_type]); 5578ccb9569SKevin Wolf info->device = g_strdup(job->id); 55830e628b7SPaolo Bonzini info->len = job->len; 5598d65883fSPaolo Bonzini info->busy = job->busy; 560751ebd76SFam Zheng info->paused = job->pause_count > 0; 56130e628b7SPaolo Bonzini info->offset = job->offset; 56230e628b7SPaolo Bonzini info->speed = job->speed; 56332c81a4aSPaolo Bonzini info->io_status = job->iostatus; 564ef6dbf1eSMax Reitz info->ready = job->ready; 56530e628b7SPaolo Bonzini return info; 56630e628b7SPaolo Bonzini } 56732c81a4aSPaolo Bonzini 56832c81a4aSPaolo Bonzini static void block_job_iostatus_set_err(BlockJob *job, int error) 56932c81a4aSPaolo Bonzini { 57032c81a4aSPaolo Bonzini if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { 57132c81a4aSPaolo Bonzini job->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE : 57232c81a4aSPaolo Bonzini BLOCK_DEVICE_IO_STATUS_FAILED; 57332c81a4aSPaolo Bonzini } 57432c81a4aSPaolo Bonzini } 57532c81a4aSPaolo Bonzini 5768254b6d9SJohn Snow static void block_job_event_cancelled(BlockJob *job) 577a66a2a36SPaolo Bonzini { 578559b935fSJohn Snow if (block_job_is_internal(job)) { 579559b935fSJohn Snow return; 580559b935fSJohn Snow } 581559b935fSJohn Snow 582bcada37bSWenchao Xia qapi_event_send_block_job_cancelled(job->driver->job_type, 5838ccb9569SKevin Wolf job->id, 584a66a2a36SPaolo Bonzini job->len, 585a66a2a36SPaolo Bonzini job->offset, 586bcada37bSWenchao Xia job->speed, 587bcada37bSWenchao Xia &error_abort); 588a66a2a36SPaolo Bonzini } 589a66a2a36SPaolo Bonzini 5908254b6d9SJohn Snow static void block_job_event_completed(BlockJob *job, const char *msg) 591a66a2a36SPaolo Bonzini { 592559b935fSJohn Snow if (block_job_is_internal(job)) { 593559b935fSJohn Snow return; 594559b935fSJohn Snow } 595559b935fSJohn Snow 596bcada37bSWenchao Xia qapi_event_send_block_job_completed(job->driver->job_type, 5978ccb9569SKevin Wolf job->id, 598bcada37bSWenchao Xia job->len, 599bcada37bSWenchao Xia job->offset, 600bcada37bSWenchao Xia job->speed, 601bcada37bSWenchao Xia !!msg, 602bcada37bSWenchao Xia msg, 603bcada37bSWenchao Xia &error_abort); 604bcada37bSWenchao Xia } 605bcada37bSWenchao Xia 60688691b37SPaolo Bonzini /* 60788691b37SPaolo Bonzini * API for block job drivers and the block layer. These functions are 60888691b37SPaolo Bonzini * declared in blockjob_int.h. 60988691b37SPaolo Bonzini */ 61088691b37SPaolo Bonzini 61188691b37SPaolo Bonzini void *block_job_create(const char *job_id, const BlockJobDriver *driver, 61288691b37SPaolo Bonzini BlockDriverState *bs, uint64_t perm, 61388691b37SPaolo Bonzini uint64_t shared_perm, int64_t speed, int flags, 61488691b37SPaolo Bonzini BlockCompletionFunc *cb, void *opaque, Error **errp) 61588691b37SPaolo Bonzini { 61688691b37SPaolo Bonzini BlockBackend *blk; 61788691b37SPaolo Bonzini BlockJob *job; 61888691b37SPaolo Bonzini int ret; 61988691b37SPaolo Bonzini 62088691b37SPaolo Bonzini if (bs->job) { 62188691b37SPaolo Bonzini error_setg(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs)); 62288691b37SPaolo Bonzini return NULL; 62388691b37SPaolo Bonzini } 62488691b37SPaolo Bonzini 62588691b37SPaolo Bonzini if (job_id == NULL && !(flags & BLOCK_JOB_INTERNAL)) { 62688691b37SPaolo Bonzini job_id = bdrv_get_device_name(bs); 62788691b37SPaolo Bonzini if (!*job_id) { 62888691b37SPaolo Bonzini error_setg(errp, "An explicit job ID is required for this node"); 62988691b37SPaolo Bonzini return NULL; 63088691b37SPaolo Bonzini } 63188691b37SPaolo Bonzini } 63288691b37SPaolo Bonzini 63388691b37SPaolo Bonzini if (job_id) { 63488691b37SPaolo Bonzini if (flags & BLOCK_JOB_INTERNAL) { 63588691b37SPaolo Bonzini error_setg(errp, "Cannot specify job ID for internal block job"); 63688691b37SPaolo Bonzini return NULL; 63788691b37SPaolo Bonzini } 63888691b37SPaolo Bonzini 63988691b37SPaolo Bonzini if (!id_wellformed(job_id)) { 64088691b37SPaolo Bonzini error_setg(errp, "Invalid job ID '%s'", job_id); 64188691b37SPaolo Bonzini return NULL; 64288691b37SPaolo Bonzini } 64388691b37SPaolo Bonzini 64488691b37SPaolo Bonzini if (block_job_get(job_id)) { 64588691b37SPaolo Bonzini error_setg(errp, "Job ID '%s' already in use", job_id); 64688691b37SPaolo Bonzini return NULL; 64788691b37SPaolo Bonzini } 64888691b37SPaolo Bonzini } 64988691b37SPaolo Bonzini 65088691b37SPaolo Bonzini blk = blk_new(perm, shared_perm); 65188691b37SPaolo Bonzini ret = blk_insert_bs(blk, bs, errp); 65288691b37SPaolo Bonzini if (ret < 0) { 65388691b37SPaolo Bonzini blk_unref(blk); 65488691b37SPaolo Bonzini return NULL; 65588691b37SPaolo Bonzini } 65688691b37SPaolo Bonzini 65788691b37SPaolo Bonzini job = g_malloc0(driver->instance_size); 65888691b37SPaolo Bonzini job->driver = driver; 65988691b37SPaolo Bonzini job->id = g_strdup(job_id); 66088691b37SPaolo Bonzini job->blk = blk; 66188691b37SPaolo Bonzini job->cb = cb; 66288691b37SPaolo Bonzini job->opaque = opaque; 66388691b37SPaolo Bonzini job->busy = false; 66488691b37SPaolo Bonzini job->paused = true; 66588691b37SPaolo Bonzini job->pause_count = 1; 66688691b37SPaolo Bonzini job->refcnt = 1; 66788691b37SPaolo Bonzini 66888691b37SPaolo Bonzini error_setg(&job->blocker, "block device is in use by block job: %s", 66988691b37SPaolo Bonzini BlockJobType_lookup[driver->job_type]); 67088691b37SPaolo Bonzini block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort); 67188691b37SPaolo Bonzini bs->job = job; 67288691b37SPaolo Bonzini 67388691b37SPaolo Bonzini blk_set_dev_ops(blk, &block_job_dev_ops, job); 67488691b37SPaolo Bonzini bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker); 67588691b37SPaolo Bonzini 67688691b37SPaolo Bonzini QLIST_INSERT_HEAD(&block_jobs, job, job_list); 67788691b37SPaolo Bonzini 67888691b37SPaolo Bonzini blk_add_aio_context_notifier(blk, block_job_attached_aio_context, 67988691b37SPaolo Bonzini block_job_detach_aio_context, job); 68088691b37SPaolo Bonzini 68188691b37SPaolo Bonzini /* Only set speed when necessary to avoid NotSupported error */ 68288691b37SPaolo Bonzini if (speed != 0) { 68388691b37SPaolo Bonzini Error *local_err = NULL; 68488691b37SPaolo Bonzini 68588691b37SPaolo Bonzini block_job_set_speed(job, speed, &local_err); 68688691b37SPaolo Bonzini if (local_err) { 68788691b37SPaolo Bonzini block_job_unref(job); 68888691b37SPaolo Bonzini error_propagate(errp, local_err); 68988691b37SPaolo Bonzini return NULL; 69088691b37SPaolo Bonzini } 69188691b37SPaolo Bonzini } 69288691b37SPaolo Bonzini return job; 69388691b37SPaolo Bonzini } 69488691b37SPaolo Bonzini 695f321dcb5SPaolo Bonzini void block_job_pause_all(void) 696f321dcb5SPaolo Bonzini { 697f321dcb5SPaolo Bonzini BlockJob *job = NULL; 698f321dcb5SPaolo Bonzini while ((job = block_job_next(job))) { 699f321dcb5SPaolo Bonzini AioContext *aio_context = blk_get_aio_context(job->blk); 700f321dcb5SPaolo Bonzini 701f321dcb5SPaolo Bonzini aio_context_acquire(aio_context); 702f321dcb5SPaolo Bonzini block_job_pause(job); 703f321dcb5SPaolo Bonzini aio_context_release(aio_context); 704f321dcb5SPaolo Bonzini } 705f321dcb5SPaolo Bonzini } 706f321dcb5SPaolo Bonzini 70788691b37SPaolo Bonzini void block_job_early_fail(BlockJob *job) 70888691b37SPaolo Bonzini { 70988691b37SPaolo Bonzini block_job_unref(job); 71088691b37SPaolo Bonzini } 71188691b37SPaolo Bonzini 71288691b37SPaolo Bonzini void block_job_completed(BlockJob *job, int ret) 71388691b37SPaolo Bonzini { 71488691b37SPaolo Bonzini assert(blk_bs(job->blk)->job == job); 71588691b37SPaolo Bonzini assert(!job->completed); 71688691b37SPaolo Bonzini job->completed = true; 71788691b37SPaolo Bonzini job->ret = ret; 71888691b37SPaolo Bonzini if (!job->txn) { 71988691b37SPaolo Bonzini block_job_completed_single(job); 72088691b37SPaolo Bonzini } else if (ret < 0 || block_job_is_cancelled(job)) { 72188691b37SPaolo Bonzini block_job_completed_txn_abort(job); 72288691b37SPaolo Bonzini } else { 72388691b37SPaolo Bonzini block_job_completed_txn_success(job); 72488691b37SPaolo Bonzini } 72588691b37SPaolo Bonzini } 72688691b37SPaolo Bonzini 72788691b37SPaolo Bonzini static bool block_job_should_pause(BlockJob *job) 72888691b37SPaolo Bonzini { 72988691b37SPaolo Bonzini return job->pause_count > 0; 73088691b37SPaolo Bonzini } 73188691b37SPaolo Bonzini 73288691b37SPaolo Bonzini void coroutine_fn block_job_pause_point(BlockJob *job) 73388691b37SPaolo Bonzini { 73488691b37SPaolo Bonzini assert(job && block_job_started(job)); 73588691b37SPaolo Bonzini 73688691b37SPaolo Bonzini if (!block_job_should_pause(job)) { 73788691b37SPaolo Bonzini return; 73888691b37SPaolo Bonzini } 73988691b37SPaolo Bonzini if (block_job_is_cancelled(job)) { 74088691b37SPaolo Bonzini return; 74188691b37SPaolo Bonzini } 74288691b37SPaolo Bonzini 74388691b37SPaolo Bonzini if (job->driver->pause) { 74488691b37SPaolo Bonzini job->driver->pause(job); 74588691b37SPaolo Bonzini } 74688691b37SPaolo Bonzini 74788691b37SPaolo Bonzini if (block_job_should_pause(job) && !block_job_is_cancelled(job)) { 74888691b37SPaolo Bonzini job->paused = true; 74988691b37SPaolo Bonzini job->busy = false; 75088691b37SPaolo Bonzini qemu_coroutine_yield(); /* wait for block_job_resume() */ 75188691b37SPaolo Bonzini job->busy = true; 75288691b37SPaolo Bonzini job->paused = false; 75388691b37SPaolo Bonzini } 75488691b37SPaolo Bonzini 75588691b37SPaolo Bonzini if (job->driver->resume) { 75688691b37SPaolo Bonzini job->driver->resume(job); 75788691b37SPaolo Bonzini } 75888691b37SPaolo Bonzini } 75988691b37SPaolo Bonzini 760f321dcb5SPaolo Bonzini void block_job_resume_all(void) 761f321dcb5SPaolo Bonzini { 762f321dcb5SPaolo Bonzini BlockJob *job = NULL; 763f321dcb5SPaolo Bonzini while ((job = block_job_next(job))) { 764f321dcb5SPaolo Bonzini AioContext *aio_context = blk_get_aio_context(job->blk); 765f321dcb5SPaolo Bonzini 766f321dcb5SPaolo Bonzini aio_context_acquire(aio_context); 767f321dcb5SPaolo Bonzini block_job_resume(job); 768f321dcb5SPaolo Bonzini aio_context_release(aio_context); 769f321dcb5SPaolo Bonzini } 770f321dcb5SPaolo Bonzini } 771f321dcb5SPaolo Bonzini 77288691b37SPaolo Bonzini void block_job_enter(BlockJob *job) 77388691b37SPaolo Bonzini { 774*eb05e011SPaolo Bonzini if (!block_job_started(job)) { 775*eb05e011SPaolo Bonzini return; 776*eb05e011SPaolo Bonzini } 777*eb05e011SPaolo Bonzini if (job->deferred_to_main_loop) { 778*eb05e011SPaolo Bonzini return; 779*eb05e011SPaolo Bonzini } 780*eb05e011SPaolo Bonzini 781*eb05e011SPaolo Bonzini if (!job->busy) { 78288691b37SPaolo Bonzini bdrv_coroutine_enter(blk_bs(job->blk), job->co); 78388691b37SPaolo Bonzini } 78488691b37SPaolo Bonzini } 78588691b37SPaolo Bonzini 78688691b37SPaolo Bonzini bool block_job_is_cancelled(BlockJob *job) 78788691b37SPaolo Bonzini { 78888691b37SPaolo Bonzini return job->cancelled; 78988691b37SPaolo Bonzini } 79088691b37SPaolo Bonzini 79188691b37SPaolo Bonzini void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns) 79288691b37SPaolo Bonzini { 79388691b37SPaolo Bonzini assert(job->busy); 79488691b37SPaolo Bonzini 79588691b37SPaolo Bonzini /* Check cancellation *before* setting busy = false, too! */ 79688691b37SPaolo Bonzini if (block_job_is_cancelled(job)) { 79788691b37SPaolo Bonzini return; 79888691b37SPaolo Bonzini } 79988691b37SPaolo Bonzini 80088691b37SPaolo Bonzini job->busy = false; 80188691b37SPaolo Bonzini if (!block_job_should_pause(job)) { 80288691b37SPaolo Bonzini co_aio_sleep_ns(blk_get_aio_context(job->blk), type, ns); 80388691b37SPaolo Bonzini } 80488691b37SPaolo Bonzini job->busy = true; 80588691b37SPaolo Bonzini 80688691b37SPaolo Bonzini block_job_pause_point(job); 80788691b37SPaolo Bonzini } 80888691b37SPaolo Bonzini 80988691b37SPaolo Bonzini void block_job_yield(BlockJob *job) 81088691b37SPaolo Bonzini { 81188691b37SPaolo Bonzini assert(job->busy); 81288691b37SPaolo Bonzini 81388691b37SPaolo Bonzini /* Check cancellation *before* setting busy = false, too! */ 81488691b37SPaolo Bonzini if (block_job_is_cancelled(job)) { 81588691b37SPaolo Bonzini return; 81688691b37SPaolo Bonzini } 81788691b37SPaolo Bonzini 81888691b37SPaolo Bonzini job->busy = false; 81988691b37SPaolo Bonzini if (!block_job_should_pause(job)) { 82088691b37SPaolo Bonzini qemu_coroutine_yield(); 82188691b37SPaolo Bonzini } 82288691b37SPaolo Bonzini job->busy = true; 82388691b37SPaolo Bonzini 82488691b37SPaolo Bonzini block_job_pause_point(job); 82588691b37SPaolo Bonzini } 82688691b37SPaolo Bonzini 8272caf63a9SPaolo Bonzini void block_job_iostatus_reset(BlockJob *job) 8282caf63a9SPaolo Bonzini { 8294c241cf5SPaolo Bonzini if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { 8304c241cf5SPaolo Bonzini return; 8314c241cf5SPaolo Bonzini } 8324c241cf5SPaolo Bonzini assert(job->user_paused && job->pause_count > 0); 8332caf63a9SPaolo Bonzini job->iostatus = BLOCK_DEVICE_IO_STATUS_OK; 8342caf63a9SPaolo Bonzini } 8352caf63a9SPaolo Bonzini 836bcada37bSWenchao Xia void block_job_event_ready(BlockJob *job) 837bcada37bSWenchao Xia { 838ef6dbf1eSMax Reitz job->ready = true; 839ef6dbf1eSMax Reitz 840559b935fSJohn Snow if (block_job_is_internal(job)) { 841559b935fSJohn Snow return; 842559b935fSJohn Snow } 843559b935fSJohn Snow 844518848a2SMarkus Armbruster qapi_event_send_block_job_ready(job->driver->job_type, 8458ccb9569SKevin Wolf job->id, 846518848a2SMarkus Armbruster job->len, 847518848a2SMarkus Armbruster job->offset, 848518848a2SMarkus Armbruster job->speed, &error_abort); 849a66a2a36SPaolo Bonzini } 850a66a2a36SPaolo Bonzini 85181e254dcSKevin Wolf BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, 85232c81a4aSPaolo Bonzini int is_read, int error) 85332c81a4aSPaolo Bonzini { 85432c81a4aSPaolo Bonzini BlockErrorAction action; 85532c81a4aSPaolo Bonzini 85632c81a4aSPaolo Bonzini switch (on_err) { 85732c81a4aSPaolo Bonzini case BLOCKDEV_ON_ERROR_ENOSPC: 8588c398252SKevin Wolf case BLOCKDEV_ON_ERROR_AUTO: 859a589569fSWenchao Xia action = (error == ENOSPC) ? 860a589569fSWenchao Xia BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT; 86132c81a4aSPaolo Bonzini break; 86232c81a4aSPaolo Bonzini case BLOCKDEV_ON_ERROR_STOP: 863a589569fSWenchao Xia action = BLOCK_ERROR_ACTION_STOP; 86432c81a4aSPaolo Bonzini break; 86532c81a4aSPaolo Bonzini case BLOCKDEV_ON_ERROR_REPORT: 866a589569fSWenchao Xia action = BLOCK_ERROR_ACTION_REPORT; 86732c81a4aSPaolo Bonzini break; 86832c81a4aSPaolo Bonzini case BLOCKDEV_ON_ERROR_IGNORE: 869a589569fSWenchao Xia action = BLOCK_ERROR_ACTION_IGNORE; 87032c81a4aSPaolo Bonzini break; 87132c81a4aSPaolo Bonzini default: 87232c81a4aSPaolo Bonzini abort(); 87332c81a4aSPaolo Bonzini } 874559b935fSJohn Snow if (!block_job_is_internal(job)) { 8758ccb9569SKevin Wolf qapi_event_send_block_job_error(job->id, 8765a2d2cbdSWenchao Xia is_read ? IO_OPERATION_TYPE_READ : 8775a2d2cbdSWenchao Xia IO_OPERATION_TYPE_WRITE, 8785a2d2cbdSWenchao Xia action, &error_abort); 879559b935fSJohn Snow } 880a589569fSWenchao Xia if (action == BLOCK_ERROR_ACTION_STOP) { 881751ebd76SFam Zheng /* make the pause user visible, which will be resumed from QMP. */ 8820df4ba58SJohn Snow block_job_user_pause(job); 88332c81a4aSPaolo Bonzini block_job_iostatus_set_err(job, error); 88432c81a4aSPaolo Bonzini } 88532c81a4aSPaolo Bonzini return action; 88632c81a4aSPaolo Bonzini } 887dec7d421SStefan Hajnoczi 888dec7d421SStefan Hajnoczi typedef struct { 889dec7d421SStefan Hajnoczi BlockJob *job; 890dec7d421SStefan Hajnoczi AioContext *aio_context; 891dec7d421SStefan Hajnoczi BlockJobDeferToMainLoopFn *fn; 892dec7d421SStefan Hajnoczi void *opaque; 893dec7d421SStefan Hajnoczi } BlockJobDeferToMainLoopData; 894dec7d421SStefan Hajnoczi 895dec7d421SStefan Hajnoczi static void block_job_defer_to_main_loop_bh(void *opaque) 896dec7d421SStefan Hajnoczi { 897dec7d421SStefan Hajnoczi BlockJobDeferToMainLoopData *data = opaque; 898dec7d421SStefan Hajnoczi AioContext *aio_context; 899dec7d421SStefan Hajnoczi 900dec7d421SStefan Hajnoczi /* Prevent race with block_job_defer_to_main_loop() */ 901dec7d421SStefan Hajnoczi aio_context_acquire(data->aio_context); 902dec7d421SStefan Hajnoczi 903dec7d421SStefan Hajnoczi /* Fetch BDS AioContext again, in case it has changed */ 904b6d2e599SKevin Wolf aio_context = blk_get_aio_context(data->job->blk); 905d79df2a2SPaolo Bonzini if (aio_context != data->aio_context) { 906dec7d421SStefan Hajnoczi aio_context_acquire(aio_context); 907d79df2a2SPaolo Bonzini } 908dec7d421SStefan Hajnoczi 909dec7d421SStefan Hajnoczi data->fn(data->job, data->opaque); 910dec7d421SStefan Hajnoczi 911d79df2a2SPaolo Bonzini if (aio_context != data->aio_context) { 912dec7d421SStefan Hajnoczi aio_context_release(aio_context); 913d79df2a2SPaolo Bonzini } 914dec7d421SStefan Hajnoczi 915dec7d421SStefan Hajnoczi aio_context_release(data->aio_context); 916dec7d421SStefan Hajnoczi 917dec7d421SStefan Hajnoczi g_free(data); 918dec7d421SStefan Hajnoczi } 919dec7d421SStefan Hajnoczi 920dec7d421SStefan Hajnoczi void block_job_defer_to_main_loop(BlockJob *job, 921dec7d421SStefan Hajnoczi BlockJobDeferToMainLoopFn *fn, 922dec7d421SStefan Hajnoczi void *opaque) 923dec7d421SStefan Hajnoczi { 924dec7d421SStefan Hajnoczi BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data)); 925dec7d421SStefan Hajnoczi data->job = job; 926b6d2e599SKevin Wolf data->aio_context = blk_get_aio_context(job->blk); 927dec7d421SStefan Hajnoczi data->fn = fn; 928dec7d421SStefan Hajnoczi data->opaque = opaque; 929794f0141SFam Zheng job->deferred_to_main_loop = true; 930dec7d421SStefan Hajnoczi 931fffb6e12SPaolo Bonzini aio_bh_schedule_oneshot(qemu_get_aio_context(), 932fffb6e12SPaolo Bonzini block_job_defer_to_main_loop_bh, data); 933dec7d421SStefan Hajnoczi } 934