Add block_job_cancel, which stops an active block streaming operation. Signed-off-by: Stefan Hajnoczi <stefa...@linux.vnet.ibm.com> --- blockdev.c | 35 +++++++++++++++++++++++++++++++++++ blockdev.h | 3 +++ hmp-commands.hx | 16 ++++++++++++++++ qmp-commands.hx | 41 +++++++++++++++++++++++++++++++++++++++++ trace-events | 2 ++ 5 files changed, 97 insertions(+), 0 deletions(-)
diff --git a/blockdev.c b/blockdev.c index 781825b..5ad7d3b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -884,3 +884,38 @@ int do_block_job_set_speed(Monitor *mon, const QDict *params, } return 0; } + +typedef struct BlockJobCancelData { + MonitorCompletion *cb; + void *opaque; +} BlockJobCancelData; + +static void do_block_job_cancel_cb(void *opaque) +{ + BlockJobCancelData *cancel_data = opaque; + + trace_block_job_cancel_cb(cancel_data, cancel_data->opaque); + + cancel_data->cb(cancel_data->opaque, NULL); + g_free(cancel_data); +} + +int do_block_job_cancel(Monitor *mon, const QDict *params, + MonitorCompletion *cb, void *opaque) +{ + const char *device = qdict_get_str(params, "device"); + BlockJob *job = find_block_job(device); + BlockJobCancelData *cancel_data; + + if (!job) { + qerror_report(QERR_DEVICE_NOT_ACTIVE, device); + return -1; + } + + cancel_data = g_malloc(sizeof(*cancel_data)); + cancel_data->cb = cb; + cancel_data->opaque = opaque; + trace_do_block_job_cancel(job, cancel_data, opaque); + block_job_cancel(job, do_block_job_cancel_cb, cancel_data); + return 0; +} diff --git a/blockdev.h b/blockdev.h index 6b48405..7d3db30 100644 --- a/blockdev.h +++ b/blockdev.h @@ -11,6 +11,7 @@ #define BLOCKDEV_H #include "block.h" +#include "monitor.h" #include "qemu-queue.h" void blockdev_mark_auto_del(BlockDriverState *bs); @@ -68,5 +69,7 @@ int do_block_resize(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 *qdict, QObject **ret_data); +int do_block_job_cancel(Monitor *mon, const QDict *params, + MonitorCompletion *cb, void *opaque); #endif diff --git a/hmp-commands.hx b/hmp-commands.hx index 2cdfa0b..a8b83f0 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -101,6 +101,22 @@ 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", + .user_print = monitor_user_noop, + .mhandler.cmd_async = do_block_job_cancel, + .flags = MONITOR_CMD_ASYNC, + }, + +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/qmp-commands.hx b/qmp-commands.hx index 6cfb548..741c2f8 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -785,6 +785,47 @@ Example: EQMP { + .name = "block_job_cancel", + .args_type = "device:B", + .params = "device", + .user_print = monitor_user_noop, + .mhandler.cmd_async = do_block_job_cancel, + .flags = MONITOR_CMD_ASYNC, + }, + +SQMP + +block_job_cancel +---------------- + +Stop an active block streaming operation. + +This command returns once the active block streaming operation has been +stopped. It is an error to call this command if no operation is in progress. + +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 (json-string) + +Errors: + +DeviceNotActive: streaming is not active on this device +DeviceInUse: cancellation already in progress + +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 15a6b7a..39023cc 100644 --- a/trace-events +++ b/trace-events @@ -76,6 +76,8 @@ stream_one_iteration(void *s, int64_t sector_num, int max_sectors) "s %p sector_ stream_start(void *bs, void *base, void *s, void *co, void *opaque) "bs %p base %p s %p co %p opaque %p" # blockdev.c +block_job_cancel_cb(void *cancel_data, void *opaque) "cancel_data %p opaque %p" +do_block_job_cancel(void *job, void *cancel_data, void *opaque) "job %p cancel_data %p opaque %p" block_stream_cb(void *bs, void *job, int ret) "bs %p job %p ret %d" do_block_stream(void *bs, void *job) "bs %p job %p" -- 1.7.7