block: Introduce op_blockers to BlockDriverState
BlockDriverState.op_blockers is an array of lists with BLOCK_OP_TYPE_MAX
elements. Each list is a list of blockers of an operation type
(BlockOpType), that marks this BDS as currently blocked for a certain
type of operation with reason errors stored in the list. The rule of
usage is:
 * BDS user who wants to take an operation should check if there's any
   blocker of the type with bdrv_op_is_blocked().
 * BDS user who wants to block certain types of operation, should call
   bdrv_op_block (or bdrv_op_block_all to block all types of operations,
   which is similar to the existing bdrv_set_in_use()).
 * A blocker is only referenced by op_blockers, so the lifecycle is
   managed by caller, and shouldn't be lost until unblock, so typically
   a caller does these:
   - Allocate a blocker with error_setg or similar, call bdrv_op_block()
     to block some operations.
   - Hold the blocker, do his job.
   - Unblock operations that it blocked, with the same reason pointer
     passed to bdrv_op_unblock().
   - Release the blocker with error_free().
Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Benoit Canet <benoit@irqsave.net>
Reviewed-by: Jeff Cody <jcody@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
			
			
This commit is contained in:
		
							parent
							
								
									8574575f90
								
							
						
					
					
						commit
						fbe40ff780
					
				
							
								
								
									
										76
									
								
								block.c
								
								
								
								
							
							
						
						
									
										76
									
								
								block.c
								
								
								
								
							| 
						 | 
					@ -335,6 +335,7 @@ void bdrv_register(BlockDriver *bdrv)
 | 
				
			||||||
BlockDriverState *bdrv_new(const char *device_name, Error **errp)
 | 
					BlockDriverState *bdrv_new(const char *device_name, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlockDriverState *bs;
 | 
					    BlockDriverState *bs;
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bdrv_find(device_name)) {
 | 
					    if (bdrv_find(device_name)) {
 | 
				
			||||||
        error_setg(errp, "Device with id '%s' already exists",
 | 
					        error_setg(errp, "Device with id '%s' already exists",
 | 
				
			||||||
| 
						 | 
					@ -353,6 +354,9 @@ BlockDriverState *bdrv_new(const char *device_name, Error **errp)
 | 
				
			||||||
    if (device_name[0] != '\0') {
 | 
					    if (device_name[0] != '\0') {
 | 
				
			||||||
        QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
 | 
					        QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
 | 
				
			||||||
 | 
					        QLIST_INIT(&bs->op_blockers[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    bdrv_iostatus_disable(bs);
 | 
					    bdrv_iostatus_disable(bs);
 | 
				
			||||||
    notifier_list_init(&bs->close_notifiers);
 | 
					    notifier_list_init(&bs->close_notifiers);
 | 
				
			||||||
    notifier_with_return_list_init(&bs->before_write_notifiers);
 | 
					    notifier_with_return_list_init(&bs->before_write_notifiers);
 | 
				
			||||||
| 
						 | 
					@ -1952,6 +1956,8 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
 | 
				
			||||||
    pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
 | 
					    pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
 | 
				
			||||||
            bs_src->device_name);
 | 
					            bs_src->device_name);
 | 
				
			||||||
    bs_dest->device_list = bs_src->device_list;
 | 
					    bs_dest->device_list = bs_src->device_list;
 | 
				
			||||||
 | 
					    memcpy(bs_dest->op_blockers, bs_src->op_blockers,
 | 
				
			||||||
 | 
					           sizeof(bs_dest->op_blockers));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -5325,6 +5331,76 @@ void bdrv_unref(BlockDriverState *bs)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct BdrvOpBlocker {
 | 
				
			||||||
 | 
					    Error *reason;
 | 
				
			||||||
 | 
					    QLIST_ENTRY(BdrvOpBlocker) list;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BdrvOpBlocker *blocker;
 | 
				
			||||||
 | 
					    assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
 | 
				
			||||||
 | 
					    if (!QLIST_EMPTY(&bs->op_blockers[op])) {
 | 
				
			||||||
 | 
					        blocker = QLIST_FIRST(&bs->op_blockers[op]);
 | 
				
			||||||
 | 
					        if (errp) {
 | 
				
			||||||
 | 
					            error_setg(errp, "Device '%s' is busy: %s",
 | 
				
			||||||
 | 
					                       bs->device_name, error_get_pretty(blocker->reason));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BdrvOpBlocker *blocker;
 | 
				
			||||||
 | 
					    assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    blocker = g_malloc0(sizeof(BdrvOpBlocker));
 | 
				
			||||||
 | 
					    blocker->reason = reason;
 | 
				
			||||||
 | 
					    QLIST_INSERT_HEAD(&bs->op_blockers[op], blocker, list);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BdrvOpBlocker *blocker, *next;
 | 
				
			||||||
 | 
					    assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
 | 
				
			||||||
 | 
					    QLIST_FOREACH_SAFE(blocker, &bs->op_blockers[op], list, next) {
 | 
				
			||||||
 | 
					        if (blocker->reason == reason) {
 | 
				
			||||||
 | 
					            QLIST_REMOVE(blocker, list);
 | 
				
			||||||
 | 
					            g_free(blocker);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void bdrv_op_block_all(BlockDriverState *bs, Error *reason)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
 | 
				
			||||||
 | 
					        bdrv_op_block(bs, i, reason);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
 | 
				
			||||||
 | 
					        bdrv_op_unblock(bs, i, reason);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool bdrv_op_blocker_is_empty(BlockDriverState *bs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
 | 
				
			||||||
 | 
					        if (!QLIST_EMPTY(&bs->op_blockers[i])) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void bdrv_set_in_use(BlockDriverState *bs, int in_use)
 | 
					void bdrv_set_in_use(BlockDriverState *bs, int in_use)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    assert(bs->in_use != in_use);
 | 
					    assert(bs->in_use != in_use);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -475,6 +475,13 @@ void bdrv_unref(BlockDriverState *bs);
 | 
				
			||||||
void bdrv_set_in_use(BlockDriverState *bs, int in_use);
 | 
					void bdrv_set_in_use(BlockDriverState *bs, int in_use);
 | 
				
			||||||
int bdrv_in_use(BlockDriverState *bs);
 | 
					int bdrv_in_use(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
 | 
				
			||||||
 | 
					void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
 | 
				
			||||||
 | 
					void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason);
 | 
				
			||||||
 | 
					void bdrv_op_block_all(BlockDriverState *bs, Error *reason);
 | 
				
			||||||
 | 
					void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason);
 | 
				
			||||||
 | 
					bool bdrv_op_blocker_is_empty(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_LINUX_AIO
 | 
					#ifdef CONFIG_LINUX_AIO
 | 
				
			||||||
int raw_get_aio_fd(BlockDriverState *bs);
 | 
					int raw_get_aio_fd(BlockDriverState *bs);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -270,6 +270,8 @@ typedef struct BlockLimits {
 | 
				
			||||||
    size_t opt_mem_alignment;
 | 
					    size_t opt_mem_alignment;
 | 
				
			||||||
} BlockLimits;
 | 
					} BlockLimits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct BdrvOpBlocker BdrvOpBlocker;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Note: the function bdrv_append() copies and swaps contents of
 | 
					 * Note: the function bdrv_append() copies and swaps contents of
 | 
				
			||||||
 * BlockDriverStates, so if you add new fields to this struct, please
 | 
					 * BlockDriverStates, so if you add new fields to this struct, please
 | 
				
			||||||
| 
						 | 
					@ -360,6 +362,9 @@ struct BlockDriverState {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
 | 
					    QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* operation blockers */
 | 
				
			||||||
 | 
					    QLIST_HEAD(, BdrvOpBlocker) op_blockers[BLOCK_OP_TYPE_MAX];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* long-running background operation */
 | 
					    /* long-running background operation */
 | 
				
			||||||
    BlockJob *job;
 | 
					    BlockJob *job;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue