job: Maintain a list of all jobs
This moves the job list from BlockJob to Job. Now we can check for duplicate IDs in job_create(). Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Reviewed-by: John Snow <jsnow@redhat.com>
This commit is contained in:
		
							parent
							
								
									fd61a701f1
								
							
						
					
					
						commit
						e7c1d78bbd
					
				
							
								
								
									
										46
									
								
								blockjob.c
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								blockjob.c
									
									
									
									
									
								
							| @ -129,8 +129,6 @@ struct BlockJobTxn { | |||||||
|     int refcnt; |     int refcnt; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static QLIST_HEAD(, BlockJob) block_jobs = QLIST_HEAD_INITIALIZER(block_jobs); |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  * The block job API is composed of two categories of functions. |  * The block job API is composed of two categories of functions. | ||||||
|  * |  * | ||||||
| @ -146,25 +144,34 @@ static QLIST_HEAD(, BlockJob) block_jobs = QLIST_HEAD_INITIALIZER(block_jobs); | |||||||
|  * blockjob_int.h. |  * blockjob_int.h. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| BlockJob *block_job_next(BlockJob *job) | static bool is_block_job(Job *job) | ||||||
| { | { | ||||||
|     if (!job) { |     return job_type(job) == JOB_TYPE_BACKUP || | ||||||
|         return QLIST_FIRST(&block_jobs); |            job_type(job) == JOB_TYPE_COMMIT || | ||||||
|     } |            job_type(job) == JOB_TYPE_MIRROR || | ||||||
|     return QLIST_NEXT(job, job_list); |            job_type(job) == JOB_TYPE_STREAM; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BlockJob *block_job_next(BlockJob *bjob) | ||||||
|  | { | ||||||
|  |     Job *job = bjob ? &bjob->job : NULL; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         job = job_next(job); | ||||||
|  |     } while (job && !is_block_job(job)); | ||||||
|  | 
 | ||||||
|  |     return job ? container_of(job, BlockJob, job) : NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BlockJob *block_job_get(const char *id) | BlockJob *block_job_get(const char *id) | ||||||
| { | { | ||||||
|     BlockJob *job; |     Job *job = job_get(id); | ||||||
| 
 | 
 | ||||||
|     QLIST_FOREACH(job, &block_jobs, job_list) { |     if (job && is_block_job(job)) { | ||||||
|         if (job->job.id && !strcmp(id, job->job.id)) { |         return container_of(job, BlockJob, job); | ||||||
|             return job; |     } else { | ||||||
|         } |         return NULL; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     return NULL; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BlockJobTxn *block_job_txn_new(void) | BlockJobTxn *block_job_txn_new(void) | ||||||
| @ -253,7 +260,6 @@ void block_job_unref(BlockJob *job) | |||||||
|         assert(job->status == BLOCK_JOB_STATUS_NULL); |         assert(job->status == BLOCK_JOB_STATUS_NULL); | ||||||
|         assert(!job->txn); |         assert(!job->txn); | ||||||
|         BlockDriverState *bs = blk_bs(job->blk); |         BlockDriverState *bs = blk_bs(job->blk); | ||||||
|         QLIST_REMOVE(job, job_list); |  | ||||||
|         bs->job = NULL; |         bs->job = NULL; | ||||||
|         block_job_remove_all_bdrv(job); |         block_job_remove_all_bdrv(job); | ||||||
|         blk_remove_aio_context_notifier(job->blk, |         blk_remove_aio_context_notifier(job->blk, | ||||||
| @ -812,7 +818,7 @@ void block_job_cancel_sync_all(void) | |||||||
|     BlockJob *job; |     BlockJob *job; | ||||||
|     AioContext *aio_context; |     AioContext *aio_context; | ||||||
| 
 | 
 | ||||||
|     while ((job = QLIST_FIRST(&block_jobs))) { |     while ((job = block_job_next(NULL))) { | ||||||
|         aio_context = blk_get_aio_context(job->blk); |         aio_context = blk_get_aio_context(job->blk); | ||||||
|         aio_context_acquire(aio_context); |         aio_context_acquire(aio_context); | ||||||
|         block_job_cancel_sync(job); |         block_job_cancel_sync(job); | ||||||
| @ -942,10 +948,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, | |||||||
|             error_setg(errp, "Cannot specify job ID for internal block job"); |             error_setg(errp, "Cannot specify job ID for internal block job"); | ||||||
|             return NULL; |             return NULL; | ||||||
|         } |         } | ||||||
|         if (block_job_get(job_id)) { |  | ||||||
|             error_setg(errp, "Job ID '%s' already in use", job_id); |  | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     blk = blk_new(perm, shared_perm); |     blk = blk_new(perm, shared_perm); | ||||||
| @ -961,6 +963,8 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, | |||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     assert(is_block_job(&job->job)); | ||||||
|  | 
 | ||||||
|     job->driver        = driver; |     job->driver        = driver; | ||||||
|     job->blk           = blk; |     job->blk           = blk; | ||||||
|     job->cb            = cb; |     job->cb            = cb; | ||||||
| @ -983,8 +987,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, | |||||||
| 
 | 
 | ||||||
|     bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker); |     bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker); | ||||||
| 
 | 
 | ||||||
|     QLIST_INSERT_HEAD(&block_jobs, job, job_list); |  | ||||||
| 
 |  | ||||||
|     blk_add_aio_context_notifier(blk, block_job_attached_aio_context, |     blk_add_aio_context_notifier(blk, block_job_attached_aio_context, | ||||||
|                                  block_job_detach_aio_context, job); |                                  block_job_detach_aio_context, job); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -105,9 +105,6 @@ typedef struct BlockJob { | |||||||
|      */ |      */ | ||||||
|     bool deferred_to_main_loop; |     bool deferred_to_main_loop; | ||||||
| 
 | 
 | ||||||
|     /** Element of the list of block jobs */ |  | ||||||
|     QLIST_ENTRY(BlockJob) job_list; |  | ||||||
| 
 |  | ||||||
|     /** Status that is published by the query-block-jobs QMP API */ |     /** Status that is published by the query-block-jobs QMP API */ | ||||||
|     BlockDeviceIoStatus iostatus; |     BlockDeviceIoStatus iostatus; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -27,6 +27,7 @@ | |||||||
| #define JOB_H | #define JOB_H | ||||||
| 
 | 
 | ||||||
| #include "qapi/qapi-types-block-core.h" | #include "qapi/qapi-types-block-core.h" | ||||||
|  | #include "qemu/queue.h" | ||||||
| 
 | 
 | ||||||
| typedef struct JobDriver JobDriver; | typedef struct JobDriver JobDriver; | ||||||
| 
 | 
 | ||||||
| @ -39,6 +40,9 @@ typedef struct Job { | |||||||
| 
 | 
 | ||||||
|     /** The type of this job. */ |     /** The type of this job. */ | ||||||
|     const JobDriver *driver; |     const JobDriver *driver; | ||||||
|  | 
 | ||||||
|  |     /** Element of the list of jobs */ | ||||||
|  |     QLIST_ENTRY(Job) job_list; | ||||||
| } Job; | } Job; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -71,4 +75,19 @@ JobType job_type(const Job *job); | |||||||
| /** Returns the enum string for the JobType of a given Job. */ | /** Returns the enum string for the JobType of a given Job. */ | ||||||
| const char *job_type_str(const Job *job); | const char *job_type_str(const Job *job); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Get the next element from the list of block jobs after @job, or the | ||||||
|  |  * first one if @job is %NULL. | ||||||
|  |  * | ||||||
|  |  * Returns the requested job, or %NULL if there are no more jobs left. | ||||||
|  |  */ | ||||||
|  | Job *job_next(Job *job); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Get the job identified by @id (which must not be %NULL). | ||||||
|  |  * | ||||||
|  |  * Returns the requested job, or %NULL if it doesn't exist. | ||||||
|  |  */ | ||||||
|  | Job *job_get(const char *id); | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
							
								
								
									
										31
									
								
								job.c
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								job.c
									
									
									
									
									
								
							| @ -29,6 +29,8 @@ | |||||||
| #include "qemu/job.h" | #include "qemu/job.h" | ||||||
| #include "qemu/id.h" | #include "qemu/id.h" | ||||||
| 
 | 
 | ||||||
|  | static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs); | ||||||
|  | 
 | ||||||
| JobType job_type(const Job *job) | JobType job_type(const Job *job) | ||||||
| { | { | ||||||
|     return job->driver->job_type; |     return job->driver->job_type; | ||||||
| @ -39,6 +41,27 @@ const char *job_type_str(const Job *job) | |||||||
|     return JobType_str(job_type(job)); |     return JobType_str(job_type(job)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Job *job_next(Job *job) | ||||||
|  | { | ||||||
|  |     if (!job) { | ||||||
|  |         return QLIST_FIRST(&jobs); | ||||||
|  |     } | ||||||
|  |     return QLIST_NEXT(job, job_list); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Job *job_get(const char *id) | ||||||
|  | { | ||||||
|  |     Job *job; | ||||||
|  | 
 | ||||||
|  |     QLIST_FOREACH(job, &jobs, job_list) { | ||||||
|  |         if (job->id && !strcmp(id, job->id)) { | ||||||
|  |             return job; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void *job_create(const char *job_id, const JobDriver *driver, Error **errp) | void *job_create(const char *job_id, const JobDriver *driver, Error **errp) | ||||||
| { | { | ||||||
|     Job *job; |     Job *job; | ||||||
| @ -48,17 +71,25 @@ void *job_create(const char *job_id, const JobDriver *driver, Error **errp) | |||||||
|             error_setg(errp, "Invalid job ID '%s'", job_id); |             error_setg(errp, "Invalid job ID '%s'", job_id); | ||||||
|             return NULL; |             return NULL; | ||||||
|         } |         } | ||||||
|  |         if (job_get(job_id)) { | ||||||
|  |             error_setg(errp, "Job ID '%s' already in use", job_id); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     job = g_malloc0(driver->instance_size); |     job = g_malloc0(driver->instance_size); | ||||||
|     job->driver        = driver; |     job->driver        = driver; | ||||||
|     job->id            = g_strdup(job_id); |     job->id            = g_strdup(job_id); | ||||||
| 
 | 
 | ||||||
|  |     QLIST_INSERT_HEAD(&jobs, job, job_list); | ||||||
|  | 
 | ||||||
|     return job; |     return job; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void job_delete(Job *job) | void job_delete(Job *job) | ||||||
| { | { | ||||||
|  |     QLIST_REMOVE(job, job_list); | ||||||
|  | 
 | ||||||
|     g_free(job->id); |     g_free(job->id); | ||||||
|     g_free(job); |     g_free(job); | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Kevin Wolf
						Kevin Wolf