summaryrefslogtreecommitdiff
path: root/block.c
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2017-01-16 18:26:20 +0100
committerKevin Wolf <kwolf@redhat.com>2017-02-28 20:40:37 +0100
commitd083319fe007e100b38995d0ea254845c8efa433 (patch)
tree14a854dfe39faaf5b7f74ae41c46c71047aa0d71 /block.c
parentb5411555877121b74cbe0a12a867d16d861746b1 (diff)
downloadqemu-d083319fe007e100b38995d0ea254845c8efa433.tar.gz
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>
Diffstat (limited to 'block.c')
-rw-r--r--block.c67
1 files changed, 56 insertions, 11 deletions
diff --git a/block.c b/block.c
index e03cc5da42..f72a67f230 100644
--- a/block.c
+++ b/block.c
@@ -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;
}