[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 05/47] block: add support for job pause/resume
From: |
Paolo Bonzini |
Subject: |
[Qemu-devel] [PATCH 05/47] block: add support for job pause/resume |
Date: |
Tue, 24 Jul 2012 13:03:43 +0200 |
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.
Signed-off-by: Paolo Bonzini <address@hidden>
---
blockdev.c | 4 ++++
blockjob.c | 35 ++++++++++++++++++++++++++++++-----
blockjob.h | 30 ++++++++++++++++++++++++++++++
qapi-schema.json | 5 ++++-
qerror.c | 4 ++++
qerror.h | 3 +++
6 files changed, 75 insertions(+), 6 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index dc099f9..33ac7e0 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1155,6 +1155,10 @@ void qmp_block_job_cancel(const char *device, Error
**errp)
error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);
return;
}
+ if (job->paused) {
+ error_set(errp, QERR_BLOCK_JOB_PAUSED, device);
+ return;
+ }
trace_qmp_block_job_cancel(job);
block_job_cancel(job);
diff --git a/blockjob.c b/blockjob.c
index a947a6e..5d62191 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)
@@ -168,6 +192,7 @@ BlockJobInfo *block_job_query(BlockJob *job)
info->type = g_strdup(job->job_type->job_type);
info->device = g_strdup(bdrv_get_device_name(job->bs));
info->len = job->len;
+ info->paused = job->paused;
info->offset = job->offset;
info->speed = job->speed;
return info;
diff --git a/blockjob.h b/blockjob.h
index 347a62f..ccbef07 100644
--- a/blockjob.h
+++ b/blockjob.h
@@ -70,6 +70,12 @@ struct BlockJob {
bool cancelled;
/**
+ * Set to true if the job is either paused, or will pause itself
+ * as soon as possible (if busy == true).
+ */
+ bool paused;
+
+ /**
* Set to false by the job while it is in a quiescent state, where
* no I/O is pending and the job has yielded on any condition
* that is not detected by #qemu_aio_wait, such as a timer.
@@ -171,6 +177,30 @@ bool block_job_is_cancelled(BlockJob *job);
BlockJobInfo *block_job_query(BlockJob *job);
/**
+ * block_job_pause:
+ * @job: The job to be paused.
+ *
+ * Asynchronously pause the specified job.
+ */
+void block_job_pause(BlockJob *job);
+
+/**
+ * block_job_resume:
+ * @job: The job to be resumed.
+ *
+ * Resume the specified job.
+ */
+void block_job_resume(BlockJob *job);
+
+/**
+ * block_job_is_paused:
+ * @job: The job being queried.
+ *
+ * Returns whether the job is currently paused.
+ */
+bool block_job_is_paused(BlockJob *job);
+
+/**
* block_job_cancel_sync:
* @job: The job to be canceled.
*
diff --git a/qapi-schema.json b/qapi-schema.json
index 040981e..f52ce3c 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -912,6 +912,8 @@
#
# @len: the maximum progress value
#
+# @paused: whether the job is paused (since 1.2)
+#
# @offset: the current progress value
#
# @speed: the rate limit, bytes per second
@@ -920,7 +922,7 @@
##
{ 'type': 'BlockJobInfo',
'data': {'type': 'str', 'device': 'str', 'len': 'int',
- 'offset': 'int', 'speed': 'int'} }
+ 'offset': 'int', 'paused': 'bool', 'speed': 'int'} }
##
# @query-block-jobs:
@@ -1686,6 +1688,7 @@
#
# Returns: Nothing on success
# If no background operation is active on this device,
BlockJobNotActive
+# If the job is currently paused, BlockJobPaused
#
# Since: 1.1
##
diff --git a/qerror.c b/qerror.c
index bc672a5..72183ec 100644
--- a/qerror.c
+++ b/qerror.c
@@ -64,6 +64,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "No active block job on device '%(name)'",
},
{
+ .error_fmt = QERR_BLOCK_JOB_PAUSED,
+ .desc = "The block job for device '%(name)' is currently paused",
+ },
+ {
.error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
.desc = "Block format '%(format)' used by device '%(name)' does
not support feature '%(feature)'",
},
diff --git a/qerror.h b/qerror.h
index 7cf7d22..d1baea0 100644
--- a/qerror.h
+++ b/qerror.h
@@ -67,6 +67,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_BLOCK_JOB_NOT_ACTIVE \
"{ 'class': 'BlockJobNotActive', 'data': { 'name': %s } }"
+#define QERR_BLOCK_JOB_PAUSED \
+ "{ 'class': 'BlockJobPaused', 'data': { 'name': %s } }"
+
#define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
"{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s,
'name': %s, 'feature': %s } }"
--
1.7.10.4
[Qemu-devel] [PATCH 05/47] block: add support for job pause/resume,
Paolo Bonzini <=
[Qemu-devel] [PATCH 04/47] block: add block_job_query, Paolo Bonzini, 2012/07/24
[Qemu-devel] [PATCH 06/47] qmp: add block-job-pause and block-job-resume, Paolo Bonzini, 2012/07/24
[Qemu-devel] [PATCH 03/47] block: move job APIs to separate files, Paolo Bonzini, 2012/07/24
[Qemu-devel] [PATCH 07/47] qemu-iotests: add test for pausing a streaming operation, Paolo Bonzini, 2012/07/24
[Qemu-devel] [PATCH 08/47] block: rename block_job_complete to block_job_completed, Paolo Bonzini, 2012/07/24