Commit 370521a1 authored by Stefan Hajnoczi's avatar Stefan Hajnoczi Committed by Kevin Wolf

qmp: add block_job_cancel command

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: default avatarStefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Acked-by: default avatarLuiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent 2d47c6e9
......@@ -293,3 +293,27 @@ 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 } }
......@@ -928,7 +928,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);
}
......@@ -989,3 +993,16 @@ void qmp_block_job_set_speed(const char *device, int64_t value, Error **errp)
error_set(errp, QERR_NOT_SUPPORTED);
}
}
void qmp_block_job_cancel(const char *device, Error **errp)
{
BlockJob *job = find_block_job(device);
if (!job) {
error_set(errp, QERR_DEVICE_NOT_ACTIVE, device);
return;
}
trace_qmp_block_job_cancel(job);
block_job_cancel(job);
}
......@@ -95,6 +95,20 @@ STEXI
@item block_job_set_stream
@findex block_job_set_stream
Set maximum speed for a background block operation.
ETEXI
{
.name = "block_job_cancel",
.args_type = "device:B",
.params = "device",
.help = "stop an active block streaming operation",
.mhandler.cmd = hmp_block_job_cancel,
},
STEXI
@item block_job_cancel
@findex block_job_cancel
Stop an active block streaming operation.
ETEXI
{
......
......@@ -805,3 +805,13 @@ void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, &error);
}
void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
{
Error *error = NULL;
const char *device = qdict_get_str(qdict, "device");
qmp_block_job_cancel(device, &error);
hmp_handle_error(mon, &error);
}
......@@ -56,5 +56,6 @@ void hmp_change(Monitor *mon, const QDict *qdict);
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
void hmp_block_stream(Monitor *mon, const QDict *qdict);
void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
#endif
......@@ -482,6 +482,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;
default:
abort();
break;
......
......@@ -37,6 +37,7 @@ typedef enum MonitorEvent {
QEVENT_SPICE_INITIALIZED,
QEVENT_SPICE_DISCONNECTED,
QEVENT_BLOCK_JOB_COMPLETED,
QEVENT_BLOCK_JOB_CANCELLED,
QEVENT_MAX,
} MonitorEvent;
......
......@@ -1487,3 +1487,32 @@
##
{ 'command': 'block_job_set_speed',
'data': { 'device': 'str', 'value': 'int' } }
##
# @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.
#
# @device: the device name
#
# Returns: Nothing on success
# If streaming is not active on this device, DeviceNotActive
# If cancellation already in progress, DeviceInUse
#
# Since: 1.1
##
{ 'command': 'block_job_cancel', 'data': { 'device': 'str' } }
......@@ -660,6 +660,12 @@ EQMP
.mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,
},
{
.name = "block_job_cancel",
.args_type = "device:B",
.mhandler.cmd_new = qmp_marshal_input_block_job_cancel,
},
{
.name = "blockdev-snapshot-sync",
.args_type = "device:B,snapshot-file:s,format:s?",
......
......@@ -75,6 +75,7 @@ stream_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocat
stream_start(void *bs, void *base, void *s, void *co, void *opaque) "bs %p base %p s %p co %p opaque %p"
# blockdev.c
qmp_block_job_cancel(void *job) "job %p"
block_stream_cb(void *bs, void *job, int ret) "bs %p job %p ret %d"
qmp_block_stream(void *bs, void *job) "bs %p job %p"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment