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 *bs;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    if (bdrv_find(device_name)) {
 | 
			
		||||
        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') {
 | 
			
		||||
        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);
 | 
			
		||||
    notifier_list_init(&bs->close_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),
 | 
			
		||||
            bs_src->device_name);
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    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);
 | 
			
		||||
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
 | 
			
		||||
int raw_get_aio_fd(BlockDriverState *bs);
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -270,6 +270,8 @@ typedef struct BlockLimits {
 | 
			
		|||
    size_t opt_mem_alignment;
 | 
			
		||||
} BlockLimits;
 | 
			
		||||
 | 
			
		||||
typedef struct BdrvOpBlocker BdrvOpBlocker;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Note: the function bdrv_append() copies and swaps contents of
 | 
			
		||||
 * BlockDriverStates, so if you add new fields to this struct, please
 | 
			
		||||
| 
						 | 
				
			
			@ -360,6 +362,9 @@ struct BlockDriverState {
 | 
			
		|||
 | 
			
		||||
    QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
 | 
			
		||||
 | 
			
		||||
    /* operation blockers */
 | 
			
		||||
    QLIST_HEAD(, BdrvOpBlocker) op_blockers[BLOCK_OP_TYPE_MAX];
 | 
			
		||||
 | 
			
		||||
    /* long-running background operation */
 | 
			
		||||
    BlockJob *job;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue