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);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtSnapshotPerm bdrv_check_ext_snapshot_forbidden(BlockDriverState *bs)
|
if (!bs->file) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bdrv_recurse_is_first_non_filter(bs->file, candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue