Skip to content

Commit

Permalink
job: Move pause/resume functions to Job
Browse files Browse the repository at this point in the history
While we already moved the state related to job pausing to Job, the
functions to do were still BlockJob only. This commit moves them over to
Job.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
  • Loading branch information
kevmw committed May 23, 2018
1 parent 5d43e86 commit b15de82
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 102 deletions.
1 change: 1 addition & 0 deletions block/backup.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ static const BlockJobDriver backup_job_driver = {
.instance_size = sizeof(BackupBlockJob),
.job_type = JOB_TYPE_BACKUP,
.free = block_job_free,
.user_resume = block_job_user_resume,
.start = backup_run,
},
.commit = backup_commit,
Expand Down
1 change: 1 addition & 0 deletions block/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ static const BlockJobDriver commit_job_driver = {
.instance_size = sizeof(CommitBlockJob),
.job_type = JOB_TYPE_COMMIT,
.free = block_job_free,
.user_resume = block_job_user_resume,
.start = commit_run,
},
};
Expand Down
2 changes: 2 additions & 0 deletions block/mirror.c
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,7 @@ static const BlockJobDriver mirror_job_driver = {
.instance_size = sizeof(MirrorBlockJob),
.job_type = JOB_TYPE_MIRROR,
.free = block_job_free,
.user_resume = block_job_user_resume,
.start = mirror_run,
.pause = mirror_pause,
},
Expand All @@ -1004,6 +1005,7 @@ static const BlockJobDriver commit_active_job_driver = {
.instance_size = sizeof(MirrorBlockJob),
.job_type = JOB_TYPE_COMMIT,
.free = block_job_free,
.user_resume = block_job_user_resume,
.start = mirror_run,
.pause = mirror_pause,
},
Expand Down
1 change: 1 addition & 0 deletions block/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ static const BlockJobDriver stream_job_driver = {
.job_type = JOB_TYPE_STREAM,
.free = block_job_free,
.start = stream_run,
.user_resume = block_job_user_resume,
},
};

Expand Down
6 changes: 3 additions & 3 deletions blockdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -3844,7 +3844,7 @@ void qmp_block_job_cancel(const char *device,
force = false;
}

if (block_job_user_paused(job) && !force) {
if (job_user_paused(&job->job) && !force) {
error_setg(errp, "The block job for device '%s' is currently paused",
device);
goto out;
Expand All @@ -3866,7 +3866,7 @@ void qmp_block_job_pause(const char *device, Error **errp)
}

trace_qmp_block_job_pause(job);
block_job_user_pause(job, errp);
job_user_pause(&job->job, errp);
aio_context_release(aio_context);
}

Expand All @@ -3880,7 +3880,7 @@ void qmp_block_job_resume(const char *device, Error **errp)
}

trace_qmp_block_job_resume(job);
block_job_user_resume(job, errp);
job_user_resume(&job->job, errp);
aio_context_release(aio_context);
}

Expand Down
81 changes: 16 additions & 65 deletions blockjob.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,29 +140,6 @@ static void block_job_txn_del_job(BlockJob *job)
}
}

/* Assumes the job_mutex is held */
static bool job_timer_not_pending(Job *job)
{
return !timer_pending(&job->sleep_timer);
}

static void block_job_pause(BlockJob *job)
{
job->job.pause_count++;
}

static void block_job_resume(BlockJob *job)
{
assert(job->job.pause_count > 0);
job->job.pause_count--;
if (job->job.pause_count) {
return;
}

/* kick only if no timer is pending */
job_enter_cond(&job->job, job_timer_not_pending);
}

static void block_job_attached_aio_context(AioContext *new_context,
void *opaque);
static void block_job_detach_aio_context(void *opaque);
Expand Down Expand Up @@ -193,7 +170,7 @@ static void block_job_attached_aio_context(AioContext *new_context,
job->driver->attached_aio_context(job, new_context);
}

block_job_resume(job);
job_resume(&job->job);
}

static void block_job_drain(BlockJob *job)
Expand All @@ -214,7 +191,7 @@ static void block_job_detach_aio_context(void *opaque)
/* In case the job terminates during aio_poll()... */
job_ref(&job->job);

block_job_pause(job);
job_pause(&job->job);

