diff options
-rw-r--r-- | block/trace-events | 1 | ||||
-rw-r--r-- | blockdev.c | 14 | ||||
-rw-r--r-- | blockjob.c | 26 | ||||
-rw-r--r-- | include/block/blockjob.h | 14 | ||||
-rw-r--r-- | qapi/block-core.json | 24 |
5 files changed, 76 insertions, 3 deletions
diff --git a/block/trace-events b/block/trace-events index 38e8b6db4a..7212f2ae2d 100644 --- a/block/trace-events +++ b/block/trace-events @@ -52,6 +52,7 @@ 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" +qmp_block_job_dismiss(void *job) "job %p" qmp_block_stream(void *bs, void *job) "bs %p job %p" # block/file-win32.c diff --git a/blockdev.c b/blockdev.c index 93ed3308e3..fc35d7c7bb 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3872,6 +3872,20 @@ void qmp_block_job_complete(const char *device, Error **errp) aio_context_release(aio_context); } +void qmp_block_job_dismiss(const char *id, Error **errp) +{ + AioContext *aio_context; + BlockJob *job = find_block_job(id, &aio_context, errp); + + if (!job) { + return; + } + + trace_qmp_block_job_dismiss(job); + block_job_dismiss(&job, errp); + aio_context_release(aio_context); +} + void qmp_change_backing_file(const char *device, const char *image_node_name, const char *backing_file, diff --git a/blockjob.c b/blockjob.c index 2ef48075b0..59ac4a13c7 100644 --- a/blockjob.c +++ b/blockjob.c @@ -63,6 +63,7 @@ bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = { [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0}, [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0}, [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0}, + [BLOCK_JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 1, 0}, }; static void block_job_state_transition(BlockJob *job, BlockJobStatus s1) @@ -391,9 +392,17 @@ static void block_job_decommission(BlockJob *job) block_job_unref(job); } +static void block_job_do_dismiss(BlockJob *job) +{ + block_job_decommission(job); +} + static void block_job_conclude(BlockJob *job) { block_job_state_transition(job, BLOCK_JOB_STATUS_CONCLUDED); + if (job->auto_dismiss || !block_job_started(job)) { + block_job_do_dismiss(job); + } } static void block_job_completed_single(BlockJob *job) @@ -437,7 +446,6 @@ static void block_job_completed_single(BlockJob *job) QLIST_REMOVE(job, txn_list); block_job_txn_unref(job->txn); block_job_conclude(job); - block_job_decommission(job); } static void block_job_cancel_async(BlockJob *job) @@ -602,6 +610,19 @@ void block_job_complete(BlockJob *job, Error **errp) job->driver->complete(job, errp); } +void block_job_dismiss(BlockJob **jobptr, Error **errp) +{ + BlockJob *job = *jobptr; + /* similarly to _complete, this is QMP-interface only. */ + assert(job->id); + if (block_job_apply_verb(job, BLOCK_JOB_VERB_DISMISS, errp)) { + return; + } + + block_job_do_dismiss(job); + *jobptr = NULL; +} + void block_job_user_pause(BlockJob *job, Error **errp) { if (block_job_apply_verb(job, BLOCK_JOB_VERB_PAUSE, errp)) { @@ -638,7 +659,7 @@ void block_job_user_resume(BlockJob *job, Error **errp) void block_job_cancel(BlockJob *job) { if (job->status == BLOCK_JOB_STATUS_CONCLUDED) { - return; + block_job_do_dismiss(job); } else if (block_job_started(job)) { block_job_cancel_async(job); block_job_enter(job); @@ -807,6 +828,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, job->paused = true; job->pause_count = 1; job->refcnt = 1; + job->auto_dismiss = !(flags & BLOCK_JOB_MANUAL_DISMISS); block_job_state_transition(job, BLOCK_JOB_STATUS_CREATED); aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, QEMU_CLOCK_REALTIME, SCALE_NS, diff --git a/include/block/blockjob.h b/include/block/blockjob.h index df0a9773d1..c535829b46 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -142,6 +142,9 @@ typedef struct BlockJob { /** Current state; See @BlockJobStatus for details. */ BlockJobStatus status; + /** True if this job should automatically dismiss itself */ + bool auto_dismiss; + BlockJobTxn *txn; QLIST_ENTRY(BlockJob) txn_list; } BlockJob; @@ -151,6 +154,8 @@ typedef enum BlockJobCreateFlags { BLOCK_JOB_DEFAULT = 0x00, /* BlockJob is not QMP-created and should not send QMP events */ BLOCK_JOB_INTERNAL = 0x01, + /* BlockJob requires manual dismiss step */ + BLOCK_JOB_MANUAL_DISMISS = 0x04, } BlockJobCreateFlags; /** @@ -235,6 +240,15 @@ void block_job_cancel(BlockJob *job); void block_job_complete(BlockJob *job, Error **errp); /** + * block_job_dismiss: + * @job: The job to be dismissed. + * @errp: Error object. + * + * Remove a concluded job from the query list. + */ +void block_job_dismiss(BlockJob **job, Error **errp); + +/** * block_job_query: * @job: The job to get information about. * diff --git a/qapi/block-core.json b/qapi/block-core.json index ef18abe09a..afb2e63fa6 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -973,10 +973,12 @@ # # @complete: see @block-job-complete # +# @dismiss: see @block-job-dismiss +# # Since: 2.12 ## { 'enum': 'BlockJobVerb', - 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete' ] } + 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete', 'dismiss' ] } ## # @BlockJobStatus: @@ -2247,6 +2249,26 @@ { 'command': 'block-job-complete', 'data': { 'device': 'str' } } ## +# @block-job-dismiss: +# +# For jobs that have already concluded, remove them from the block-job-query +# list. This command only needs to be run for jobs which were started with +# QEMU 2.12+ job lifetime management semantics. +# +# This command will refuse to operate on any job that has not yet reached +# its terminal state, BLOCK_JOB_STATUS_CONCLUDED. For jobs that make use of +# BLOCK_JOB_READY event, block-job-cancel or block-job-complete will still need +# to be used as appropriate. +# +# @id: The job identifier. +# +# Returns: Nothing on success +# +# Since: 2.12 +## +{ 'command': 'block-job-dismiss', 'data': { 'id': 'str' } } + +## # @BlockdevDiscardOptions: # # Determines how to handle discard requests. |