X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=blockdev.c;h=c5b2c2c209223d6521261df2c265d1f929529ab2;hb=142b9ca51d7260d20f6e87bd7f2020ac0a7d95d9;hp=ff781d9df32b4017afbb0f17b8df960c1ca0a652;hpb=0db832f42e445398b2815cd740e9cd915e7dd644;p=mirror_qemu.git diff --git a/blockdev.c b/blockdev.c index ff781d9df3..c5b2c2c209 100644 --- a/blockdev.c +++ b/blockdev.c @@ -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, @@ -1768,7 +1769,19 @@ static void external_snapshot_prepare(BlkActionState *common, if (!state->new_bs->drv->supports_backing) { error_setg(errp, "The snapshot does not support backing images"); + return; + } + + /* This removes our old bs and adds the new bs. This is an operation that + * can fail, so we need to do it in .prepare; undoing it for abort is + * always possible. */ + bdrv_ref(state->new_bs); + bdrv_append(state->new_bs, state->old_bs, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; } + state->overlay_appended = true; } static void external_snapshot_commit(BlkActionState *common) @@ -1778,8 +1791,6 @@ static void external_snapshot_commit(BlkActionState *common) bdrv_set_aio_context(state->new_bs, state->aio_context); - /* This removes our old bs and adds the new bs */ - bdrv_append(state->new_bs, state->old_bs); /* We don't need (or want) to use the transactional * bdrv_reopen_multiple() across all the entries at once, because we * don't want to abort all of them if one of them fails the reopen */ @@ -1794,7 +1805,9 @@ static void external_snapshot_abort(BlkActionState *common) ExternalSnapshotState *state = DO_UPCAST(ExternalSnapshotState, common, common); if (state->new_bs) { - bdrv_unref(state->new_bs); + if (state->overlay_appended) { + bdrv_replace_node(state->new_bs, state->old_bs, &error_abort); + } } } @@ -1805,6 +1818,7 @@ static void external_snapshot_clean(BlkActionState *common) if (state->aio_context) { bdrv_drained_end(state->old_bs); aio_context_release(state->aio_context); + bdrv_unref(state->new_bs); } } @@ -2033,7 +2047,9 @@ static void block_dirty_bitmap_clear_abort(BlkActionState *common) BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, common, common); - bdrv_undo_clear_dirty_bitmap(state->bitmap, state->backup); + if (state->backup) { + bdrv_undo_clear_dirty_bitmap(state->bitmap, state->backup); + } } static void block_dirty_bitmap_clear_commit(BlkActionState *common)