Patchwork [RFC,28/36] block: add block-job-complete

login
register
mail settings
Submitter Paolo Bonzini
Date June 15, 2012, 3:05 p.m.
Message ID <1339772759-31004-29-git-send-email-pbonzini@redhat.com>
Download mbox | patch
Permalink /patch/165187/
State New
Headers show

Comments

Paolo Bonzini - June 15, 2012, 3:05 p.m.
While streaming can be dropped as soon as it progressed through the whole
image, mirroring needs to be completed manually for two reasons: 1) so that
management knows exactly when the VM switches to the target; 2) because
for other use cases such as replication, we may leave the operation running
for the whole life of the virtual machine.

Add a new block job command that manually completes background operations.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 blockdev.c       |   13 +++++++++++++
 blockjob.c       |   10 ++++++++++
 blockjob.h       |   15 +++++++++++++++
 hmp-commands.hx  |   17 ++++++++++++++++-
 hmp.c            |   10 ++++++++++
 hmp.h            |    1 +
 qapi-schema.json |   27 +++++++++++++++++++++++++++
 qerror.c         |    4 ++++
 qerror.h         |    3 +++
 qmp-commands.hx  |    5 +++++
 trace-events     |    1 +
 11 files changed, 105 insertions(+), 1 deletion(-)
Eric Blake - June 15, 2012, 9:42 p.m.
On 06/15/2012 09:05 AM, Paolo Bonzini wrote:
> While streaming can be dropped as soon as it progressed through the whole
> image, mirroring needs to be completed manually for two reasons: 1) so that
> management knows exactly when the VM switches to the target; 2) because
> for other use cases such as replication, we may leave the operation running
> for the whole life of the virtual machine.
> 
> Add a new block job command that manually completes background operations.
> 


>  ##
> +# @block-job-complete:
> +#
> +# Manually trigger completion of an active background block operation.  This
> +# is supported for drive mirroring, where it also switches the device to
> +# write to the target path only.
> +#
> +# This command completes an active background block operation synchronously.
> +# The ordering of this command's return with the BLOCK_JOB_COMPLETED event
> +# is not defined.  Note that if an I/O error occurs during the processing of
> +# this command: 1) the command itself will fail; 2) the error will be processed
> +# according to the rerror/werror arguments that were specified when starting
> +# the operation.
> +#
> +# A cancelled or paused job cannot be completed.

US vs. UK spelling.

So 'block-job-complete' ends by pivoting or errors because it is not
ready, 'block-job-cancel' without force ends with a clean mirror without
pivoting or errors because it is not ready, and 'block-job-cancel' with
force ends no matter what, even if it means a non-clean mirror.  I think
that was all the cases I asked for regarding a single disk.  And
hopefully we still have time to add additional patches to also support
'transaction' of combinations of these block actions across multiple disks.

> +#
> +# @device: the device name
> +#
> +# Returns: Nothing on success
> +#          If no background operation is active on this device, BlockJobNotActive
> +#          If the operation cannot be completed manually (either in general, or
> +#            not at the time the command is invoked), BlockJobNotReady
> +#
> +# Since: 1.1

1.2

Patch

diff --git a/blockdev.c b/blockdev.c
index 4000d16..b46a86c 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1328,6 +1328,19 @@  void qmp_block_job_resume(const char *device, Error **errp)
     block_job_resume(job);
 }
 
+void qmp_block_job_complete(const char *device, Error **errp)
+{
+    BlockJob *job = find_block_job(device);
+
+    if (!job) {
+        error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);
+        return;
+    }
+
+    trace_qmp_block_job_complete(job);
+    block_job_complete(job, errp);
+}
+
 static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
 {
     BlockJobInfoList **prev = opaque;
diff --git a/blockjob.c b/blockjob.c
index d3819df..602e669 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -99,6 +99,16 @@  void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
     job->speed = speed;
 }
 
