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); 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) { if (!bs->drv) {
return bs->drv->bdrv_check_ext_snapshot(bs); return false;
} }
if (bs->file && bs->file->drv && bs->file->drv->bdrv_check_ext_snapshot) { if (!bs->drv->authorizations[BS_IS_A_FILTER]) {
return bs->file->drv->bdrv_check_ext_snapshot(bs); if (bs == candidate) {
return true;
} else {
return false;
}
} }
/* external snapshots are allowed by default */ if (!bs->drv->authorizations[BS_FILTER_PASS_DOWN]) {
return EXT_SNAPSHOT_ALLOWED; 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_writev = blkverify_aio_writev,
.bdrv_aio_flush = blkverify_aio_flush, .bdrv_aio_flush = blkverify_aio_flush,
.bdrv_check_ext_snapshot = bdrv_check_ext_snapshot_forbidden, .authorizations = { true, false },
}; };
static void bdrv_blkverify_init(void) 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"); error_set(errp, QERR_FEATURE_DISABLED, "snapshot");
return; return;
} }

View File

@ -287,16 +287,16 @@ int bdrv_amend_options(BlockDriverState *bs_new, QEMUOptionParameter *options);
/* external snapshots */ /* external snapshots */
typedef enum { typedef enum {
EXT_SNAPSHOT_ALLOWED, BS_IS_A_FILTER,
EXT_SNAPSHOT_FORBIDDEN, BS_FILTER_PASS_DOWN,
} ExtSnapshotPerm; BS_AUTHORIZATION_COUNT,
} BsAuthorization;
/* return EXT_SNAPSHOT_ALLOWED if external snapshot is allowed bool bdrv_generic_is_first_non_filter(BlockDriverState *bs,
* return EXT_SNAPSHOT_FORBIDDEN if external snapshot is forbidden BlockDriverState *candidate);
*/ bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
ExtSnapshotPerm bdrv_check_ext_snapshot(BlockDriverState *bs); BlockDriverState *candidate);
/* helper used to forbid external snapshots like in blkverify */ bool bdrv_is_first_non_filter(BlockDriverState *candidate);
ExtSnapshotPerm bdrv_check_ext_snapshot_forbidden(BlockDriverState *bs);
/* async block I/O */ /* async block I/O */
typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector, typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,

View File

@ -69,10 +69,16 @@ struct BlockDriver {
const char *format_name; const char *format_name;
int instance_size; int instance_size;
/* if not defined external snapshots are allowed /* this table of boolean contains authorizations for the block operations */
* future block filters will query their children to build the response 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)(const uint8_t *buf, int buf_size, const char *filename);
int (*bdrv_probe_device)(const char *filename); int (*bdrv_probe_device)(const char *filename);