From 9374b98eb452b82fcd60a20f30a111be02fa8930 Mon Sep 17 00:00:00 2001
From: Jeffrey Cody <jcody@redhat.com>
Date: Wed, 21 Mar 2012 21:55:10 +0100
Subject: [PATCH 43/55] qmp: add block_job_cancel command

RH-Author: Jeffrey Cody <jcody@redhat.com>
Message-id: <2f125facc24af1180b063232a4c573a332f7a27c.1332362400.git.jcody@redhat.com>
Patchwork-id: 38893
O-Subject: [RHEL6.3 qemu-kvm PATCH v8 43/54] qmp: add block_job_cancel command
Bugzilla: 582475
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
RH-Acked-by: Marcelo Tosatti <mtosatti@redhat.com>
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>

From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>

Add block_job_cancel, which stops an active block streaming operation.
When the operation has been cancelled the new BLOCK_JOB_CANCELLED event
is emitted.

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Acked-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>

(cherry picked from commit 370521a1d6f5537ea7271c119f3fbb7b0fa57063)

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Jeff Cody <jcody@redhat.com>
---
 QMP/qmp-events.txt |   23 +++++++++++++++++++++++
 blockdev.c         |   21 ++++++++++++++++++++-
 blockdev.h         |    1 +
 monitor.c          |    3 +++
 monitor.h          |    1 +
 qemu-monitor.hx    |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 trace-events       |    1 +
 7 files changed, 95 insertions(+), 1 deletions(-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 QMP/qmp-events.txt |   23 +++++++++++++++++++++++
 blockdev.c         |   21 ++++++++++++++++++++-
 blockdev.h         |    1 +
 monitor.c          |    3 +++
 monitor.h          |    1 +
 qemu-monitor.hx    |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 trace-events       |    1 +
 7 files changed, 95 insertions(+), 1 deletions(-)

diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
index cb43ba7..75f4708 100644
--- a/QMP/qmp-events.txt
+++ b/QMP/qmp-events.txt
@@ -326,3 +326,26 @@ Example:
                "len": 10737418240, "offset": 10737418240,
                "speed": 0 },
      "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
+BLOCK_JOB_CANCELLED
+-------------------
+
+Emitted when a block job has been cancelled.
+
+Data:
+
+- "type":     Job type ("stream" for image streaming, json-string)
+- "device":   Device name (json-string)
+- "len":      Maximum progress value (json-int)
+- "offset":   Current progress value (json-int)
+              On success this is equal to len.
+              On failure this is less than len.
+- "speed":    Rate limit, bytes per second (json-int)
+
+Example:
+
+{ "event": "BLOCK_JOB_CANCELLED",
+     "data": { "type": "stream", "device": "virtio-disk0",
+               "len": 10737418240, "offset": 134217728,
+               "speed": 0 },
+     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
diff --git a/blockdev.c b/blockdev.c
index 3d7e3a7..ee19b39 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1029,7 +1029,11 @@ static void block_stream_cb(void *opaque, int ret)
         qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
     }
 
-    monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj);
+    if (block_job_is_cancelled(bs->job)) {
+        monitor_protocol_event(QEVENT_BLOCK_JOB_CANCELLED, obj);
+    } else {
+        monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj);
+    }
     qobject_decref(obj);
 }
 
@@ -1097,3 +1101,18 @@ int do_block_job_set_speed(Monitor *mon, const QDict *params,
     }
     return 0;
 }
+
+int do_block_job_cancel(Monitor *mon, const QDict *params, QObject **ret_data)
+{
+    const char *device = qdict_get_str(params, "device");
+    BlockJob *job = find_block_job(device);
+
+    if (!job) {
+        qerror_report(QERR_DEVICE_NOT_ACTIVE, device);
+        return -1;
+    }
+
+    trace_do_block_job_cancel(job);
+    block_job_cancel(job);
+    return 0;
+}
diff --git a/blockdev.h b/blockdev.h
index 32e516b..56adcd1 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -74,5 +74,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
 int do_block_stream(Monitor *mon, const QDict *qdict, QObject **ret_data);
 int do_block_job_set_speed(Monitor *mon, const QDict *params,
                            QObject **ret_data);
+int do_block_job_cancel(Monitor *mon, const QDict *params, QObject **ret_data);
 
 #endif
diff --git a/monitor.c b/monitor.c
index ff688a0..0954ef0 100644
--- a/monitor.c
+++ b/monitor.c
@@ -481,6 +481,9 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
         case QEVENT_BLOCK_JOB_COMPLETED:
             event_name = "BLOCK_JOB_COMPLETED";
             break;
+        case QEVENT_BLOCK_JOB_CANCELLED:
+            event_name = "BLOCK_JOB_CANCELLED";
+            break;
         case QEVENT_RH_SPICE_INITIALIZED:
             event_name = RFQDN_REDHAT "SPICE_INITIALIZED";
             break;
diff --git a/monitor.h b/monitor.h
index f315a92..bbd50f1 100644
--- a/monitor.h
+++ b/monitor.h
@@ -40,6 +40,7 @@ typedef enum MonitorEvent {
     QEVENT_SPICE_DISCONNECTED,
     QEVENT_DEVICE_TRAY_MOVED,
     QEVENT_BLOCK_JOB_COMPLETED,
+    QEVENT_BLOCK_JOB_CANCELLED,
     QEVENT_RH_SPICE_INITIALIZED,
     QEVENT_RH_SPICE_DISCONNECTED,
     QEVENT_SUSPEND,
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index af9a69e..7c318ac 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -2121,6 +2121,52 @@ Example:
     "arguments": { "device": "virtio0", "value": 1024 } }
 EQMP
 
+    {
+        .name       = "block_job_cancel",
+        .args_type  = "device:B",
+        .params     = "device",
+        .help       = "stop an active block streaming operation",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_block_job_cancel,
+    },
+
+STEXI
+@item block_job_cancel
+@findex block_job_cancel
+Stop an active block streaming operation.
+ETEXI
+
+SQMP
+block_job_cancel
+----------------
+
+Stop an active block streaming operation.
+
+This command returns immediately after marking the active block streaming
+operation for cancellation.  It is an error to call this command if no
+operation is in progress.
+
+The operation will cancel as soon as possible and then emit the
+BLOCK_JOB_CANCELLED event.  Before that happens the job is still visible when
+enumerated using query-block-jobs.
+
+The image file retains its backing file unless the streaming operation happens
+to complete just as it is being cancelled.
+
+A new block streaming operation can be started at a later time to finish
+copying all data from the backing file.
+
+Arguments:
+
+- device: the device name
+
+Returns:
+
+Nothing on success
+If streaming is not active on this device, DeviceNotActive
+If cancellation already in progress, DeviceInUse
+EQMP
+
 HXCOMM Keep the 'info' command at the end!
 HXCOMM This is required for the QMP documentation layout.
 
diff --git a/trace-events b/trace-events
index f226c1c..872fa27 100644
--- a/trace-events
+++ b/trace-events
@@ -67,6 +67,7 @@ disable stream_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is
 disable stream_start(void *bs, void *base, void *s, void *co, void *opaque) "bs %p base %p s %p co %p opaque %p"
 
 # blockdev.c
+disable do_block_job_cancel(void *job) "job %p"
 disable block_stream_cb(void *bs, void *job, int ret) "bs %p job %p ret %d"
 disable do_block_stream(void *bs, void *job) "bs %p job %p"
 
-- 
1.7.7.6

