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:
parent
8acc72a4d2
commit
6e37fb811a
41
blockdev.c
41
blockdev.c
@ -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)
|
||||||
|
@ -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
23
hmp.c
@ -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
2
hmp.h
@ -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);
|
||||||
|
@ -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:
|
||||||
|
@ -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",
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user