blockjobs: add ABORTING state

Add a new state ABORTING.

This makes transitions from normative states to error states explicit
in the STM, and serves as a disambiguation for which states may complete
normally when normal end-states (CONCLUDED) are added in future commits.

Notably, Paused/Standby jobs do not transition directly to aborting,
as they must wake up first and cooperate in their cancellation.

Transitions:
Created -> Aborting: can be cancelled (by the system)
Running -> Aborting: can be cancelled or encounter an error
Ready   -> Aborting: can be cancelled or encounter an error

Verbs:
None. The job must finish cleaning itself up and report its final status.

             +---------+
             |UNDEFINED|
             +--+------+
                |
             +--v----+
   +---------+CREATED|
   |         +--+----+
   |            |
   |         +--v----+     +------+
   +---------+RUNNING<----->PAUSED|
   |         +--+----+     +------+
   |            |
   |         +--v--+       +-------+
   +---------+READY<------->STANDBY|
   |         +-----+       +-------+
   |
+--v-----+
|ABORTING|
+--------+

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
John Snow 2018-03-10 03:27:33 -05:00 committed by Kevin Wolf
parent 0ec4dfb8d6
commit 10a3fbb0f7
2 changed files with 24 additions and 14 deletions

View File

@ -44,22 +44,23 @@ static QemuMutex block_job_mutex;
/* BlockJob State Transition Table */
bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
/* U, C, R, P, Y, S */
/* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0},
/* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0},
/* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0},
/* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0},
/* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1},
/* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0},
/* U, C, R, P, Y, S, X */
/* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0},
/* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 1},
/* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1},
/* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0},
/* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1},
/* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0},
/* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0},
};
bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = {
/* U, C, R, P, Y, S */
[BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1},
[BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1},
[BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1},
[BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1},
[BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0},
/* U, C, R, P, Y, S, X */
[BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 0},
[BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0},
[BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0},
[BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0},
[BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0},
};
static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
@ -380,6 +381,10 @@ static void block_job_completed_single(BlockJob *job)
{
assert(job->completed);
if (job->ret || block_job_is_cancelled(job)) {
block_job_state_transition(job, BLOCK_JOB_STATUS_ABORTING);
}
if (!job->ret) {
if (job->driver->commit) {
job->driver->commit(job);

View File

@ -999,10 +999,15 @@
# @standby: The job is ready, but paused. This is nearly identical to @paused.
# The job may return to @ready or otherwise be canceled.
#
# @aborting: The job is in the process of being aborted, and will finish with
# an error.
# This status may not be visible to the management process.
#
# Since: 2.12
##
{ 'enum': 'BlockJobStatus',
'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby'] }
'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby',
'aborting' ] }
##
# @BlockJobInfo: