From a4877192a1cc6ba1a5975010d8efa84fac5d1845 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Mon, 6 Jan 2020 15:32:54 +0100 Subject: [PATCH] qemu: backup: roll-back checkpoint metadata if the checkpoint wasn't taken MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We insert the checkpoint metadata into the list of checkpoints prior to actually creating the on-disk bits. If the 'transaction' or any other steps done between inserting the checkpoint and creating the on-disk data fail we'd end up with an unusable checkpoint that would vanish after libvirtd restart. Prevent this by rolling back the metadata if we didn't actually take and record the checkpoint. Signed-off-by: Peter Krempa Reviewed-by: Daniel P. Berrangé --- src/qemu/qemu_backup.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_backup.c b/src/qemu/qemu_backup.c index c0445e0869..e7358082d5 100644 --- a/src/qemu/qemu_backup.c +++ b/src/qemu/qemu_backup.c @@ -812,6 +812,8 @@ qemuBackupBegin(virDomainObjPtr vm, if (!(actions = virJSONValueNewArray())) goto endjob; + /* The 'chk' checkpoint must be rolled back if the transaction command + * which creates it on disk is not executed or fails */ if (chkdef) { if (qemuCheckpointCreateCommon(priv->driver, vm, &chkdef, &actions, &chk) < 0) @@ -857,9 +859,11 @@ qemuBackupBegin(virDomainObjPtr vm, job_started = true; qemuBackupDiskStarted(vm, dd, ndd); - if (chk && - qemuCheckpointCreateFinalize(priv->driver, vm, cfg, chk, true) < 0) - goto endjob; + if (chk) { + virDomainMomentObjPtr tmpchk = g_steal_pointer(&chk); + if (qemuCheckpointCreateFinalize(priv->driver, vm, cfg, tmpchk, true) < 0) + goto endjob; + } if (pull) { if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, QEMU_ASYNC_JOB_BACKUP) < 0) @@ -880,6 +884,10 @@ qemuBackupBegin(virDomainObjPtr vm, endjob: qemuBackupDiskDataCleanup(vm, dd, ndd); + + /* if 'chk' is non-NULL here it's a failure and it must be rolled back */ + qemuCheckpointRollbackMetadata(vm, chk); + if (!job_started && nbd_running && qemuDomainObjEnterMonitorAsync(priv->driver, vm, QEMU_ASYNC_JOB_BACKUP) < 0) { ignore_value(qemuMonitorNBDServerStop(priv->mon));