Commit 33d60999 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging



Block layer patches:

- block: Remove bs->job
- block: Ignore loosening perm restrictions failures
- block/null: Expose read-zeroes option in QAPI schema
- iotests: Hide timestamps for skipped tests

# gpg: Signature made Tue 18 Jun 2019 15:44:12 BST
# gpg:                using RSA key 7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* remotes/kevin/tags/for-upstream:
  block/null: Expose read-zeroes option in QAPI schema
  iotests: Test failure to loosen restrictions
  block: Ignore loosening perm restrictions failures
  block: Add *tighten_restrictions to *check*_perm()
  block: Fix order in bdrv_replace_child()
  block/commit: Drop bdrv_child_try_set_perm()
  block/mirror: Fix child permissions
  block: Add bdrv_child_refresh_perms()
  file-posix: Update open_flags in raw_set_perm()
  block: drop bs->job
  blockdev: blockdev_mark_auto_del: drop usage of bs->job
  block/block-backend: blk_iostatus_reset: drop usage of bs->job
  block/replication: drop usage of bs->job
  iotests: Hide timestamps for skipped tests

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents afec70e4 128b05f7
Loading
Loading
Loading
Loading
+129 −26
Original line number Diff line number Diff line
@@ -1706,7 +1706,8 @@ static int bdrv_fill_options(QDict **options, const char *filename,

static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
                                 uint64_t perm, uint64_t shared,
                                 GSList *ignore_children, Error **errp);
                                 GSList *ignore_children,
                                 bool *tighten_restrictions, Error **errp);
static void bdrv_child_abort_perm_update(BdrvChild *c);
static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
@@ -1781,18 +1782,43 @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
 * permissions of all its parents. This involves checking whether all necessary
 * permission changes to child nodes can be performed.
 *
 * Will set *tighten_restrictions to true if and only if new permissions have to
 * be taken or currently shared permissions are to be unshared.  Otherwise,
 * errors are not fatal as long as the caller accepts that the restrictions
 * remain tighter than they need to be.  The caller still has to abort the
 * transaction.
 * @tighten_restrictions cannot be used together with @q: When reopening, we may
 * encounter fatal errors even though no restrictions are to be tightened.  For
 * example, changing a node from RW to RO will fail if the WRITE permission is
 * to be kept.
 *
 * A call to this function must always be followed by a call to bdrv_set_perm()
 * or bdrv_abort_perm_update().
 */
static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
                           uint64_t cumulative_perms,
                           uint64_t cumulative_shared_perms,
                           GSList *ignore_children, Error **errp)
                           GSList *ignore_children,
                           bool *tighten_restrictions, Error **errp)
{
    BlockDriver *drv = bs->drv;
    BdrvChild *c;
    int ret;

    assert(!q || !tighten_restrictions);

    if (tighten_restrictions) {
        uint64_t current_perms, current_shared;
        uint64_t added_perms, removed_shared_perms;

        bdrv_get_cumulative_perm(bs, &current_perms, &current_shared);

        added_perms = cumulative_perms & ~current_perms;
        removed_shared_perms = current_shared & ~cumulative_shared_perms;

        *tighten_restrictions = added_perms || removed_shared_perms;
    }

    /* Write permissions never work with read-only images */
    if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) &&
        !bdrv_is_writable_after_reopen(bs, q))
@@ -1833,11 +1859,18 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
    /* Check all children */
    QLIST_FOREACH(c, &bs->children, next) {
        uint64_t cur_perm, cur_shared;
        bool child_tighten_restr;

        bdrv_child_perm(bs, c->bs, c, c->role, q,
                        cumulative_perms, cumulative_shared_perms,
                        &cur_perm, &cur_shared);
        ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared,
                                    ignore_children, errp);
        ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, ignore_children,
                                    tighten_restrictions ? &child_tighten_restr
                                                         : NULL,
                                    errp);
        if (tighten_restrictions) {
            *tighten_restrictions |= child_tighten_restr;
        }
        if (ret < 0) {
            return ret;
        }
@@ -1961,17 +1994,23 @@ char *bdrv_perm_names(uint64_t perm)
 * set, the BdrvChild objects in this list are ignored in the calculations;
 * this allows checking permission updates for an existing reference.
 *
 * See bdrv_check_perm() for the semantics of @tighten_restrictions.
 *
 * Needs to be followed by a call to either bdrv_set_perm() or
 * bdrv_abort_perm_update(). */
static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
                                  uint64_t new_used_perm,
                                  uint64_t new_shared_perm,
                                  GSList *ignore_children, Error **errp)
                                  GSList *ignore_children,
                                  bool *tighten_restrictions,
                                  Error **errp)
{
    BdrvChild *c;
    uint64_t cumulative_perms = new_used_perm;
    uint64_t cumulative_shared_perms = new_shared_perm;

    assert(!q || !tighten_restrictions);

    /* There is no reason why anyone couldn't tolerate write_unchanged */
    assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED);

@@ -1983,6 +2022,11 @@ static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
        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);

            if (tighten_restrictions) {
                *tighten_restrictions = true;
            }

            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));
@@ -1994,6 +2038,11 @@ static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
        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);

            if (tighten_restrictions) {
                *tighten_restrictions = true;
            }

            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));
@@ -2007,19 +2056,21 @@ static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
    }

    return bdrv_check_perm(bs, q, cumulative_perms, cumulative_shared_perms,
                           ignore_children, errp);
                           ignore_children, tighten_restrictions, errp);
}

/* Needs to be followed by a call to either bdrv_child_set_perm() or
 * bdrv_child_abort_perm_update(). */
static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
                                 uint64_t perm, uint64_t shared,
                                 GSList *ignore_children, Error **errp)
                                 GSList *ignore_children,
                                 bool *tighten_restrictions, Error **errp)
{
    int ret;

    ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c);
    ret = bdrv_check_update_perm(c->bs, q, perm, shared, ignore_children, errp);
    ret = bdrv_check_update_perm(c->bs, q, perm, shared, ignore_children,
                                 tighten_restrictions, errp);
    g_slist_free(ignore_children);

    if (ret < 0) {
@@ -2070,11 +2121,26 @@ static void bdrv_child_abort_perm_update(BdrvChild *c)
int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
                            Error **errp)
{
    Error *local_err = NULL;
    int ret;
    bool tighten_restrictions;

    ret = bdrv_child_check_perm(c, NULL, perm, shared, NULL, errp);
    ret = bdrv_child_check_perm(c, NULL, perm, shared, NULL,
                                &tighten_restrictions, &local_err);
    if (ret < 0) {
        bdrv_child_abort_perm_update(c);
        if (tighten_restrictions) {
            error_propagate(errp, local_err);
        } else {
            /*
             * Our caller may intend to only loosen restrictions and
             * does not expect this function to fail.  Errors are not
             * fatal in such a case, so we can just hide them from our
             * caller.
             */
            error_free(local_err);
            ret = 0;
        }
        return ret;
    }

@@ -2083,6 +2149,18 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
    return 0;
}

int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp)
{
    uint64_t parent_perms, parent_shared;
    uint64_t perms, shared;

    bdrv_get_cumulative_perm(bs, &parent_perms, &parent_shared);
    bdrv_child_perm(bs, c->bs, c, c->role, NULL, parent_perms, parent_shared,
                    &perms, &shared);

    return bdrv_child_try_set_perm(c, perms, shared, errp);
}

void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c,
                               const BdrvChildRole *role,
                               BlockReopenQueue *reopen_queue,
@@ -2228,23 +2306,41 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)

    bdrv_replace_child_noperm(child, new_bs);

    /*
     * Start with the new node's permissions.  If @new_bs is a (direct
     * or indirect) child of @old_bs, we must complete the permission
     * update on @new_bs before we loosen the restrictions on @old_bs.
     * Otherwise, bdrv_check_perm() on @old_bs would re-initiate
     * updating the permissions of @new_bs, and thus not purely loosen
     * restrictions.
     */
    if (new_bs) {
        bdrv_get_cumulative_perm(new_bs, &perm, &shared_perm);
        bdrv_set_perm(new_bs, perm, shared_perm);
    }

    if (old_bs) {
        /* Update permissions for old node. This is guaranteed to succeed
         * because we're just taking a parent away, so we're loosening
         * restrictions. */
        bool tighten_restrictions;
        int ret;

        bdrv_get_cumulative_perm(old_bs, &perm, &shared_perm);
        bdrv_check_perm(old_bs, NULL, perm, shared_perm, NULL, &error_abort);
        ret = bdrv_check_perm(old_bs, NULL, perm, shared_perm, NULL,
                              &tighten_restrictions, NULL);
        assert(tighten_restrictions == false);
        if (ret < 0) {
            /* We only tried to loosen restrictions, so errors are not fatal */
            bdrv_abort_perm_update(old_bs);
        } else {
            bdrv_set_perm(old_bs, perm, shared_perm);
        }

        /* When the parent requiring a non-default AioContext is removed, the
         * node moves back to the main AioContext */
        bdrv_try_set_aio_context(old_bs, qemu_get_aio_context(), NULL);
    }

    if (new_bs) {
        bdrv_get_cumulative_perm(new_bs, &perm, &shared_perm);
        bdrv_set_perm(new_bs, perm, shared_perm);
    }
}

