block: add block-job-complete
While streaming can be dropped as soon as it progressed through the whole image, mirroring needs to be completed manually for two reasons: 1) so that management knows exactly when the VM switches to the target; 2) because for other use cases such as replication, we may leave the operation running for the whole life of the virtual machine. Add a new block job command that manually completes background operations. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
65f4632243
commit
aeae883baf
13
blockdev.c
13
blockdev.c
@ -1266,6 +1266,19 @@ void qmp_block_job_resume(const char *device, Error **errp)
|
||||
block_job_resume(job);
|
||||
}
|
||||
|
||||
void qmp_block_job_complete(const char *device, Error **errp)
|
||||
{
|
||||
BlockJob *job = find_block_job(device);
|
||||
|
||||
if (!job) {
|
||||
error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);
|
||||
return;
|
||||
}
|
||||
|
||||
trace_qmp_block_job_complete(job);
|
||||
block_job_complete(job, errp);
|
||||
}
|
||||
|
||||
static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
|
||||
{
|
||||
BlockJobInfoList **prev = opaque;
|
||||
|
10
blockjob.c
10
blockjob.c
@ -99,6 +99,16 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||
job->speed = speed;
|
||||
}
|
||||
|
||||
void block_job_complete(BlockJob *job, Error **errp)
|
||||
{
|
||||
if (job->paused || job->cancelled || !job->job_type->complete) {
|
||||
error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
|
||||
return;
|
||||
}
|
||||
|
||||
job->job_type->complete(job, errp);
|
||||
}
|
||||
|
||||
void block_job_pause(BlockJob *job)
|
||||
{
|
||||
job->paused = true;
|
||||
|
15
blockjob.h
15
blockjob.h
@ -41,6 +41,12 @@ typedef struct BlockJobType {
|
||||
|
||||
/** Optional callback for job types that support setting a speed limit */
|
||||
void (*set_speed)(BlockJob *job, int64_t speed, Error **errp);
|
||||
|
||||
/**
|
||||
* Optional callback for job types whose completion must be triggered
|
||||
* manually.
|
||||
*/
|
||||
void (*complete)(BlockJob *job, Error **errp);
|
||||
} BlockJobType;
|
||||
|
||||
/**
|
||||
@ -163,6 +169,15 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp);
|
||||
*/
|
||||
void block_job_cancel(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_complete:
|
||||
* @job: The job to be completed.
|
||||
* @errp: Error object.
|
||||
*
|
||||
* Asynchronously complete the specified job.
|
||||
*/
|
||||
void block_job_complete(BlockJob *job, Error **errp);
|
||||
|
||||
/**
|
||||
* block_job_is_cancelled:
|
||||
* @job: The job being queried.
|
||||
|
@ -109,7 +109,22 @@ ETEXI
|
||||
STEXI
|
||||
@item block_job_cancel
|
||||
@findex block_job_cancel
|
||||
Stop an active block streaming operation.
|
||||
Stop an active background block operation (streaming, mirroring).
|
||||
ETEXI
|
||||
|
||||
{
|
||||
.name = "block_job_complete",
|
||||
.args_type = "device:B",
|
||||
.params = "device",
|
||||
.help = "stop an active background block operation",
|
||||
.mhandler.cmd = hmp_block_job_complete,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@item block_job_complete
|
||||
@findex block_job_complete
|
||||
Manually trigger completion of an active background block operation.
|
||||
For mirroring, this will switch the device to the destination path.
|
||||
ETEXI
|
||||
|
||||
{
|
||||
|
10
hmp.c
10
hmp.c
@ -990,6 +990,16 @@ void hmp_block_job_resume(Monitor *mon, const QDict *qdict)
|
||||
hmp_handle_error(mon, &error);
|
||||
}
|
||||
|
||||
void hmp_block_job_complete(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *error = NULL;
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
|
||||
qmp_block_job_complete(device, &error);
|
||||
|
||||
hmp_handle_error(mon, &error);
|
||||
}
|
||||
|
||||
typedef struct MigrationStatus
|
||||
{
|
||||
QEMUTimer *timer;
|
||||
|
1
hmp.h
1
hmp.h
@ -66,6 +66,7 @@ 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_pause(Monitor *mon, const QDict *qdict);
|
||||
void hmp_block_job_resume(Monitor *mon, const QDict *qdict);
|
||||
void hmp_block_job_complete(Monitor *mon, const QDict *qdict);
|
||||
void hmp_migrate(Monitor *mon, const QDict *qdict);
|
||||
void hmp_device_del(Monitor *mon, const QDict *qdict);
|
||||
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict);
|
||||
|
@ -2032,6 +2032,31 @@
|
||||
##
|
||||
{ 'command': 'block-job-resume', 'data': { 'device': 'str' } }
|
||||
|
||||
##
|
||||
# @block-job-complete:
|
||||
#
|
||||
# Manually trigger completion of an active background block operation. This
|
||||
# is supported for drive mirroring, where it also switches the device to
|
||||
# write to the target path only.
|
||||
#
|
||||
# This command completes an active background block operation synchronously.
|
||||
# The ordering of this command's return with the BLOCK_JOB_COMPLETED event
|
||||
# is not defined. Note that if an I/O error occurs during the processing of
|
||||
# this command: 1) the command itself will fail; 2) the error will be processed
|
||||
# according to the rerror/werror arguments that were specified when starting
|
||||
# the operation.
|
||||
#
|
||||
# A cancelled or paused job cannot be completed.
|
||||
#
|
||||
# @device: the device name
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
# If no background operation is active on this device, DeviceNotActive
|
||||
#
|
||||
# Since: 1.3
|
||||
##
|
||||
{ 'command': 'block-job-complete', 'data': { 'device': 'str' } }
|
||||
|
||||
##
|
||||
# @ObjectTypeInfo:
|
||||
#
|
||||
|
3
qerror.h
3
qerror.h
@ -54,6 +54,9 @@ void assert_no_error(Error *err);
|
||||
#define QERR_BLOCK_JOB_PAUSED \
|
||||
ERROR_CLASS_GENERIC_ERROR, "The block job for device '%s' is currently paused"
|
||||
|
||||
#define QERR_BLOCK_JOB_NOT_READY \
|
||||
ERROR_CLASS_GENERIC_ERROR, "The active block job for device '%s' cannot be completed"
|
||||
|
||||
#define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
|
||||
ERROR_CLASS_GENERIC_ERROR, "Block format '%s' used by device '%s' does not support feature '%s'"
|
||||
|
||||
|
@ -842,6 +842,11 @@ EQMP
|
||||
.args_type = "device:B",
|
||||
.mhandler.cmd_new = qmp_marshal_input_block_job_resume,
|
||||
},
|
||||
{
|
||||
.name = "block-job-complete",
|
||||
.args_type = "device:B",
|
||||
.mhandler.cmd_new = qmp_marshal_input_block_job_complete,
|
||||
},
|
||||
{
|
||||
.name = "transaction",
|
||||
.args_type = "actions:q",
|
||||
|
@ -81,6 +81,7 @@ commit_start(void *bs, void *base, void *top, void *s, void *co, void *opaque) "
|
||||
qmp_block_job_cancel(void *job) "job %p"
|
||||
qmp_block_job_pause(void *job) "job %p"
|
||||
qmp_block_job_resume(void *job) "job %p"
|
||||
qmp_block_job_complete(void *job) "job %p"
|
||||
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"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user