aboutsummaryrefslogtreecommitdiff
path: root/blockjob.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2012-09-28 17:22:50 +0200
committerKevin Wolf <kwolf@redhat.com>2012-09-28 19:14:32 +0200
commit8acc72a4d20910d522516dab31272fe66da8da28 (patch)
tree4d521649f4d3a32eb74cf021ea12cfc1fc763e8f /blockjob.c
parent8d65883fff22e00d70f5880a26b7a1248c59a2d8 (diff)
block: add support for job pause/resume
Job pausing reuses the existing support for cancellable sleeps. A pause happens at the next sleeping point and lasts until the coroutine is re-entered explicitly. Cancellation was already doing a forced resume, so implement it explicitly in terms of resume. Paused jobs cannot be canceled without first resuming them. This ensures that I/O errors are never missed by management. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'blockjob.c')
-rw-r--r--blockjob.c35
1 files changed, 30 insertions, 5 deletions
diff --git a/blockjob.c b/blockjob.c
index 64c9d2dda1..8219f73979 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -99,14 +99,30 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
job->speed = speed;
}
-void block_job_cancel(BlockJob *job)
+void block_job_pause(BlockJob *job)
{
- job->cancelled = true;
+ job->paused = true;
+}
+
+bool block_job_is_paused(BlockJob *job)
+{
+ return job->paused;
+}
+
+void block_job_resume(BlockJob *job)
+{
+ job->paused = false;
if (job->co && !job->busy) {
qemu_coroutine_enter(job->co, NULL);
}
}
+void block_job_cancel(BlockJob *job)
+{
+ job->cancelled = true;
+ block_job_resume(job);
+}
+
bool block_job_is_cancelled(BlockJob *job)
{
return job->cancelled;
@@ -154,12 +170,20 @@ int block_job_cancel_sync(BlockJob *job)
void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns)
{
+ assert(job->busy);
+
/* Check cancellation *before* setting busy = false, too! */
- if (!block_job_is_cancelled(job)) {
- job->busy = false;
+ if (block_job_is_cancelled(job)) {
+ return;
+ }
+
+ job->busy = false;
+ if (block_job_is_paused(job)) {
+ qemu_coroutine_yield();
+ } else {
co_sleep_ns(clock, ns);
- job->busy = true;
}
+ job->busy = true;
}
BlockJobInfo *block_job_query(BlockJob *job)
@@ -169,6 +193,7 @@ BlockJobInfo *block_job_query(BlockJob *job)
info->device = g_strdup(bdrv_get_device_name(job->bs));
info->len = job->len;
info->busy = job->busy;
+ info->paused = job->paused;
info->offset = job->offset;
info->speed = job->speed;
return info;