job: Add job_drain()
block_job_drain() contains a blk_drain() call which cannot be moved to Job, so add a new JobDriver callback JobDriver.drain which has a common implementation for all BlockJobs. In addition to this we keep the existing BlockJobDriver.drain callback that is called by the common drain implementation for all block jobs. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
		
							parent
							
								
									004e95df98
								
							
						
					
					
						commit
						b69f777dd9
					
				@ -529,6 +529,7 @@ static const BlockJobDriver backup_job_driver = {
 | 
			
		||||
        .job_type               = JOB_TYPE_BACKUP,
 | 
			
		||||
        .free                   = block_job_free,
 | 
			
		||||
        .user_resume            = block_job_user_resume,
 | 
			
		||||
        .drain                  = block_job_drain,
 | 
			
		||||
        .start                  = backup_run,
 | 
			
		||||
        .commit                 = backup_commit,
 | 
			
		||||
        .abort                  = backup_abort,
 | 
			
		||||
 | 
			
		||||
@ -221,6 +221,7 @@ static const BlockJobDriver commit_job_driver = {
 | 
			
		||||
        .job_type      = JOB_TYPE_COMMIT,
 | 
			
		||||
        .free          = block_job_free,
 | 
			
		||||
        .user_resume   = block_job_user_resume,
 | 
			
		||||
        .drain         = block_job_drain,
 | 
			
		||||
        .start         = commit_run,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -992,6 +992,7 @@ static const BlockJobDriver mirror_job_driver = {
 | 
			
		||||
        .job_type               = JOB_TYPE_MIRROR,
 | 
			
		||||
        .free                   = block_job_free,
 | 
			
		||||
        .user_resume            = block_job_user_resume,
 | 
			
		||||
        .drain                  = block_job_drain,
 | 
			
		||||
        .start                  = mirror_run,
 | 
			
		||||
        .pause                  = mirror_pause,
 | 
			
		||||
    },
 | 
			
		||||
@ -1006,6 +1007,7 @@ static const BlockJobDriver commit_active_job_driver = {
 | 
			
		||||
        .job_type               = JOB_TYPE_COMMIT,
 | 
			
		||||
        .free                   = block_job_free,
 | 
			
		||||
        .user_resume            = block_job_user_resume,
 | 
			
		||||
        .drain                  = block_job_drain,
 | 
			
		||||
        .start                  = mirror_run,
 | 
			
		||||
        .pause                  = mirror_pause,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@ -215,6 +215,7 @@ static const BlockJobDriver stream_job_driver = {
 | 
			
		||||
        .free          = block_job_free,
 | 
			
		||||
        .start         = stream_run,
 | 
			
		||||
        .user_resume   = block_job_user_resume,
 | 
			
		||||
        .drain         = block_job_drain,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								blockjob.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								blockjob.c
									
									
									
									
									
								
							@ -169,14 +169,13 @@ static void block_job_attached_aio_context(AioContext *new_context,
 | 
			
		||||
    job_resume(&job->job);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void block_job_drain(BlockJob *job)
 | 
			
		||||
void block_job_drain(Job *job)
 | 
			
		||||
{
 | 
			
		||||
    /* If job is !job->job.busy this kicks it into the next pause point. */
 | 
			
		||||
    block_job_enter(job);
 | 
			
		||||
    BlockJob *bjob = container_of(job, BlockJob, job);
 | 
			
		||||
 | 
			
		||||
    blk_drain(job->blk);
 | 
			
		||||
    if (job->driver->drain) {
 | 
			
		||||
        job->driver->drain(job);
 | 
			
		||||
    blk_drain(bjob->blk);
 | 
			
		||||
    if (bjob->driver->drain) {
 | 
			
		||||
        bjob->driver->drain(bjob);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -190,7 +189,7 @@ static void block_job_detach_aio_context(void *opaque)
 | 
			
		||||
    job_pause(&job->job);
 | 
			
		||||
 | 
			
		||||
    while (!job->job.paused && !job_is_completed(&job->job)) {
 | 
			
		||||
        block_job_drain(job);
 | 
			
		||||
        job_drain(&job->job);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    job->job.aio_context = NULL;
 | 
			
		||||
@ -327,11 +326,11 @@ static int block_job_finish_sync(BlockJob *job,
 | 
			
		||||
        job_unref(&job->job);
 | 
			
		||||
        return -EBUSY;
 | 
			
		||||
    }
 | 
			
		||||
    /* block_job_drain calls block_job_enter, and it should be enough to
 | 
			
		||||
     * induce progress until the job completes or moves to the main thread.
 | 
			
		||||
    /* job_drain calls job_enter, and it should be enough to induce progress
 | 
			
		||||
     * until the job completes or moves to the main thread.
 | 
			
		||||
    */
 | 
			
		||||
    while (!job->job.deferred_to_main_loop && !job_is_completed(&job->job)) {
 | 
			
		||||
        block_job_drain(job);
 | 
			
		||||
        job_drain(&job->job);
 | 
			
		||||
    }
 | 
			
		||||
    while (!job_is_completed(&job->job)) {
 | 
			
		||||
        aio_poll(qemu_get_aio_context(), true);
 | 
			
		||||
@ -713,6 +712,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);
 | 
			
		||||
    assert(job->job.driver->drain == &block_job_drain);
 | 
			
		||||
 | 
			
		||||
    job->driver        = driver;
 | 
			
		||||
    job->blk           = blk;
 | 
			
		||||
 | 
			
		||||
@ -65,6 +65,10 @@ struct BlockJobDriver {
 | 
			
		||||
     * If the callback is not NULL, it will be invoked when the job has to be
 | 
			
		||||
     * synchronously cancelled or completed; it should drain BlockDriverStates
 | 
			
		||||
     * as required to ensure progress.
 | 
			
		||||
     *
 | 
			
		||||
     * Block jobs must use the default implementation for job_driver.drain,
 | 
			
		||||
     * which will in turn call this callback after doing generic block job
 | 
			
		||||
     * stuff.
 | 
			
		||||
     */
 | 
			
		||||
    void (*drain)(BlockJob *job);
 | 
			
		||||
};
 | 
			
		||||
@ -111,6 +115,14 @@ void block_job_free(Job *job);
 | 
			
		||||
 */
 | 
			
		||||
void block_job_user_resume(Job *job);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * block_job_drain:
 | 
			
		||||
 * Callback to be used for JobDriver.drain in all block jobs. Drains the main
 | 
			
		||||
 * block node associated with the block jobs and calls BlockJobDriver.drain for
 | 
			
		||||
 * job-specific actions.
 | 
			
		||||
 */
 | 
			
		||||
void block_job_drain(Job *job);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * block_job_yield:
 | 
			
		||||
 * @job: The job that calls the function.
 | 
			
		||||
 | 
			
		||||
@ -167,6 +167,13 @@ struct JobDriver {
 | 
			
		||||
     */
 | 
			
		||||
    void (*user_resume)(Job *job);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * If the callback is not NULL, it will be invoked when the job has to be
 | 
			
		||||
     * synchronously cancelled or completed; it should drain any activities
 | 
			
		||||
     * as required to ensure progress.
 | 
			
		||||
     */
 | 
			
		||||
    void (*drain)(Job *job);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * If the callback is not NULL, it will be invoked when all the jobs
 | 
			
		||||
     * belonging to the same transaction complete; or upon this job's
 | 
			
		||||
@ -325,6 +332,12 @@ bool job_user_paused(Job *job);
 | 
			
		||||
 */
 | 
			
		||||
void job_user_resume(Job *job, Error **errp);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Drain any activities as required to ensure progress. This can be called in a
 | 
			
		||||
 * loop to synchronously complete a job.
 | 
			
		||||
 */
 | 
			
		||||
void job_drain(Job *job);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get the next element from the list of block jobs after @job, or the
 | 
			
		||||
 * first one if @job is %NULL.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								job.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								job.c
									
									
									
									
									
								
							@ -367,6 +367,17 @@ void coroutine_fn job_sleep_ns(Job *job, int64_t ns)
 | 
			
		||||
    job_pause_point(job);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void job_drain(Job *job)
 | 
			
		||||
{
 | 
			
		||||
    /* If job is !busy this kicks it into the next pause point. */
 | 
			
		||||
    job_enter(job);
 | 
			
		||||
 | 
			
		||||
    if (job->driver->drain) {
 | 
			
		||||
        job->driver->drain(job);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * All jobs must allow a pause point before entering their job proper. This
 | 
			
		||||
 * ensures that jobs can be paused prior to being started, then resumed later.
 | 
			
		||||
 | 
			
		||||
@ -525,6 +525,7 @@ BlockJobDriver test_job_driver = {
 | 
			
		||||
        .instance_size  = sizeof(TestBlockJob),
 | 
			
		||||
        .free           = block_job_free,
 | 
			
		||||
        .user_resume    = block_job_user_resume,
 | 
			
		||||
        .drain          = block_job_drain,
 | 
			
		||||
        .start          = test_job_start,
 | 
			
		||||
    },
 | 
			
		||||
    .complete       = test_job_complete,
 | 
			
		||||
 | 
			
		||||
@ -79,6 +79,7 @@ static const BlockJobDriver test_block_job_driver = {
 | 
			
		||||
        .instance_size = sizeof(TestBlockJob),
 | 
			
		||||
        .free          = block_job_free,
 | 
			
		||||
        .user_resume   = block_job_user_resume,
 | 
			
		||||
        .drain         = block_job_drain,
 | 
			
		||||
        .start         = test_block_job_run,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,7 @@ static const BlockJobDriver test_block_job_driver = {
 | 
			
		||||
        .instance_size = sizeof(BlockJob),
 | 
			
		||||
        .free          = block_job_free,
 | 
			
		||||
        .user_resume   = block_job_user_resume,
 | 
			
		||||
        .drain         = block_job_drain,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -201,6 +202,7 @@ static const BlockJobDriver test_cancel_driver = {
 | 
			
		||||
        .instance_size = sizeof(CancelJob),
 | 
			
		||||
        .free          = block_job_free,
 | 
			
		||||
        .user_resume   = block_job_user_resume,
 | 
			
		||||
        .drain         = block_job_drain,
 | 
			
		||||
        .start         = cancel_job_start,
 | 
			
		||||
    },
 | 
			
		||||
    .complete      = cancel_job_complete,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user