Re: [Qemu-block] [RFC v4 04/21] blockjobs: add status enum

2018-02-27 Thread Kevin Wolf
Am 24.02.2018 um 00:51 hat John Snow geschrieben:
> We're about to add several new states, and booleans are becoming
> unwieldly and difficult to reason about. It would help to have a
> more explicit bookkeeping of the state of blockjobs. To this end,
> add a new "status" field and add our existing states in a redundant
> manner alongside the bools they are replacing:
> 
> UNDEFINED: Placeholder, default state. Not currently visible to QMP
>unless changes occur in the future to allow creating jobs
>without starting them via QMP.
> CREATED:   replaces !!job->co && paused && !busy
> RUNNING:   replaces effectively (!paused && busy)
> PAUSED:Nearly redundant with info->paused, which shows pause_count.
>This reports the actual status of the job, which almost always
>matches the paused request status. It differs in that it is
>strictly only true when the job has actually gone dormant.
> READY: replaces job->ready.
> STANDBY:   Paused, but job->ready is true.
> 
> New state additions in coming commits will not be quite so redundant:
> 
> WAITING:   Waiting on transaction. This job has finished all the work
>it can until the transaction converges, fails, or is canceled.
> PENDING:   Pending authorization from user. This job has finished all the
>work it can until the job or transaction is finalized via
>block_job_finalize. This implies the transaction has converged
>and left the WAITING phase.
> ABORTING:  Job has encountered an error condition and is in the process
>of aborting.
> CONCLUDED: Job has ceased all operations and has a return code available
>for query and may be dismissed via block_job_dismiss.
> NULL:  Job has been dismissed and (should) be destroyed. Should never
>be visible to QMP.
> 
> Some of these states appear somewhat superfluous, but it helps define the
> expected flow of a job; so some of the states wind up being synchronous
> empty transitions. Importantly, jobs can be in only one of these states
> at any given time, which helps code and external users alike reason about
> the current condition of a job unambiguously.
> 
> Signed-off-by: John Snow 

Reviewed-by: Kevin Wolf 



[Qemu-block] [RFC v4 04/21] blockjobs: add status enum

2018-02-23 Thread John Snow
We're about to add several new states, and booleans are becoming
unwieldly and difficult to reason about. It would help to have a
more explicit bookkeeping of the state of blockjobs. To this end,
add a new "status" field and add our existing states in a redundant
manner alongside the bools they are replacing:

UNDEFINED: Placeholder, default state. Not currently visible to QMP
   unless changes occur in the future to allow creating jobs
   without starting them via QMP.
CREATED:   replaces !!job->co && paused && !busy
RUNNING:   replaces effectively (!paused && busy)
PAUSED:Nearly redundant with info->paused, which shows pause_count.
   This reports the actual status of the job, which almost always
   matches the paused request status. It differs in that it is
   strictly only true when the job has actually gone dormant.
READY: replaces job->ready.
STANDBY:   Paused, but job->ready is true.

New state additions in coming commits will not be quite so redundant:

WAITING:   Waiting on transaction. This job has finished all the work
   it can until the transaction converges, fails, or is canceled.
PENDING:   Pending authorization from user. This job has finished all the
   work it can until the job or transaction is finalized via
   block_job_finalize. This implies the transaction has converged
   and left the WAITING phase.
ABORTING:  Job has encountered an error condition and is in the process
   of aborting.
CONCLUDED: Job has ceased all operations and has a return code available
   for query and may be dismissed via block_job_dismiss.
NULL:  Job has been dismissed and (should) be destroyed. Should never
   be visible to QMP.

Some of these states appear somewhat superfluous, but it helps define the
expected flow of a job; so some of the states wind up being synchronous
empty transitions. Importantly, jobs can be in only one of these states
at any given time, which helps code and external users alike reason about
the current condition of a job unambiguously.

Signed-off-by: John Snow 
---
 blockjob.c |  9 +
 include/block/blockjob.h   |  7 +--
 qapi/block-core.json   | 31 ++-
 tests/qemu-iotests/109.out | 24 
 4 files changed, 56 insertions(+), 15 deletions(-)

diff --git a/blockjob.c b/blockjob.c
index 47468331ec..1be9c20cff 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -320,6 +320,7 @@ void block_job_start(BlockJob *job)
 job->pause_count--;
 job->busy = true;
 job->paused = false;
+job->status = BLOCK_JOB_STATUS_RUNNING;
 bdrv_coroutine_enter(blk_bs(job->blk), job->co);
 }
 
@@ -598,6 +599,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
 info->speed = job->speed;
 info->io_status = job->iostatus;
 info->ready = job->ready;
+info->status= job->status;
 return info;
 }
 
@@ -701,6 +703,7 @@ void *block_job_create(const char *job_id, const 
BlockJobDriver *driver,
 job->pause_count   = 1;
 job->refcnt= 1;
 job->manual= (flags & BLOCK_JOB_MANUAL);
+job->status= BLOCK_JOB_STATUS_CREATED;
 aio_timer_init(qemu_get_aio_context(), >sleep_timer,
QEMU_CLOCK_REALTIME, SCALE_NS,
block_job_sleep_timer_cb, job);
@@ -814,9 +817,14 @@ void coroutine_fn block_job_pause_point(BlockJob *job)
 }
 
 if (block_job_should_pause(job) && !block_job_is_cancelled(job)) {
+BlockJobStatus status = job->status;
+job->status = status == BLOCK_JOB_STATUS_READY ? \
+BLOCK_JOB_STATUS_STANDBY : \
+BLOCK_JOB_STATUS_PAUSED;
 job->paused = true;
 block_job_do_yield(job, -1);
 job->paused = false;
+job->status = status;
 }
 
 if (job->driver->resume) {
@@ -922,6 +930,7 @@ void block_job_iostatus_reset(BlockJob *job)
 
 void block_job_event_ready(BlockJob *job)
 {
+job->status = BLOCK_JOB_STATUS_READY;
 job->ready = true;
 
 if (block_job_is_internal(job)) {
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
index 8ffabdcbc4..e254359d6b 100644
--- a/include/block/blockjob.h
+++ b/include/block/blockjob.h
@@ -143,10 +143,13 @@ typedef struct BlockJob {
 
 /**
  * Set to true when the management API has requested manual job
- * management semantics.
+ * management semantics. See @BlockJobStatus for details.
  */
 bool manual;
 
+/** Current state; See @BlockJobStatus for details. */
+BlockJobStatus status;
+
 /** Non-NULL if this job is part of a transaction */
 BlockJobTxn *txn;
 QLIST_ENTRY(BlockJob) txn_list;
@@ -157,7 +160,7 @@ typedef enum BlockJobCreateFlags {
 BLOCK_JOB_DEFAULT = 0x00,
 /* BlockJob is not QMP-created and should not send QMP events */
 BLOCK_JOB_INTERNAL = 0x01,