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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user