Add block_job_cancel, which stops an active block streaming operation. Signed-off-by: Stefan Hajnoczi <stefa...@linux.vnet.ibm.com> --- blockdev.c | 19 ++++++++++++++++++- hmp-commands.hx | 14 ++++++++++++++ hmp.c | 13 +++++++++++++ hmp.h | 1 + monitor.c | 3 +++ monitor.h | 1 + qapi-schema.json | 36 ++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 18 ++++++++++++++++++ trace-events | 1 + 9 files changed, 105 insertions(+), 1 deletions(-)
diff --git a/blockdev.c b/blockdev.c index b101ba1..b276b2f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -919,7 +919,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); } @@ -980,3 +984,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); +} diff --git a/hmp-commands.hx b/hmp-commands.hx index 788ec97..cc91055 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -99,6 +99,20 @@ 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 + + { .name = "eject", .args_type = "force:-f,device:B", .params = "[-f] device", diff --git a/hmp.c b/hmp.c index f3edf7c..66d9d0f 100644 --- a/hmp.c +++ b/hmp.c @@ -559,3 +559,16 @@ void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict) error_free(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); + + if (error) { + monitor_printf(mon, "%s\n", error_get_pretty(error)); + error_free(error); + } +} diff --git a/hmp.h b/hmp.h index 4c1458e..30d9051 100644 --- a/hmp.h +++ b/hmp.h @@ -39,5 +39,6 @@ void hmp_system_powerdown(Monitor *mon, const QDict *qdict); void hmp_cpu(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 diff --git a/monitor.c b/monitor.c index a33218c..5bf29f2 100644 --- a/monitor.c +++ b/monitor.c @@ -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; diff --git a/monitor.h b/monitor.h index d9b07dc..2e7f38a 100644 --- a/monitor.h +++ b/monitor.h @@ -36,6 +36,7 @@ typedef enum MonitorEvent { QEVENT_SPICE_INITIALIZED, QEVENT_SPICE_DISCONNECTED, QEVENT_BLOCK_JOB_COMPLETED, + QEVENT_BLOCK_JOB_CANCELLED, QEVENT_MAX, } MonitorEvent; diff --git a/qapi-schema.json b/qapi-schema.json index f6a8252..270d05e 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -943,6 +943,10 @@ # - speed: rate limit, bytes per second (json-int) # - error: error message (json-string, only on error) # +# If the operation was cancelled using block_job_cancel then the +# BLOCK_JOB_CANCELLED event is raised with the same fields as +# BLOCK_JOB_COMPLETED. +# # The completion event is raised both on success and on failure. On # success offset is equal to len. On failure offset and len can be # used to indicate at which point the operation failed. @@ -977,3 +981,35 @@ ## { '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 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: device name +# +# Errors: +# +# DeviceNotActive: streaming is not active on this device +# DeviceInUse: cancellation already in progress +# +# Since: 1.1 +## +{ 'command': 'block_job_cancel', 'data': { 'device': 'str' } } diff --git a/qmp-commands.hx b/qmp-commands.hx index 5541ca0..a57d079 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -719,6 +719,24 @@ Example: EQMP { + .name = "block_job_cancel", + .args_type = "device:B", + .mhandler.cmd_new = qmp_marshal_input_block_job_cancel, + }, + +SQMP +block_job_cancel +---------------- +See qapi-schema.json for documentation. + +Examples: + +-> { "execute": "block_job_cancel", "arguments": { "device": "virtio0" } } +<- { "return": {} } + +EQMP + + { .name = "blockdev-snapshot-sync", .args_type = "device:B,snapshot-file:s?,format:s?", .params = "device [new-image-file] [format]", diff --git a/trace-events b/trace-events index 6c1eec2..cbca6d5 100644 --- a/trace-events +++ b/trace-events @@ -74,6 +74,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" -- 1.7.7.3