qmp: add block-job-pause and block-job-resume

Add QMP commands matching the functionality.

Paused jobs cannot be canceled without first resuming them.  This
ensures that I/O errors are never missed by management.  However, an
optional force argument can be specified to allow that.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Paolo Bonzini 2012-09-28 17:22:51 +02:00 committed by Kevin Wolf
parent 8acc72a4d2
commit 6e37fb811a
7 changed files with 150 additions and 11 deletions

View File

@ -1213,7 +1213,29 @@ void qmp_block_job_set_speed(const char *device, int64_t speed, Error **errp)
block_job_set_speed(job, speed, errp); block_job_set_speed(job, speed, errp);
} }
void qmp_block_job_cancel(const char *device, Error **errp) void qmp_block_job_cancel(const char *device,
bool has_force, bool force, Error **errp)
{
BlockJob *job = find_block_job(device);
if (!has_force) {
force = false;
}
if (!job) {
error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);
return;
}
if (job->paused && !force) {
error_set(errp, QERR_BLOCK_JOB_PAUSED, device);
return;
}
trace_qmp_block_job_cancel(job);
block_job_cancel(job);
}
void qmp_block_job_pause(const char *device, Error **errp)
{ {
BlockJob *job = find_block_job(device); BlockJob *job = find_block_job(device);
@ -1221,13 +1243,22 @@ void qmp_block_job_cancel(const char *device, Error **errp)
error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device); error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);
return; return;
} }
if (job->paused) {
error_set(errp, QERR_BLOCK_JOB_PAUSED, device); trace_qmp_block_job_pause(job);
block_job_pause(job);
}
void qmp_block_job_resume(const char *device, Error **errp)
{
BlockJob *job = find_block_job(device);
if (!job) {
error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);
return; return;
} }
trace_qmp_block_job_cancel(job); trace_qmp_block_job_resume(job);
block_job_cancel(job); block_job_resume(job);
} }
static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs) static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)

View File

