job: Add job_transition_to_ready()
The transition to the READY state was still performed in the BlockJob layer, in the same function that sent the BLOCK_JOB_READY QMP event. This patch brings the state transition to the Job layer and implements the QMP event using a notifier called from the Job layer, like we already do for other events related to state transitions. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
df956ae201
commit
2e1795b581
@ -727,8 +727,8 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
}
|
||||
|
||||
if (s->bdev_length == 0) {
|
||||
/* Report BLOCK_JOB_READY and wait for complete. */
|
||||
block_job_event_ready(&s->common);
|
||||
/* Transition to the READY state and wait for complete. */
|
||||
job_transition_to_ready(&s->common.job);
|
||||
s->synced = true;
|
||||
while (!job_is_cancelled(&s->common.job) && !s->should_complete) {
|
||||
job_yield(&s->common.job);
|
||||
@ -824,7 +824,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
* report completion. This way, block-job-cancel will leave
|
||||
* the target in a consistent state.
|
||||
*/
|
||||
block_job_event_ready(&s->common);
|
||||
job_transition_to_ready(&s->common.job);
|
||||
s->synced = true;
|
||||
}
|
||||
|
||||
|
33
blockjob.c
33
blockjob.c
@ -338,6 +338,22 @@ static void block_job_event_pending(Notifier *n, void *opaque)
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static void block_job_event_ready(Notifier *n, void *opaque)
|
||||
{
|
||||
BlockJob *job = opaque;
|
||||
|
||||
if (block_job_is_internal(job)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qapi_event_send_block_job_ready(job_type(&job->job),
|
||||
job->job.id,
|
||||
job->len,
|
||||
job->offset,
|
||||
job->speed, &error_abort);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* API for block job drivers and the block layer. These functions are
|
||||
* declared in blockjob_int.h.
|
||||
@ -386,12 +402,14 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
job->finalize_cancelled_notifier.notify = block_job_event_cancelled;
|
||||
job->finalize_completed_notifier.notify = block_job_event_completed;
|
||||
job->pending_notifier.notify = block_job_event_pending;
|
||||
job->ready_notifier.notify = block_job_event_ready;
|
||||
|
||||
notifier_list_add(&job->job.on_finalize_cancelled,
|
||||
&job->finalize_cancelled_notifier);
|
||||
notifier_list_add(&job->job.on_finalize_completed,
|
||||
&job->finalize_completed_notifier);
|
||||
notifier_list_add(&job->job.on_pending, &job->pending_notifier);
|
||||
notifier_list_add(&job->job.on_ready, &job->ready_notifier);
|
||||
|
||||
error_setg(&job->blocker, "block device is in use by block job: %s",
|
||||
job_type_str(&job->job));
|
||||
@ -433,21 +451,6 @@ void block_job_user_resume(Job *job)
|
||||
block_job_iostatus_reset(bjob);
|
||||
}
|
||||
|
||||
void block_job_event_ready(BlockJob *job)
|
||||
{
|
||||
job_state_transition(&job->job, JOB_STATUS_READY);
|
||||
|
||||
if (block_job_is_internal(job)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qapi_event_send_block_job_ready(job_type(&job->job),
|
||||
job->job.id,
|
||||
job->len,
|
||||
job->offset,
|
||||
job->speed, &error_abort);
|
||||
}
|
||||
|
||||
BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
|
||||
int is_read, int error)
|
||||
{
|
||||
|
@ -76,6 +76,9 @@ typedef struct BlockJob {
|
||||
/** Called when the job transitions to PENDING */
|
||||
Notifier pending_notifier;
|
||||
|
||||
/** Called when the job transitions to READY */
|
||||
Notifier ready_notifier;
|
||||
|
||||
/** BlockDriverStates that are involved in this block job */
|
||||
GSList *nodes;
|
||||
} BlockJob;
|
||||
|
@ -115,14 +115,6 @@ void block_job_drain(Job *job);
|
||||
*/
|
||||
int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n);
|
||||
|
||||
/**
|
||||
* block_job_event_ready:
|
||||
* @job: The job which is now ready to be completed.
|
||||
*
|
||||
* Send a BLOCK_JOB_READY event for the specified job.
|
||||
*/
|
||||
void block_job_event_ready(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_error_action:
|
||||
* @job: The job to signal an error for.
|
||||
|
@ -132,6 +132,9 @@ typedef struct Job {
|
||||
/** Notifiers called when the job transitions to PENDING */
|
||||
NotifierList on_pending;
|
||||
|
||||
/** Notifiers called when the job transitions to READY */
|
||||
NotifierList on_ready;
|
||||
|
||||
/** Element of the list of jobs */
|
||||
QLIST_ENTRY(Job) job_list;
|
||||
|
||||
@ -426,6 +429,9 @@ int job_apply_verb(Job *job, JobVerb verb, Error **errp);
|
||||
/** The @job could not be started, free it. */
|
||||
void job_early_fail(Job *job);
|
||||
|
||||
/** Moves the @job from RUNNING to READY */
|
||||
void job_transition_to_ready(Job *job);
|
||||
|
||||
/**
|
||||
* @job: The job being completed.
|
||||
* @ret: The status code.
|
||||
@ -522,7 +528,4 @@ void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque);
|
||||
*/
|
||||
int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp);
|
||||
|
||||
/* TODO To be removed from the public interface */
|
||||
void job_state_transition(Job *job, JobStatus s1);
|
||||
|
||||
#endif
|
||||
|
16
job.c
16
job.c
@ -157,9 +157,7 @@ static int job_txn_apply(JobTxn *txn, int fn(Job *), bool lock)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* TODO Make static once the whole state machine is in job.c */
|
||||
void job_state_transition(Job *job, JobStatus s1)
|
||||
static void job_state_transition(Job *job, JobStatus s1)
|
||||
{
|
||||
JobStatus s0 = job->status;
|
||||
assert(s1 >= 0 && s1 <= JOB_STATUS__MAX);
|
||||
@ -321,6 +319,7 @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn,
|
||||
notifier_list_init(&job->on_finalize_cancelled);
|
||||
notifier_list_init(&job->on_finalize_completed);
|
||||
notifier_list_init(&job->on_pending);
|
||||
notifier_list_init(&job->on_ready);
|
||||
|
||||
job_state_transition(job, JOB_STATUS_CREATED);
|
||||
aio_timer_init(qemu_get_aio_context(), &job->sleep_timer,
|
||||
@ -380,6 +379,11 @@ static void job_event_pending(Job *job)
|
||||
notifier_list_notify(&job->on_pending, job);
|
||||
}
|
||||
|
||||
static void job_event_ready(Job *job)
|
||||
{
|
||||
notifier_list_notify(&job->on_ready, job);
|
||||
}
|
||||
|
||||
void job_enter_cond(Job *job, bool(*fn)(Job *job))
|
||||
{
|
||||
if (!job_started(job)) {
|
||||
@ -799,6 +803,12 @@ static int job_transition_to_pending(Job *job)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void job_transition_to_ready(Job *job)
|
||||
{
|
||||
job_state_transition(job, JOB_STATUS_READY);
|
||||
job_event_ready(job);
|
||||
}
|
||||
|
||||
static void job_completed_txn_success(Job *job)
|
||||
{
|
||||
JobTxn *txn = job->txn;
|
||||
|
@ -505,7 +505,7 @@ static void coroutine_fn test_job_start(void *opaque)
|
||||
{
|
||||
TestBlockJob *s = opaque;
|
||||
|
||||
block_job_event_ready(&s->common);
|
||||
job_transition_to_ready(&s->common.job);
|
||||
while (!s->should_complete) {
|
||||
job_sleep_ns(&s->common.job, 100000);
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ static void coroutine_fn cancel_job_start(void *opaque)
|
||||
}
|
||||
|
||||
if (!job_is_ready(&s->common.job) && s->should_converge) {
|
||||
block_job_event_ready(&s->common);
|
||||
job_transition_to_ready(&s->common.job);
|
||||
}
|
||||
|
||||
job_sleep_ns(&s->common.job, 100000);
|
||||
|
Loading…
Reference in New Issue
Block a user