block: bdrv_refresh_perms: check for parents permissions conflict
Add additional check that node parents do not interfere with each other. This should not hurt existing callers and allows in further patch use bdrv_refresh_perms() to update a subtree of changed BdrvChild (check that change is correct). New check will substitute bdrv_check_update_perm() in following permissions refactoring, so keep error messages the same to avoid unit test result changes. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Alberto Garcia <berto@igalia.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Message-Id: <20210428151804.439460-10-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
8cad15b156
commit
3bf416ba0f
63
block.c
63
block.c
|
@ -2026,6 +2026,57 @@ bool bdrv_is_writable(BlockDriverState *bs)
|
||||||
return bdrv_is_writable_after_reopen(bs, NULL);
|
return bdrv_is_writable_after_reopen(bs, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *bdrv_child_user_desc(BdrvChild *c)
|
||||||
|
{
|
||||||
|
if (c->klass->get_parent_desc) {
|
||||||
|
return c->klass->get_parent_desc(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_strdup("another user");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp)
|
||||||
|
{
|
||||||
|
g_autofree char *user = NULL;
|
||||||
|
g_autofree char *perm_names = NULL;
|
||||||
|
|
||||||
|
if ((b->perm & a->shared_perm) == b->perm) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
perm_names = bdrv_perm_names(b->perm & ~a->shared_perm);
|
||||||
|
user = bdrv_child_user_desc(a);
|
||||||
|
error_setg(errp, "Conflicts with use by %s as '%s', which does not "
|
||||||
|
"allow '%s' on %s",
|
||||||
|
user, a->name, perm_names, bdrv_get_node_name(b->bs));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp)
|
||||||
|
{
|
||||||
|
BdrvChild *a, *b;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* During the loop we'll look at each pair twice. That's correct because
|
||||||
|
* bdrv_a_allow_b() is asymmetric and we should check each pair in both
|
||||||
|
* directions.
|
||||||
|
*/
|
||||||
|
QLIST_FOREACH(a, &bs->parents, next_parent) {
|
||||||
|
QLIST_FOREACH(b, &bs->parents, next_parent) {
|
||||||
|
if (a == b) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bdrv_a_allow_b(a, b, errp)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
|
static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
|
||||||
BdrvChild *c, BdrvChildRole role,
|
BdrvChild *c, BdrvChildRole role,
|
||||||
BlockReopenQueue *reopen_queue,
|
BlockReopenQueue *reopen_queue,
|
||||||
|
@ -2203,15 +2254,6 @@ void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
|
||||||
*shared_perm = cumulative_shared_perms;
|
*shared_perm = cumulative_shared_perms;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *bdrv_child_user_desc(BdrvChild *c)
|
|
||||||
{
|
|
||||||
if (c->klass->get_parent_desc) {
|
|
||||||
return c->klass->get_parent_desc(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_strdup("another user");
|
|
||||||
}
|
|
||||||
|
|
||||||
char *bdrv_perm_names(uint64_t perm)
|
char *bdrv_perm_names(uint64_t perm)
|
||||||
{
|
{
|
||||||
struct perm_name {
|
struct perm_name {
|
||||||
|
@ -2355,6 +2397,9 @@ static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp)
|
||||||
int ret;
|
int ret;
|
||||||
uint64_t perm, shared_perm;
|
uint64_t perm, shared_perm;
|
||||||
|
|
||||||
|
if (bdrv_parent_perms_conflict(bs, errp)) {
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
|
bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
|
||||||
ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, errp);
|
ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, errp);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
Loading…
Reference in New Issue