/*
@@ -2268,7 +2364,8 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
    Error *local_err = NULL;
    int ret;

    ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, errp);
    ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, NULL,
                                 errp);
    if (ret < 0) {
        bdrv_abort_perm_update(child_bs);
        bdrv_unref(child_bs);
@@ -3349,7 +3446,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
    QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
        BDRVReopenState *state = &bs_entry->state;
        ret = bdrv_check_perm(state->bs, bs_queue, state->perm,
                              state->shared_perm, NULL, errp);
                              state->shared_perm, NULL, NULL, errp);
        if (ret < 0) {
            goto cleanup_perm;
        }
@@ -3361,7 +3458,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
                            state->perm, state->shared_perm,
                            &nperm, &nshared);
            ret = bdrv_check_update_perm(state->new_backing_bs, NULL,
                                         nperm, nshared, NULL, errp);
                                         nperm, nshared, NULL, NULL, errp);
            if (ret < 0) {
                goto cleanup_perm;
            }
@@ -3905,7 +4002,6 @@ static void bdrv_close(BlockDriverState *bs)
    BdrvAioNotifier *ban, *ban_next;
    BdrvChild *child, *next;

    assert(!bs->job);
    assert(!bs->refcnt);

    bdrv_drained_begin(bs); /* complete I/O */
@@ -4078,7 +4174,7 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,

    /* Check whether the required permissions can be granted on @to, ignoring
     * all BdrvChild in @list so that they can't block themselves. */
    ret = bdrv_check_update_perm(to, NULL, perm, shared, list, errp);
    ret = bdrv_check_update_perm(to, NULL, perm, shared, list, NULL, errp);
    if (ret < 0) {
        bdrv_abort_perm_update(to);
        goto out;
@@ -4146,7 +4242,6 @@ out:

static void bdrv_delete(BlockDriverState *bs)
{
    assert(!bs->job);
    assert(bdrv_op_blocker_is_empty(bs));
    assert(!bs->refcnt);

@@ -4426,7 +4521,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
        /* Check whether we are allowed to switch c from top to base */
        GSList *ignore_children = g_slist_prepend(NULL, c);
        ret = bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm,
                                     ignore_children, &local_err);
                                     ignore_children, NULL, &local_err);
        g_slist_free(ignore_children);
        if (ret < 0) {
            error_report_err(local_err);
@@ -5201,7 +5296,7 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
     */
    bs->open_flags &= ~BDRV_O_INACTIVE;
    bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
    ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &local_err);
    ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, &local_err);
    if (ret < 0) {
        bs->open_flags |= BDRV_O_INACTIVE;
        error_propagate(errp, local_err);
@@ -5315,6 +5410,7 @@ static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active)
static int bdrv_inactivate_recurse(BlockDriverState *bs)
{
    BdrvChild *child, *parent;
    bool tighten_restrictions;
    uint64_t perm, shared_perm;
    int ret;

@@ -5351,8 +5447,15 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs)

    /* Update permissions, they may differ for inactive nodes */
    bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
    bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &error_abort);
    ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL,
                          &tighten_restrictions, NULL);
    assert(tighten_restrictions == false);
    if (ret < 0) {
        /* We only tried to loosen restrictions, so errors are not fatal */
        bdrv_abort_perm_update(bs);
    } else {
        bdrv_set_perm(bs, perm, shared_perm);
    }


    /* Recursively inactivate children */
+0 −4
Original line number Diff line number Diff line
@@ -1073,11 +1073,7 @@ void blk_iostatus_disable(BlockBackend *blk)
void blk_iostatus_reset(BlockBackend *blk)
{
    if (blk_iostatus_is_enabled(blk)) {
        BlockDriverState *bs = blk_bs(blk);
        blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
        if (bs && bs->job) {
            block_job_iostatus_reset(bs->job);
        }
    }
}

+0 −2
Original line number Diff line number Diff line
@@ -110,8 +110,6 @@ static void commit_abort(Job *job)
     * XXX Can (or should) we somehow keep 'consistent read' blocked even
     * after the failed/cancelled commit job is gone? If we already wrote
     * something to base, the intermediate images aren't valid any more. */
    bdrv_child_try_set_perm(s->commit_top_bs->backing, 0, BLK_PERM_ALL,
                            &error_abort);
    bdrv_replace_node(s->commit_top_bs, backing_bs(s->commit_top_bs),
                      &error_abort);

