summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/trace-events1
-rw-r--r--blockdev.c14
-rw-r--r--blockjob.c26
-rw-r--r--include/block/blockjob.h14
-rw-r--r--qapi/block-core.json24
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.