X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=blockjob.c;h=513620c199fde95f7448d01e3e3c33fb3724ba21;hb=77424a452abe5f941d8cd81f1e85f42bca31c9ef;hp=4aa14a4974b602d0063d97c5107b54470391ed59;hpb=c46ef897dbb75590af94b6e3dca6a9c5f9a1ea1e;p=mirror_qemu.git diff --git a/blockjob.c b/blockjob.c index 4aa14a4974..513620c199 100644 --- a/blockjob.c +++ b/blockjob.c @@ -174,7 +174,9 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, job->blk = blk; job->cb = cb; job->opaque = opaque; - job->busy = true; + job->busy = false; + job->paused = true; + job->pause_count = 1; job->refcnt = 1; bs->job = job; @@ -202,6 +204,23 @@ bool block_job_is_internal(BlockJob *job) return (job->id == NULL); } +static bool block_job_started(BlockJob *job) +{ + return job->co; +} + +void block_job_start(BlockJob *job) +{ + assert(job && !block_job_started(job) && job->paused && + !job->busy && job->driver->start); + job->co = qemu_coroutine_create(job->driver->start, job); + if (--job->pause_count == 0) { + job->paused = false; + job->busy = true; + qemu_coroutine_enter(job->co); + } +} + void block_job_ref(BlockJob *job) { ++job->refcnt; @@ -241,21 +260,29 @@ static void block_job_completed_single(BlockJob *job) job->driver->abort(job); } } + if (job->driver->clean) { + job->driver->clean(job); + } if (job->cb) { job->cb(job->opaque, job->ret); } - if (block_job_is_cancelled(job)) { - block_job_event_cancelled(job); - } else { - const char *msg = NULL; - if (job->ret < 0) { - msg = strerror(-job->ret); + + /* Emit events only if we actually started */ + if (block_job_started(job)) { + if (block_job_is_cancelled(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_event_completed(job, msg); } if (job->txn) { + QLIST_REMOVE(job, txn_list); block_job_txn_unref(job->txn); } block_job_unref(job); @@ -359,7 +386,8 @@ void block_job_complete(BlockJob *job, Error **errp) { /* Should not be reachable via external interface for internal jobs */ assert(job->id); - if (job->pause_count || job->cancelled || !job->driver->complete) { + if (job->pause_count || job->cancelled || + !block_job_started(job) || !job->driver->complete) { error_setg(errp, "The active block job '%s' cannot be completed", job->id); return; @@ -391,6 +419,8 @@ bool block_job_user_paused(BlockJob *job) void coroutine_fn block_job_pause_point(BlockJob *job) { + assert(job && block_job_started(job)); + if (!block_job_should_pause(job)) { return; } @@ -442,9 +472,13 @@ void block_job_enter(BlockJob *job) void block_job_cancel(BlockJob *job) { - job->cancelled = true; - block_job_iostatus_reset(job); - block_job_enter(job); + if (block_job_started(job)) { + job->cancelled = true; + block_job_iostatus_reset(job); + block_job_enter(job); + } else { + block_job_completed(job, -ECANCELED); + } } bool block_job_is_cancelled(BlockJob *job)