+4 −0
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ typedef struct BDRVRawState {
    uint64_t locked_shared_perm;

    int perm_change_fd;
    int perm_change_flags;
    BDRVReopenState *reopen_state;

#ifdef CONFIG_XFS
@@ -2788,6 +2789,7 @@ static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared,
        assert(s->reopen_state->shared_perm == shared);
        rs = s->reopen_state->opaque;
        s->perm_change_fd = rs->fd;
        s->perm_change_flags = rs->open_flags;
    } else {
        /* We may need a new fd if auto-read-only switches the mode */
        ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags, perm,
@@ -2796,6 +2798,7 @@ static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared,
            return ret;
        } else if (ret != s->fd) {
            s->perm_change_fd = ret;
            s->perm_change_flags = open_flags;
        }
    }

@@ -2834,6 +2837,7 @@ static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
    if (s->perm_change_fd && s->fd != s->perm_change_fd) {
        qemu_close(s->fd);
        s->fd = s->perm_change_fd;
        s->open_flags = s->perm_change_flags;
    }
    s->perm_change_fd = 0;

+45 −25
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) {
@@ -1482,7 +1495,8 @@ static BlockDriver bdrv_mirror_top = {
    .bdrv_child_perm            = bdrv_mirror_top_child_perm,
};

static void mirror_start_job(const char *job_id, BlockDriverState *bs,
static BlockJob *mirror_start_job(
                             const char *job_id, BlockDriverState *bs,
                             int creation_flags, BlockDriverState *target,
                             const char *replaces, int64_t speed,
                             uint32_t granularity, int64_t buf_size,
@@ -1514,7 +1528,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,

    if (buf_size < 0) {
        error_setg(errp, "Invalid parameter 'buf-size'");
        return;
        return NULL;
    }

    if (buf_size == 0) {
@@ -1523,7 +1537,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,

    if (bs == target) {
        error_setg(errp, "Can't mirror node into itself");
        return;
        return NULL;
    }

    /* In the case of active commit, add dummy driver to provide consistent
@@ -1532,7 +1546,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
    mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, filter_node_name,
                                         BDRV_O_RDWR, errp);
    if (mirror_top_bs == NULL) {
        return;
        return NULL;
    }
    if (!filter_node_name) {
        mirror_top_bs->implicit = true;
@@ -1554,7 +1568,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
    if (local_err) {
        bdrv_unref(mirror_top_bs);
        error_propagate(errp, local_err);
        return;
        return NULL;
    }

    /* Make sure that the source is not resized while the job is running */
@@ -1662,7 +1676,8 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,

    trace_mirror_start(bs, s, opaque);
    job_start(&s->common.job);
    return;

    return &s->common;

fail:
    if (s) {
@@ -1679,11 +1694,14 @@ 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);

    bdrv_unref(mirror_top_bs);

    return NULL;
}

void mirror_start(const char *job_id, BlockDriverState *bs,
@@ -1712,7 +1730,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
                     filter_node_name, true, copy_mode, errp);
}

void commit_active_start(const char *job_id, BlockDriverState *bs,
BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
                              BlockDriverState *base, int creation_flags,
                              int64_t speed, BlockdevOnError on_error,
                              const char *filter_node_name,
@@ -1721,16 +1739,18 @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
{
    bool base_read_only;
    Error *local_err = NULL;
    BlockJob *ret;

    base_read_only = bdrv_is_read_only(base);

    if (base_read_only) {
        if (bdrv_reopen_set_read_only(base, false, errp) < 0) {
            return;
            return NULL;
        }
    }

    mirror_start_job(job_id, bs, creation_flags, base, NULL, speed, 0, 0,
    ret = mirror_start_job(
                     job_id, bs, creation_flags, base, NULL, speed, 0, 0,
                     MIRROR_LEAVE_BACKING_CHAIN,
                     on_error, on_error, true, cb, opaque,
                     &commit_active_job_driver, false, base, auto_complete,
@@ -1741,7 +1761,7 @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
        goto error_restore_flags;
    }

    return;
    return ret;

error_restore_flags:
    /* ignore error and errp for bdrv_reopen, because we want to propagate
@@ -1749,5 +1769,5 @@ error_restore_flags:
    if (base_read_only) {
        bdrv_reopen_set_read_only(base, true, NULL);
    }
    return;
    return NULL;
}
Loading