Skip to content

Commit

Permalink
block: add block-job-complete
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Kevin Wolf <[email protected]>
bonzini authored and kevmw committed Oct 24, 2012
1 parent 65f4632 commit aeae883
Showing 10 changed files with 99 additions and 1 deletion.
13 changes: 13 additions & 0 deletions blockdev.c
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions blockjob.c
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions blockjob.h
Original file line number Diff line number Diff line change
@@ -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.
17 changes: 16 additions & 1 deletion hmp-commands.hx
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions hmp.c
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions hmp.h
Original file line number Diff line number Diff line change
@@ -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);
25 changes: 25 additions & 0 deletions qapi-schema.json
Original file line number Diff line number Diff line change
@@ -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 changes: 3 additions & 0 deletions qerror.h
Original file line number Diff line number Diff line change
@@ -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'"

5 changes: 5 additions & 0 deletions qmp-commands.hx
Original file line number Diff line number Diff line change
@@ -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",
1 change: 1 addition & 0 deletions trace-events
Original file line number Diff line number Diff line change
@@ -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"

0 comments on commit aeae883

Please sign in to comment.