@ -99,9 +99,10 @@ ETEXI
{ {
.name = "block_job_cancel", .name = "block_job_cancel",
.args_type = "device:B", .args_type = "force:-f,device:B",
.params = "device", .params = "[-f] device",
.help = "stop an active background block operation", .help = "stop an active background block operation (use -f"
"\n\t\t\t if the operation is currently paused)",
.mhandler.cmd = hmp_block_job_cancel, .mhandler.cmd = hmp_block_job_cancel,
}, },
@ -109,6 +110,34 @@ STEXI
@item block_job_cancel @item block_job_cancel
@findex block_job_cancel @findex block_job_cancel
Stop an active block streaming operation. Stop an active block streaming operation.
ETEXI
{
.name = "block_job_pause",
.args_type = "device:B",
.params = "device",
.help = "pause an active background block operation",
.mhandler.cmd = hmp_block_job_pause,
},
STEXI
@item block_job_pause
@findex block_job_pause
Pause an active block streaming operation.
ETEXI
{
.name = "block_job_resume",
.args_type = "device:B",
.params = "device",
.help = "resume a paused background block operation",
.mhandler.cmd = hmp_block_job_resume,
},
STEXI
@item block_job_resume
@findex block_job_resume
Resume a paused block streaming operation.
ETEXI ETEXI
{ {

23
hmp.c
View File

@ -950,8 +950,29 @@ void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
{ {
Error *error = NULL; Error *error = NULL;
const char *device = qdict_get_str(qdict, "device"); const char *device = qdict_get_str(qdict, "device");
bool force = qdict_get_try_bool(qdict, "force", 0);
qmp_block_job_cancel(device, &error); qmp_block_job_cancel(device, true, force, &error);
hmp_handle_error(mon, &error);
}
void hmp_block_job_pause(Monitor *mon, const QDict *qdict)
{
Error *error = NULL;
const char *device = qdict_get_str(qdict, "device");
qmp_block_job_pause(device, &error);
hmp_handle_error(mon, &error);
}
void hmp_block_job_resume(Monitor *mon, const QDict *qdict)
{
Error *error = NULL;
const char *device = qdict_get_str(qdict, "device");
qmp_block_job_resume(device, &error);
hmp_handle_error(mon, &error); hmp_handle_error(mon, &error);
} }

2
hmp.h
View File

@ -64,6 +64,8 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
void hmp_block_stream(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_set_speed(Monitor *mon, const QDict *qdict);
void hmp_block_job_cancel(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_migrate(Monitor *mon, const QDict *qdict); void hmp_migrate(Monitor *mon, const QDict *qdict);
void hmp_device_del(Monitor *mon, const QDict *qdict); void hmp_device_del(Monitor *mon, const QDict *qdict);
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict); void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict);

View File

@ -1893,12 +1893,56 @@
# #
# @device: the device name # @device: the device name
# #
# @force: #optional whether to allow cancellation of a paused job (default
# false). Since 1.3.
#
# Returns: Nothing on success # Returns: Nothing on success
# If no background operation is active on this device, DeviceNotActive # If no background operation is active on this device, DeviceNotActive
# #
# Since: 1.1 # Since: 1.1
## ##
{ 'command': 'block-job-cancel', 'data': { 'device': 'str' } } { 'command': 'block-job-cancel', 'data': { 'device': 'str', '*force': 'bool' } }
##
# @block-job-pause:
#
# Pause an active background block operation.
#
# This command returns immediately after marking the active background block
# operation for pausing. It is an error to call this command if no
# operation is in progress. Pausing an already paused job has no cumulative
# effect; a single block-job-resume command will resume the job.
#
# The operation will pause as soon as possible. No event is emitted when
# the operation is actually paused. Cancelling a paused job automatically
# resumes it.
#
# @device: the device name
#
# Returns: Nothing on success
# If no background operation is active on this device, DeviceNotActive
#
# Since: 1.3
##
{ 'command': 'block-job-pause', 'data': { 'device': 'str' } }
##
# @block-job-resume:
#
# Resume an active background block operation.
#
# This command returns immediately after resuming a paused background block
# operation. It is an error to call this command if no operation is in
# progress. Resuming an already running job is not an error.
#
# @device: the device name
#
# Returns: Nothing on success
# If no background operation is active on this device, DeviceNotActive
#
# Since: 1.3
##
{ 'command': 'block-job-resume', 'data': { 'device': 'str' } }
## ##
# @ObjectTypeInfo: # @ObjectTypeInfo:

View File

@ -805,9 +805,19 @@ EQMP
{ {
.name = "block-job-cancel", .name = "block-job-cancel",
.args_type = "device:B", .args_type = "device:B,force:b?",
.mhandler.cmd_new = qmp_marshal_input_block_job_cancel, .mhandler.cmd_new = qmp_marshal_input_block_job_cancel,
}, },
{
.name = "block-job-pause",
.args_type = "device:B",
.mhandler.cmd_new = qmp_marshal_input_block_job_pause,
},
{
.name = "block-job-resume",
.args_type = "device:B",
.mhandler.cmd_new = qmp_marshal_input_block_job_resume,
},
{ {
.name = "transaction", .name = "transaction",
.args_type = "actions:q", .args_type = "actions:q",

View File

@ -79,6 +79,8 @@ commit_start(void *bs, void *base, void *top, void *s, void *co, void *opaque) "
# blockdev.c # blockdev.c
qmp_block_job_cancel(void *job) "job %p" qmp_block_job_cancel(void *job) "job %p"
qmp_block_job_pause(void *job) "job %p"
qmp_block_job_resume(void *job) "job %p"
block_job_cb(void *bs, void *job, int ret) "bs %p job %p ret %d" 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" qmp_block_stream(void *bs, void *job) "bs %p job %p"