while (!job->job.paused && !job->completed) {
block_job_drain(job);
Expand All @@ -233,13 +210,13 @@ static char *child_job_get_parent_desc(BdrvChild *c)
static void child_job_drained_begin(BdrvChild *c)
{
BlockJob *job = c->opaque;
block_job_pause(job);
job_pause(&job->job);
}

static void child_job_drained_end(BdrvChild *c)
{
BlockJob *job = c->opaque;
block_job_resume(job);
job_resume(&job->job);
}

static const BdrvChildRole child_job = {
Expand Down Expand Up @@ -396,9 +373,9 @@ static void block_job_cancel_async(BlockJob *job, bool force)
if (job->iostatus != BLOCK_DEVICE_IO_STATUS_OK) {
block_job_iostatus_reset(job);
}
if (job->user_paused) {
if (job->job.user_paused) {
/* Do not call block_job_enter here, the caller will handle it. */
job->user_paused = false;
job->job.user_paused = false;
job->job.pause_count--;
}
job->job.cancelled = true;
Expand Down Expand Up @@ -628,39 +605,6 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp)
*jobptr = NULL;
}

void block_job_user_pause(BlockJob *job, Error **errp)
{
if (job_apply_verb(&job->job, JOB_VERB_PAUSE, errp)) {
return;
}
if (job->user_paused) {
error_setg(errp, "Job is already paused");
return;
}
job->user_paused = true;
block_job_pause(job);
}

bool block_job_user_paused(BlockJob *job)
{
return job->user_paused;
}

void block_job_user_resume(BlockJob *job, Error **errp)
{
assert(job);
if (!job->user_paused || job->job.pause_count <= 0) {
error_setg(errp, "Can't resume a job that was not paused");
return;
}
if (job_apply_verb(&job->job, JOB_VERB_RESUME, errp)) {
return;
}
block_job_iostatus_reset(job);
job->user_paused = false;
block_job_resume(job);
}

void block_job_cancel(BlockJob *job, bool force)
{
if (job->job.status == JOB_STATUS_CONCLUDED) {
Expand Down Expand Up @@ -851,6 +795,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,

assert(is_block_job(&job->job));
assert(job->job.driver->free == &block_job_free);
assert(job->job.driver->user_resume == &block_job_user_resume);

job->driver = driver;
job->blk = blk;
Expand Down Expand Up @@ -941,10 +886,16 @@ void block_job_iostatus_reset(BlockJob *job)
if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
return;
}
assert(job->user_paused && job->job.pause_count > 0);
assert(job->job.user_paused && job->job.pause_count > 0);
job->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
}

void block_job_user_resume(Job *job)
{
BlockJob *bjob = container_of(job, BlockJob, job);
block_job_iostatus_reset(bjob);
}

void block_job_event_ready(BlockJob *job)
{
job_state_transition(&job->job, JOB_STATUS_READY);
Expand Down Expand Up @@ -991,9 +942,9 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
action, &error_abort);
}
if (action == BLOCK_ERROR_ACTION_STOP) {
block_job_pause(job);
job_pause(&job->job);
/* make the pause user visible, which will be resumed from QMP. */
job->user_paused = true;
job->job.user_paused = true;
block_job_iostatus_set_err(job, error);
}
return action;
Expand Down
32 changes: 0 additions & 32 deletions include/block/blockjob.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,6 @@ typedef struct BlockJob {
*/
bool force;

/**
* Set to true if the job is paused by user. Can be unpaused with the
* block-job-resume QMP command.
*/
bool user_paused;

/**
* Set to true when the job is ready to be completed.
*/
Expand Down Expand Up @@ -247,32 +241,6 @@ void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining);
*/
BlockJobInfo *block_job_query(BlockJob *job, Error **errp);

/**
* block_job_user_pause:
* @job: The job to be paused.
*
* Asynchronously pause the specified job.
* Do not allow a resume until a matching call to block_job_user_resume.
*/
void block_job_user_pause(BlockJob *job, Error **errp);

/**
* block_job_paused:
* @job: The job to query.
*
* Returns true if the job is user-paused.
*/
bool block_job_user_paused(BlockJob *job);

/**
* block_job_user_resume:
* @job: The job to be resumed.
*
* Resume the specified job.
* Must be paired with a preceding block_job_user_pause.
*/
void block_job_user_resume(BlockJob *job, Error **errp);

/**
* block_job_user_cancel:
* @job: The job to be cancelled.
Expand Down
7 changes: 7 additions & 0 deletions include/block/blockjob_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
*/
void block_job_free(Job *job);

/**
* block_job_user_resume:
* Callback to be used for JobDriver.user_resume in all block jobs. Resets the
* iostatus when the user resumes @job.
*/
void block_job_user_resume(Job *job);

/**
* block_job_yield:
* @job: The job that calls the function.
Expand Down
37 changes: 37 additions & 0 deletions include/qemu/job.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ typedef struct Job {
*/
bool paused;

/**
* Set to true if the job is paused by user. Can be unpaused with the
* block-job-resume QMP command.
*/
bool user_paused;

/**
* Set to true if the job should cancel itself. The flag must
* always be tested just before toggling the busy flag from false
Expand Down Expand Up @@ -124,6 +130,12 @@ struct JobDriver {
*/
void coroutine_fn (*resume)(Job *job);

/**
* Called when the job is resumed by the user (i.e. user_paused becomes
* false). .user_resume is called before .resume.
*/
void (*user_resume)(Job *job);

/** Called when the job is freed */
void (*free)(Job *job);
};
Expand Down Expand Up @@ -202,6 +214,31 @@ const char *job_type_str(const Job *job);
/** Returns whether the job is scheduled for cancellation. */
bool job_is_cancelled(Job *job);

/**
* Request @job to pause at the next pause point. Must be paired with
* job_resume(). If the job is supposed to be resumed by user action, call
* job_user_pause() instead.
*/
void job_pause(Job *job);

/** Resumes a @job paused with job_pause. */
void job_resume(Job *job);

/**
* Asynchronously pause the specified @job.
* Do not allow a resume until a matching call to job_user_resume.
*/
void job_user_pause(Job *job, Error **errp);

/** Returns true if the job is user-paused. */
bool job_user_paused(Job *job);

/**
* Resume the specified @job.
* Must be paired with a preceding job_user_pause.
*/
void job_user_resume(Job *job, Error **errp);

/**
* Get the next element from the list of block jobs after @job, or the
* first one if @job is %NULL.
Expand Down
Loading

0 comments on commit b15de82

Please sign in to comment.