From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:57601) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SfY6b-00027d-Hr for qemu-devel@nongnu.org; Fri, 15 Jun 2012 11:06:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SfY6U-0004ih-VM for qemu-devel@nongnu.org; Fri, 15 Jun 2012 11:06:33 -0400 Received: from mail-pb0-f45.google.com ([209.85.160.45]:47190) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SfY6U-0004gs-M7 for qemu-devel@nongnu.org; Fri, 15 Jun 2012 11:06:26 -0400 Received: by mail-pb0-f45.google.com with SMTP id ro12so5648793pbb.4 for ; Fri, 15 Jun 2012 08:06:25 -0700 (PDT) Sender: Paolo Bonzini From: Paolo Bonzini Date: Fri, 15 Jun 2012 17:05:28 +0200 Message-Id: <1339772759-31004-6-git-send-email-pbonzini@redhat.com> In-Reply-To: <1339772759-31004-1-git-send-email-pbonzini@redhat.com> References: <1339772759-31004-1-git-send-email-pbonzini@redhat.com> Subject: [Qemu-devel] [RFC PATCH 05/36] block: add support for job pause/resume List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: kwolf@redhat.com, stefanha@linux.vnet.ibm.com, lcapitulino@redhat.com 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 --- 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 3dba4b8..8bf659a 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1159,6 +1159,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 32854b8..d35c65b 100644 --- a/blockjob.h +++ b/blockjob.h @@ -72,6 +72,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. @@ -173,6 +179,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 35c16f3..178549d 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -906,6 +906,8 @@ # # @len: the maximum progress value # +# @paused: whether the job is paused +# # @offset: the current progress value # # @speed: the rate limit, bytes per second @@ -914,7 +916,7 @@ ## { 'type': 'BlockJobInfo', 'data': {'type': 'str', 'device': 'str', 'len': 'int', - 'offset': 'int', 'speed': 'int'} } + 'offset': 'int', 'paused': 'bool', 'speed': 'int'} } ## # @query-block-jobs: @@ -1680,6 +1682,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.2