block: Include details on permission errors in message

Instead of just telling that there was some conflict, we can be specific
and tell which permissions were in conflict and which way the conflict
is.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Acked-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
Kevin Wolf 2017-01-16 18:26:20 +01:00
parent b541155587
commit d083319fe0

67
block.c
View file

@ -1462,6 +1462,43 @@ static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
*shared_perm = cumulative_shared_perms;
}
static char *bdrv_child_user_desc(BdrvChild *c)
{
if (c->role->get_parent_desc) {
return c->role->get_parent_desc(c);
}
return g_strdup("another user");
}
static char *bdrv_perm_names(uint64_t perm)
{
struct perm_name {
uint64_t perm;
const char *name;
} permissions[] = {
{ BLK_PERM_CONSISTENT_READ, "consistent read" },
{ BLK_PERM_WRITE, "write" },
{ BLK_PERM_WRITE_UNCHANGED, "write unchanged" },
{ BLK_PERM_RESIZE, "resize" },
{ BLK_PERM_GRAPH_MOD, "change children" },
{ 0, NULL }
};
char *result = g_strdup("");
struct perm_name *p;
for (p = permissions; p->name; p++) {
if (perm & p->perm) {
char *old = result;
result = g_strdup_printf("%s%s%s", old, *old ? ", " : "", p->name);
g_free(old);
}
}
return result;
}
/*
* Checks whether a new reference to @bs can be added if the new user requires
* @new_used_perm/@new_shared_perm as its permissions. If @ignore_child is set,
@ -1486,17 +1523,25 @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
continue;
}
if ((new_used_perm & c->shared_perm) != new_used_perm ||
(c->perm & new_shared_perm) != c->perm)
{
const char *user = NULL;
if (c->role->get_name) {
user = c->role->get_name(c);
if (user && !*user) {
user = NULL;
}
}
error_setg(errp, "Conflicts with %s", user ?: "another operation");
if ((new_used_perm & c->shared_perm) != new_used_perm) {
char *user = bdrv_child_user_desc(c);
char *perm_names = bdrv_perm_names(new_used_perm & ~c->shared_perm);
error_setg(errp, "Conflicts with use by %s as '%s', which does not "
"allow '%s' on %s",
user, c->name, perm_names, bdrv_get_node_name(c->bs));
g_free(user);
g_free(perm_names);
return -EPERM;
}
if ((c->perm & new_shared_perm) != c->perm) {
char *user = bdrv_child_user_desc(c);
char *perm_names = bdrv_perm_names(c->perm & ~new_shared_perm);
error_setg(errp, "Conflicts with use by %s as '%s', which uses "
"'%s' on %s",
user, c->name, perm_names, bdrv_get_node_name(c->bs));
g_free(user);
g_free(perm_names);
return -EPERM;
}