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:
Benoît Canet 2014-01-23 21:31:36 +01:00 committed by Kevin Wolf
parent 12d3ba821d
commit 212a5a8f09
5 changed files with 76 additions and 23 deletions

65
block.c
View file

@ -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;
}

View file

@ -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)

View file

@ -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;
}

View file

@ -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,

View file

@ -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);