-bool block_job_is_internal(BlockJob *job)
-{
- return (job->job.id == NULL);
-}
-
-const BlockJobDriver *block_job_driver(BlockJob *job)
-{
- return job->driver;
-}
-
-static void block_job_decommission(BlockJob *job)
-{
- assert(job);
- job->job.busy = false;
- job->job.paused = false;
- job->job.deferred_to_main_loop = true;
- block_job_txn_del_job(job);
- job_state_transition(&job->job, JOB_STATUS_NULL);
- job_unref(&job->job);
-}
-
-static void block_job_do_dismiss(BlockJob *job)
-{
- block_job_decommission(job);
-}
-
-static void block_job_conclude(BlockJob *job)
-{
- job_state_transition(&job->job, JOB_STATUS_CONCLUDED);
- if (job->job.auto_dismiss || !job_started(&job->job)) {
- block_job_do_dismiss(job);
- }
-}
-
-static void block_job_update_rc(BlockJob *job)
-{
- if (!job->ret && job_is_cancelled(&job->job)) {
- job->ret = -ECANCELED;
- }
- if (job->ret) {
- job_state_transition(&job->job, JOB_STATUS_ABORTING);
- }
-}
-
-static int block_job_prepare(BlockJob *job)
-{
- if (job->ret == 0 && job->driver->prepare) {
- job->ret = job->driver->prepare(job);
- }
- return job->ret;
-}
-
-static void block_job_commit(BlockJob *job)
-{
- assert(!job->ret);
- if (job->driver->commit) {
- job->driver->commit(job);
- }
-}
-
-static void block_job_abort(BlockJob *job)
-{
- assert(job->ret);
- if (job->driver->abort) {
- job->driver->abort(job);
- }
-}
-
-static void block_job_clean(BlockJob *job)
-{
- if (job->driver->clean) {
- job->driver->clean(job);
- }
-}
-
-static int block_job_finalize_single(BlockJob *job)
-{
- assert(job_is_completed(&job->job));
-
- /* Ensure abort is called for late-transactional failures */
- block_job_update_rc(job);
-
- if (!job->ret) {
- block_job_commit(job);
- } else {
- block_job_abort(job);
- }
- block_job_clean(job);
-
- if (job->cb) {
- job->cb(job->opaque, job->ret);
- }
-
- /* Emit events only if we actually started */
- if (job_started(&job->job)) {
- if (job_is_cancelled(&job->job)) {
- block_job_event_cancelled(job);
- } else {
- const char *msg = NULL;
- if (job->ret < 0) {
- msg = strerror(-job->ret);
- }
- block_job_event_completed(job, msg);
- }
- }
-
- block_job_txn_del_job(job);
- block_job_conclude(job);
- return 0;
-}
-
-static void block_job_cancel_async(BlockJob *job, bool force)
-{
- if (job->iostatus != BLOCK_DEVICE_IO_STATUS_OK) {
- block_job_iostatus_reset(job);
- }
- if (job->job.user_paused) {
- /* Do not call block_job_enter here, the caller will handle it. */
- job->job.user_paused = false;
- job->job.pause_count--;
- }
- job->job.cancelled = true;
- /* To prevent 'force == false' overriding a previous 'force == true' */
- job->force |= force;
-}
-
-static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *), bool lock)
-{
- AioContext *ctx;
- BlockJob *job, *next;
- int rc = 0;
-
- QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) {
- if (lock) {
- ctx = blk_get_aio_context(job->blk);
- aio_context_acquire(ctx);
- }
- rc = fn(job);
- if (lock) {
- aio_context_release(ctx);
- }
- if (rc) {
- break;
- }
- }
- return rc;
-}
-
-static int block_job_finish_sync(BlockJob *job,
- void (*finish)(BlockJob *, Error **errp),
- Error **errp)
-{
- Error *local_err = NULL;
- int ret;
-
- assert(blk_bs(job->blk)->job == job);
-
- job_ref(&job->job);
-
- if (finish) {
- finish(job, &local_err);
- }
- if (local_err) {
- error_propagate(errp, local_err);
- job_unref(&job->job);
- return -EBUSY;
- }
- /* block_job_drain calls block_job_enter, and it should be enough to
- * induce progress until the job completes or moves to the main thread.
- */
- while (!job->job.deferred_to_main_loop && !job_is_completed(&job->job)) {
- block_job_drain(job);
- }
- while (!job_is_completed(&job->job)) {
- aio_poll(qemu_get_aio_context(), true);
- }
- ret = (job_is_cancelled(&job->job) && job->ret == 0)
- ? -ECANCELED : job->ret;
- job_unref(&job->job);
- return ret;
-}
-
-static void block_job_completed_txn_abort(BlockJob *job)