aboutsummaryrefslogtreecommitdiff
path: root/block.c
diff options
context:
space:
mode:
authorVladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>2021-04-28 18:17:58 +0300
committerKevin Wolf <kwolf@redhat.com>2021-04-30 12:27:48 +0200
commit72373e40fbc7e4218061a8211384db362d3e7348 (patch)
tree4ce1e028249dff7b973c2e3b2c06e1e40af7bcbb /block.c
parenta2aabf88958119ec7d3022287eff6bcc924c90a8 (diff)
downloadqemu-72373e40fbc7e4218061a8211384db362d3e7348.zip
qemu-72373e40fbc7e4218061a8211384db362d3e7348.tar.gz
qemu-72373e40fbc7e4218061a8211384db362d3e7348.tar.bz2
block: bdrv_reopen_multiple: refresh permissions on updated graph
Move bdrv_reopen_multiple to new paradigm of permission update: first update graph relations, then do refresh the permissions. We have to modify reopen process in file-posix driver: with new scheme we don't have prepared permissions in raw_reopen_prepare(), so we should reconfigure fd in raw_check_perm(). Still this seems more native and simple anyway. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Message-Id: <20210428151804.439460-31-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block.c')
-rw-r--r--block.c187
1 files changed, 54 insertions, 133 deletions
diff --git a/block.c b/block.c
index 357ec1b..ffaa367 100644
--- a/block.c
+++ b/block.c
@@ -95,8 +95,9 @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs,
Transaction *tran);
-static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue
- *queue, Error **errp);
+static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
+ BlockReopenQueue *queue,
+ Transaction *set_backings_tran, Error **errp);
static void bdrv_reopen_commit(BDRVReopenState *reopen_state);
static void bdrv_reopen_abort(BDRVReopenState *reopen_state);
@@ -2468,6 +2469,7 @@ static void bdrv_list_abort_perm_update(GSList *list)
}
}
+__attribute__((unused))
static void bdrv_abort_perm_update(BlockDriverState *bs)
{
g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
@@ -2563,6 +2565,7 @@ char *bdrv_perm_names(uint64_t perm)
*
* Needs to be followed by a call to either bdrv_set_perm() or
* bdrv_abort_perm_update(). */
+__attribute__((unused))
static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
uint64_t new_used_perm,
uint64_t new_shared_perm,
@@ -4183,10 +4186,6 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
bs_entry->state.explicit_options = explicit_options;
bs_entry->state.flags = flags;
- /* This needs to be overwritten in bdrv_reopen_prepare() */
- bs_entry->state.perm = UINT64_MAX;
- bs_entry->state.shared_perm = 0;
-
/*
* If keep_old_opts is false then it means that unspecified
* options must be reset to their original value. We don't allow
@@ -4271,6 +4270,9 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
{
int ret = -1;
BlockReopenQueueEntry *bs_entry, *next;
+ Transaction *tran = tran_new();
+ g_autoptr(GHashTable) found = NULL;
+ g_autoptr(GSList) refresh_list = NULL;
assert(bs_queue != NULL);
@@ -4284,33 +4286,33 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
assert(bs_entry->state.bs->quiesce_counter > 0);
- if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, errp)) {
- goto cleanup;
+ ret = bdrv_reopen_prepare(&bs_entry->state, bs_queue, tran, errp);
+ if (ret < 0) {
+ goto abort;
}
bs_entry->prepared = true;
}
+ found = g_hash_table_new(NULL, NULL);
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
BDRVReopenState *state = &bs_entry->state;
- ret = bdrv_check_perm(state->bs, bs_queue, state->perm,
- state->shared_perm, errp);
- if (ret < 0) {
- goto cleanup_perm;
- }
- /* Check if new_backing_bs would accept the new permissions */
- if (state->replace_backing_bs && state->new_backing_bs) {
- uint64_t nperm, nshared;
- bdrv_child_perm(state->bs, state->new_backing_bs,
- NULL, bdrv_backing_role(state->bs),
- bs_queue, state->perm, state->shared_perm,
- &nperm, &nshared);
- ret = bdrv_check_update_perm(state->new_backing_bs, NULL,
- nperm, nshared, errp);
- if (ret < 0) {
- goto cleanup_perm;
- }
+
+ refresh_list = bdrv_topological_dfs(refresh_list, found, state->bs);
+ if (state->old_backing_bs) {
+ refresh_list = bdrv_topological_dfs(refresh_list, found,
+ state->old_backing_bs);
}
- bs_entry->perms_checked = true;
+ }
+
+ /*
+ * Note that file-posix driver rely on permission update done during reopen
+ * (even if no permission changed), because it wants "new" permissions for
+ * reconfiguring the fd and that's why it does it in raw_check_perm(), not
+ * in raw_reopen_prepare() which is called with "old" permissions.
+ */
+ ret = bdrv_list_refresh_perms(refresh_list, bs_queue, tran, errp);
+ if (ret < 0) {
+ goto abort;
}
/*
@@ -4326,51 +4328,31 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
bdrv_reopen_commit(&bs_entry->state);
}
- ret = 0;
-cleanup_perm:
- QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
- BDRVReopenState *state = &bs_entry->state;
-
- if (!bs_entry->perms_checked) {
- continue;
- }
-
- if (ret == 0) {
- uint64_t perm, shared;
+ tran_commit(tran);
- bdrv_get_cumulative_perm(state->bs, &perm, &shared);
- assert(perm == state->perm);
- assert(shared == state->shared_perm);
+ QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
+ BlockDriverState *bs = bs_entry->state.bs;
- bdrv_set_perm(state->bs);
- } else {
- bdrv_abort_perm_update(state->bs);
- if (state->replace_backing_bs && state->new_backing_bs) {
- bdrv_abort_perm_update(state->new_backing_bs);
- }
+ if (bs->drv->bdrv_reopen_commit_post) {
+ bs->drv->bdrv_reopen_commit_post(&bs_entry->state);
}
}
- if (ret == 0) {
- QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
- BlockDriverState *bs = bs_entry->state.bs;
+ ret = 0;
+ goto cleanup;
- if (bs->drv->bdrv_reopen_commit_post)
- bs->drv->bdrv_reopen_commit_post(&bs_entry->state);
+abort:
+ tran_abort(tran);
+ QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
+ if (bs_entry->prepared) {
+ bdrv_reopen_abort(&bs_entry->state);
}
+ qobject_unref(bs_entry->state.explicit_options);
+ qobject_unref(bs_entry->state.options);
}
+
cleanup:
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
- if (ret) {
- if (bs_entry->prepared) {
- bdrv_reopen_abort(&bs_entry->state);
- }
- qobject_unref(bs_entry->state.explicit_options);
- qobject_unref(bs_entry->state.options);
- }
- if (bs_entry->state.new_backing_bs) {
- bdrv_unref(bs_entry->state.new_backing_bs);
- }
g_free(bs_entry);
}
g_free(bs_queue);
@@ -4395,53 +4377,6 @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
return ret;
}
-static BlockReopenQueueEntry *find_parent_in_reopen_queue(BlockReopenQueue *q,
- BdrvChild *c)
-{
- BlockReopenQueueEntry *entry;
-
- QTAILQ_FOREACH(entry, q, entry) {
- BlockDriverState *bs = entry->state.bs;
- BdrvChild *child;
-
- QLIST_FOREACH(child, &bs->children, next) {
- if (child == c) {
- return entry;
- }
- }
- }
-
- return NULL;
-}
-
-static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs,
- uint64_t *perm, uint64_t *shared)
-{
- BdrvChild *c;
- BlockReopenQueueEntry *parent;
- uint64_t cumulative_perms = 0;
- uint64_t cumulative_shared_perms = BLK_PERM_ALL;
-
- QLIST_FOREACH(c, &bs->parents, next_parent) {
- parent = find_parent_in_reopen_queue(q, c);
- if (!parent) {
- cumulative_perms |= c->perm;
- cumulative_shared_perms &= c->shared_perm;
- } else {
- uint64_t nperm, nshared;
-
- bdrv_child_perm(parent->state.bs, bs, c, c->role, q,
- parent->state.perm, parent->state.shared_perm,
- &nperm, &nshared);
-
- cumulative_perms |= nperm;
- cumulative_shared_perms &= nshared;
- }
- }
- *perm = cumulative_perms;
- *shared = cumulative_shared_perms;
-}
-
static bool bdrv_reopen_can_attach(BlockDriverState *parent,
BdrvChild *child,
BlockDriverState *new_child,
@@ -4483,6 +4418,7 @@ static bool bdrv_reopen_can_attach(BlockDriverState *parent,
* Return 0 on success, otherwise return < 0 and set @errp.
*/
static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
+ Transaction *set_backings_tran,
Error **errp)
{
BlockDriverState *bs = reopen_state->bs;
@@ -4559,6 +4495,8 @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
/* If we want to replace the backing file we need some extra checks */
if (new_backing_bs != bdrv_filter_or_cow_bs(overlay_bs)) {
+ int ret;
+
/* Check for implicit nodes between bs and its backing file */
if (bs != overlay_bs) {
error_setg(errp, "Cannot change backing link if '%s' has "
@@ -4579,9 +4517,11 @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
return -EPERM;
}
reopen_state->replace_backing_bs = true;
- if (new_backing_bs) {
- bdrv_ref(new_backing_bs);
- reopen_state->new_backing_bs = new_backing_bs;
+ reopen_state->old_backing_bs = bs->backing ? bs->backing->bs : NULL;
+ ret = bdrv_set_backing_noperm(bs, new_backing_bs, set_backings_tran,
+ errp);
+ if (ret < 0) {
+ return ret;
}
}
@@ -4606,7 +4546,8 @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
*
*/
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
- BlockReopenQueue *queue, Error **errp)
+ BlockReopenQueue *queue,
+ Transaction *set_backings_tran, Error **errp)
{
int ret = -1;
int old_flags;
@@ -4673,10 +4614,6 @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
goto error;
}
- /* Calculate required permissions after reopening */
- bdrv_reopen_perm(queue, reopen_state->bs,
- &reopen_state->perm, &reopen_state->shared_perm);
-
if (drv->bdrv_reopen_prepare) {
/*
* If a driver-specific option is missing, it means that we
@@ -4730,7 +4667,7 @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
* either a reference to an existing node (using its node name)
* or NULL to simply detach the current backing file.
*/
- ret = bdrv_reopen_parse_backing(reopen_state, errp);
+ ret = bdrv_reopen_parse_backing(reopen_state, set_backings_tran, errp);
if (ret < 0) {
goto error;
}
@@ -4852,22 +4789,6 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
qdict_del(bs->explicit_options, child->name);
qdict_del(bs->options, child->name);
}
-
- /*
- * Change the backing file if a new one was specified. We do this
- * after updating bs->options, so bdrv_refresh_filename() (called
- * from bdrv_set_backing_hd()) has the new values.
- */
- if (reopen_state->replace_backing_bs) {
- BlockDriverState *old_backing_bs = child_bs(bs->backing);
- assert(!old_backing_bs || !old_backing_bs->implicit);
- /* Abort the permission update on the backing bs we're detaching */
- if (old_backing_bs) {
- bdrv_abort_perm_update(old_backing_bs);
- }
- bdrv_set_backing_hd(bs, reopen_state->new_backing_bs, &error_abort);
- }
-
bdrv_refresh_limits(bs, NULL, NULL);
}