Commit f94dc3b4 authored by Max Reitz's avatar Max Reitz Committed by Kevin Wolf
Browse files

block/mirror: Fix child permissions



We cannot use bdrv_child_try_set_perm() to give up all restrictions on
the child edge, and still have bdrv_mirror_top_child_perm() request
BLK_PERM_WRITE.  Fix this by making bdrv_mirror_top_child_perm() return
0/BLK_PERM_ALL when we want to give up all permissions, and replacing
bdrv_child_try_set_perm() by bdrv_child_refresh_perms().

The bdrv_child_try_set_perm() before removing the node with
bdrv_replace_node() is then unnecessary.  No permissions have changed
since the previous invocation of bdrv_child_try_set_perm().

Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
Reviewed-by: default avatarKevin Wolf <kwolf@redhat.com>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent c1087f12
Loading
Loading
Loading
Loading
+23 −9
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ typedef struct MirrorBlockJob {

typedef struct MirrorBDSOpaque {
    MirrorBlockJob *job;
    bool stop;
} MirrorBDSOpaque;

struct MirrorOp {
@@ -656,7 +657,8 @@ static int mirror_exit_common(Job *job)

    /* We don't access the source any more. Dropping any WRITE/RESIZE is
     * required before it could become a backing file of target_bs. */
    bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,
    bs_opaque->stop = true;
    bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
                             &error_abort);
    if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {
        BlockDriverState *backing = s->is_none_mode ? src : s->base;
@@ -704,13 +706,12 @@ static int mirror_exit_common(Job *job)
    g_free(s->replaces);
    bdrv_unref(target_bs);

    /* Remove the mirror filter driver from the graph. Before this, get rid of
    /*
     * Remove the mirror filter driver from the graph. Before this, get rid of
     * the blockers on the intermediate nodes so that the resulting state is
     * valid. Also give up permissions on mirror_top_bs->backing, which might
     * block the removal. */
     * valid.
     */
    block_job_remove_all_bdrv(bjob);
    bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,
                            &error_abort);
    bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);

    /* We just changed the BDS the job BB refers to (with either or both of the
@@ -1459,6 +1460,18 @@ static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c,
                                       uint64_t perm, uint64_t shared,
                                       uint64_t *nperm, uint64_t *nshared)
{
    MirrorBDSOpaque *s = bs->opaque;

    if (s->stop) {
        /*
         * If the job is to be stopped, we do not need to forward
         * anything to the real image.
         */
        *nperm = 0;
        *nshared = BLK_PERM_ALL;
        return;
    }

    /* Must be able to forward guest writes to the real image */
    *nperm = 0;
    if (perm & BLK_PERM_WRITE) {
@@ -1681,7 +1694,8 @@ fail:
        job_early_fail(&s->common.job);
    }

    bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,
    bs_opaque->stop = true;
    bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
                             &error_abort);
    bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);