Commit 067acf28 authored by Kevin Wolf's avatar Kevin Wolf
Browse files

block: Fix blockdev-snapshot error handling



For blockdev-snapshot, external_snapshot_prepare() accepts an arbitrary
node reference at first and only checks later whether it already has a
backing file. Between those places, other errors can occur.

Therefore checking in external_snapshot_abort() whether state->new_bs
has a backing file is not sufficient to tell whether bdrv_append() was
already completed or not. Trying to undo the bdrv_append() when it
wasn't even executed is wrong.

Introduce a new boolean flag in the state to fix this.

Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
Reviewed-by: default avatarFam Zheng <famz@redhat.com>
Reviewed-by: default avatarEric Blake <eblake@redhat.com>
parent 88f9d1b3
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -1614,6 +1614,7 @@ typedef struct ExternalSnapshotState {
    BlockDriverState *old_bs;
    BlockDriverState *new_bs;
    AioContext *aio_context;
    bool overlay_appended;
} ExternalSnapshotState;

static void external_snapshot_prepare(BlkActionState *common,
@@ -1780,6 +1781,7 @@ static void external_snapshot_prepare(BlkActionState *common,
        error_propagate(errp, local_err);
        return;
    }
    state->overlay_appended = true;
}

static void external_snapshot_commit(BlkActionState *common)
@@ -1803,7 +1805,7 @@ static void external_snapshot_abort(BlkActionState *common)
    ExternalSnapshotState *state =
                             DO_UPCAST(ExternalSnapshotState, common, common);
    if (state->new_bs) {
        if (state->new_bs->backing) {
        if (state->overlay_appended) {
            bdrv_replace_in_backing_chain(state->new_bs, state->old_bs);
        }
    }