mirror of https://github.com/xemu-project/xemu.git
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