mirror of
https://github.com/qemu/qemu.git
synced 2024-11-23 10:53:37 +08:00
block: Create authorizations mechanism for external snapshot and resize.
Signed-off-by: Benoit Canet <benoit@irqsave.net> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
12d3ba821d
commit
212a5a8f09
65
block.c
65
block.c
@ -5094,21 +5094,68 @@ int bdrv_amend_options(BlockDriverState *bs, QEMUOptionParameter *options)
|
||||
return bs->drv->bdrv_amend_options(bs, options);
|
||||
}
|
||||
|
||||
ExtSnapshotPerm bdrv_check_ext_snapshot(BlockDriverState *bs)
|
||||
/* Used to recurse on single child block filters.
|
||||
* Single child block filter will store their child in bs->file.
|
||||
*/
|
||||
bool bdrv_generic_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
if (bs->drv->bdrv_check_ext_snapshot) {
|
||||
return bs->drv->bdrv_check_ext_snapshot(bs);
|
||||
if (!bs->drv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bs->file && bs->file->drv && bs->file->drv->bdrv_check_ext_snapshot) {
|
||||
return bs->file->drv->bdrv_check_ext_snapshot(bs);
|
||||
if (!bs->drv->authorizations[BS_IS_A_FILTER]) {
|
||||
if (bs == candidate) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* external snapshots are allowed by default */
|
||||
return EXT_SNAPSHOT_ALLOWED;
|
||||
if (!bs->drv->authorizations[BS_FILTER_PASS_DOWN]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bs->file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bdrv_recurse_is_first_non_filter(bs->file, candidate);
|
||||
}
|
||||
|
||||
ExtSnapshotPerm bdrv_check_ext_snapshot_forbidden(BlockDriverState *bs)
|
||||
bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
return EXT_SNAPSHOT_FORBIDDEN;
|
||||
if (bs->drv && bs->drv->bdrv_recurse_is_first_non_filter) {
|
||||
return bs->drv->bdrv_recurse_is_first_non_filter(bs, candidate);
|
||||
}
|
||||
|
||||
return bdrv_generic_is_first_non_filter(bs, candidate);
|
||||
}
|
||||
|
||||
/* This function checks if the candidate is the first non filter bs down it's
|
||||
* bs chain. Since we don't have pointers to parents it explore all bs chains
|
||||
* from the top. Some filters can choose not to pass down the recursion.
|
||||
*/
|
||||
bool bdrv_is_first_non_filter(BlockDriverState *candidate)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
|
||||
/* walk down the bs forest recursively */
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||
bool perm;
|
||||
|
||||
if (!bs->file) {
|
||||
continue;
|
||||
}
|
||||
|
||||
perm = bdrv_recurse_is_first_non_filter(bs->file, candidate);
|
||||
|
||||
/* candidate is the first non filter */
|
||||
if (perm) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -404,7 +404,7 @@ static BlockDriver bdrv_blkverify = {
|
||||
.bdrv_aio_writev = blkverify_aio_writev,
|
||||
.bdrv_aio_flush = blkverify_aio_flush,
|
||||
|
||||
.bdrv_check_ext_snapshot = bdrv_check_ext_snapshot_forbidden,
|
||||
.authorizations = { true, false },
|
||||
};
|
||||
|
||||
static void bdrv_blkverify_init(void)
|
||||
|
@ -1243,7 +1243,7 @@ static void external_snapshot_prepare(BlkTransactionState *common,
|
||||
}
|
||||
}
|
||||
|
||||
if (bdrv_check_ext_snapshot(state->old_bs) != EXT_SNAPSHOT_ALLOWED) {
|
||||
if (!bdrv_is_first_non_filter(state->old_bs)) {
|
||||
error_set(errp, QERR_FEATURE_DISABLED, "snapshot");
|
||||
return;
|
||||
}
|
||||
|
@ -287,16 +287,16 @@ int bdrv_amend_options(BlockDriverState *bs_new, QEMUOptionParameter *options);
|
||||
/* external snapshots */
|
||||
|
||||
typedef enum {
|
||||
EXT_SNAPSHOT_ALLOWED,
|
||||
EXT_SNAPSHOT_FORBIDDEN,
|
||||
} ExtSnapshotPerm;
|
||||
BS_IS_A_FILTER,
|
||||
BS_FILTER_PASS_DOWN,
|
||||
BS_AUTHORIZATION_COUNT,
|
||||
} BsAuthorization;
|
||||
|
||||
/* return EXT_SNAPSHOT_ALLOWED if external snapshot is allowed
|
||||
* return EXT_SNAPSHOT_FORBIDDEN if external snapshot is forbidden
|
||||
*/
|
||||
ExtSnapshotPerm bdrv_check_ext_snapshot(BlockDriverState *bs);
|
||||
/* helper used to forbid external snapshots like in blkverify */
|
||||
ExtSnapshotPerm bdrv_check_ext_snapshot_forbidden(BlockDriverState *bs);
|
||||
bool bdrv_generic_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate);
|
||||
bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate);
|
||||
bool bdrv_is_first_non_filter(BlockDriverState *candidate);
|
||||
|
||||
/* async block I/O */
|
||||
typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
|
||||
|
@ -69,10 +69,16 @@ struct BlockDriver {
|
||||
const char *format_name;
|
||||
int instance_size;
|
||||
|
||||
/* if not defined external snapshots are allowed
|
||||
* future block filters will query their children to build the response
|
||||
/* this table of boolean contains authorizations for the block operations */
|
||||
bool authorizations[BS_AUTHORIZATION_COUNT];
|
||||
/* for snapshots complex block filter like Quorum can implement the
|
||||
* following recursive callback instead of BS_IS_A_FILTER.
|
||||
* It's purpose is to recurse on the filter children while calling
|
||||
* bdrv_recurse_is_first_non_filter on them.
|
||||
* For a sample implementation look in the future Quorum block filter.
|
||||
*/
|
||||
ExtSnapshotPerm (*bdrv_check_ext_snapshot)(BlockDriverState *bs);
|
||||
bool (*bdrv_recurse_is_first_non_filter)(BlockDriverState *bs,
|
||||
BlockDriverState *candidate);
|
||||
|
||||
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
|
||||
int (*bdrv_probe_device)(const char *filename);
|
||||
|
Loading…
Reference in New Issue
Block a user