+void block_job_complete(BlockJob *job, Error **errp)
+{
+    if (job->paused || job->cancelled || !job->job_type->complete) {
+       error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
+       return;
+    }
+
+    job->job_type->complete(job, errp);
+}
+
 void block_job_pause(BlockJob *job)
 {
     job->paused = true;
diff --git a/blockjob.h b/blockjob.h
index 02e0363..563b0a2 100644
--- a/blockjob.h
+++ b/blockjob.h
@@ -52,6 +52,12 @@  typedef struct BlockJobType {
      * of BlockJobInfo.
      */
     void (*query)(BlockJob *job, BlockJobInfo *info);
+
+    /**
+     * Optional callback for job types whose completion must be triggered
+     * manually.
+     */
+    void (*complete)(BlockJob *job, Error **errp);
 } BlockJobType;
 
 /**
@@ -175,6 +181,15 @@  void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp);
 void block_job_cancel(BlockJob *job);
 
 /**
+ * block_job_complete:
+ * @job: The job to be completed.
+ * @errp: Error object.
+ *
+ * Synchronously complete the specified job.
+ */
+void block_job_complete(BlockJob *job, Error **errp);
+
+/**
  * block_job_is_cancelled:
  * @job: The job being queried.
  *
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 7ee8de8..47827bf 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -109,7 +109,22 @@  ETEXI
 STEXI
 @item block_job_cancel
 @findex block_job_cancel
-Stop an active block streaming operation.
+Stop an active background block operation (streaming, mirroring).
+ETEXI
+
+    {
+        .name       = "block_job_complete",
+        .args_type  = "device:B",
+        .params     = "device",
+        .help       = "stop an active background block operation",
+        .mhandler.cmd = hmp_block_job_complete,
+    },
+
+STEXI
+@item block_job_complete
+@findex block_job_complete
+Manually trigger completion of an active background block operation.
+For mirroring, this will switch the device to the destination path.
 ETEXI
 
     {
diff --git a/hmp.c b/hmp.c
index ce0d040..ef0b87f 100644
--- a/hmp.c
+++ b/hmp.c
@@ -920,6 +920,16 @@  void hmp_block_job_resume(Monitor *mon, const QDict *qdict)
     hmp_handle_error(mon, &error);
 }
 
+void hmp_block_job_complete(Monitor *mon, const QDict *qdict)
+{
+    Error *error = NULL;
+    const char *device = qdict_get_str(qdict, "device");
+
+    qmp_block_job_complete(device, &error);
+
+    hmp_handle_error(mon, &error);
+}
+
 typedef struct MigrationStatus
 {
     QEMUTimer *timer;
diff --git a/hmp.h b/hmp.h
index 4e86083..61fadc1 100644
--- a/hmp.h
+++ b/hmp.h
@@ -62,6 +62,7 @@  void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
 void hmp_block_job_pause(Monitor *mon, const QDict *qdict);
 void hmp_block_job_resume(Monitor *mon, const QDict *qdict);
+void hmp_block_job_complete(Monitor *mon, const QDict *qdict);
 void hmp_migrate(Monitor *mon, const QDict *qdict);
 void hmp_device_del(Monitor *mon, const QDict *qdict);
 void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict);
diff --git a/qapi-schema.json b/qapi-schema.json
index 250edf2..bbcfa0e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1840,6 +1840,33 @@ 
 { 'command': 'block-job-resume', 'data': { 'device': 'str' } }
 
 ##
+# @block-job-complete:
+#
+# Manually trigger completion of an active background block operation.  This
+# is supported for drive mirroring, where it also switches the device to
+# write to the target path only.
+#
+# This command completes an active background block operation synchronously.
+# The ordering of this command's return with the BLOCK_JOB_COMPLETED event
+# is not defined.  Note that if an I/O error occurs during the processing of
+# this command: 1) the command itself will fail; 2) the error will be processed
+# according to the rerror/werror arguments that were specified when starting
+# the operation.
+#
+# A cancelled or paused job cannot be completed.
+#
+# @device: the device name
+#
+# Returns: Nothing on success
+#          If no background operation is active on this device, BlockJobNotActive
+#          If the operation cannot be completed manually (either in general, or
+#            not at the time the command is invoked), BlockJobNotReady
+#
+# Since: 1.1
+##
+{ 'command': 'block-job-complete', 'data': { 'device': 'str' } }
+
+##
 # @ObjectTypeInfo:
 #
 # This structure describes a search result from @qom-list-types
diff --git a/qerror.c b/qerror.c
index 72183ec..60303a4 100644
--- a/qerror.c
+++ b/qerror.c
@@ -68,6 +68,10 @@  static const QErrorStringTable qerror_table[] = {
         .desc      = "The block job for device '%(name)' is currently paused",
     },
     {
+        .error_fmt = QERR_BLOCK_JOB_NOT_READY,
+        .desc      = "The active block job for device '%(name)' cannot be completed",
+    },
+    {
         .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 d1baea0..c15e933 100644
--- a/qerror.h
+++ b/qerror.h
@@ -70,6 +70,9 @@  QError *qobject_to_qerror(const QObject *obj);
 #define QERR_BLOCK_JOB_PAUSED \
     "{ 'class': 'BlockJobPaused', 'data': { 'name': %s } }"
 
+#define QERR_BLOCK_JOB_NOT_READY \
+    "{ 'class': 'BlockJobNotReady', 'data': { 'name': %s } }"
+
 #define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
     "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
 
diff --git a/qmp-commands.hx b/qmp-commands.hx
index aff1660..f1b0f90 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -744,6 +744,11 @@  EQMP
         .mhandler.cmd_new = qmp_marshal_input_block_job_resume,
     },
     {
+        .name       = "block-job-complete",
+        .args_type  = "device:B",
+        .mhandler.cmd_new = qmp_marshal_input_block_job_complete,
+    },
+    {
         .name       = "transaction",
         .args_type  = "actions:q",
         .mhandler.cmd_new = qmp_marshal_input_transaction,
diff --git a/trace-events b/trace-events
index 306faf6..65db490 100644
--- a/trace-events
+++ b/trace-events
@@ -83,6 +83,7 @@  mirror_one_iteration(void *s, int64_t sector_num) "s %p sector_num %"PRId64
 qmp_block_job_cancel(void *job) "job %p"
 qmp_block_job_pause(void *job) "job %p"
 qmp_block_job_resume(void *job) "job %p"
+qmp_block_job_complete(void *job) "job %p"
 block_job_cb(void *bs, void *job, int ret) "bs %p job %p ret %d"
 qmp_block_stream(void *bs, void *job) "bs %p job %p"