blockjob: add block_job_defer_to_main_loop()
Block jobs will run in the BlockDriverState's AioContext, which may not always be the QEMU main loop. There are some block layer APIs that are either not thread-safe or risk lock ordering problems. This includes bdrv_unref(), bdrv_close(), and anything that calls bdrv_drain_all(). The block_job_defer_to_main_loop() API allows a block job to schedule a function to run in the main loop with the BlockDriverState AioContext held. This function will be used to perform cleanup and backing chain manipulations in block jobs. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-id: 1413889440-32577-6-git-send-email-stefanha@redhat.com
This commit is contained in:
		
							parent
							
								
									723c5d93c5
								
							
						
					
					
						commit
						dec7d421f8
					
				
							
								
								
									
										45
									
								
								blockjob.c
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								blockjob.c
									
									
									
									
									
								
							@ -342,3 +342,48 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return action;
 | 
					    return action;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    BlockJob *job;
 | 
				
			||||||
 | 
					    QEMUBH *bh;
 | 
				
			||||||
 | 
					    AioContext *aio_context;
 | 
				
			||||||
 | 
					    BlockJobDeferToMainLoopFn *fn;
 | 
				
			||||||
 | 
					    void *opaque;
 | 
				
			||||||
 | 
					} BlockJobDeferToMainLoopData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void block_job_defer_to_main_loop_bh(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BlockJobDeferToMainLoopData *data = opaque;
 | 
				
			||||||
 | 
					    AioContext *aio_context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_bh_delete(data->bh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Prevent race with block_job_defer_to_main_loop() */
 | 
				
			||||||
 | 
					    aio_context_acquire(data->aio_context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Fetch BDS AioContext again, in case it has changed */
 | 
				
			||||||
 | 
					    aio_context = bdrv_get_aio_context(data->job->bs);
 | 
				
			||||||
 | 
					    aio_context_acquire(aio_context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data->fn(data->job, data->opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    aio_context_release(aio_context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    aio_context_release(data->aio_context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_free(data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void block_job_defer_to_main_loop(BlockJob *job,
 | 
				
			||||||
 | 
					                                  BlockJobDeferToMainLoopFn *fn,
 | 
				
			||||||
 | 
					                                  void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data));
 | 
				
			||||||
 | 
					    data->job = job;
 | 
				
			||||||
 | 
					    data->bh = qemu_bh_new(block_job_defer_to_main_loop_bh, data);
 | 
				
			||||||
 | 
					    data->aio_context = bdrv_get_aio_context(job->bs);
 | 
				
			||||||
 | 
					    data->fn = fn;
 | 
				
			||||||
 | 
					    data->opaque = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_bh_schedule(data->bh);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -315,4 +315,23 @@ void block_job_iostatus_reset(BlockJob *job);
 | 
				
			|||||||
BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
 | 
					BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
 | 
				
			||||||
                                        BlockdevOnError on_err,
 | 
					                                        BlockdevOnError on_err,
 | 
				
			||||||
                                        int is_read, int error);
 | 
					                                        int is_read, int error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef void BlockJobDeferToMainLoopFn(BlockJob *job, void *opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * block_job_defer_to_main_loop:
 | 
				
			||||||
 | 
					 * @job: The job
 | 
				
			||||||
 | 
					 * @fn: The function to run in the main loop
 | 
				
			||||||
 | 
					 * @opaque: The opaque value that is passed to @fn
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Execute a given function in the main loop with the BlockDriverState
 | 
				
			||||||
 | 
					 * AioContext acquired.  Block jobs must call bdrv_unref(), bdrv_close(), and
 | 
				
			||||||
 | 
					 * anything that uses bdrv_drain_all() in the main loop.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The @job AioContext is held while @fn executes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void block_job_defer_to_main_loop(BlockJob *job,
 | 
				
			||||||
 | 
					                                  BlockJobDeferToMainLoopFn *fn,
 | 
				
			||||||
 | 
					                                  void *opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user