Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx> --- src/qemu/qemu_checkpoint.c | 185 ++++++++++++++++++++++++++++++++++--- src/qemu/qemu_checkpoint.h | 5 + src/qemu/qemu_domain.c | 162 +------------------------------- src/qemu/qemu_domain.h | 15 --- 4 files changed, 180 insertions(+), 187 deletions(-) diff --git a/src/qemu/qemu_checkpoint.c b/src/qemu/qemu_checkpoint.c index 9e9af76871..22f0ffb26e 100644 --- a/src/qemu/qemu_checkpoint.c +++ b/src/qemu/qemu_checkpoint.c @@ -76,6 +76,169 @@ qemuCheckpointObjFromCheckpoint(virDomainObjPtr vm, } +static int +qemuCheckpointWriteMetadata(virDomainObjPtr vm, + virDomainMomentObjPtr checkpoint, + virCapsPtr caps, + virDomainXMLOptionPtr xmlopt, + const char *checkpointDir) +{ + unsigned int flags = VIR_DOMAIN_CHECKPOINT_FORMAT_SECURE; + virDomainCheckpointDefPtr def = virDomainCheckpointObjGetDef(checkpoint); + VIR_AUTOFREE(char *) newxml = NULL; + VIR_AUTOFREE(char *) chkDir = NULL; + VIR_AUTOFREE(char *) chkFile = NULL; + + newxml = virDomainCheckpointDefFormat(def, caps, xmlopt, flags); + if (newxml == NULL) + return -1; + + if (virAsprintf(&chkDir, "%s/%s", checkpointDir, vm->def->name) < 0) + return -1; + if (virFileMakePath(chkDir) < 0) { + virReportSystemError(errno, _("cannot create checkpoint directory '%s'"), + chkDir); + return -1; + } + + if (virAsprintf(&chkFile, "%s/%s.xml", chkDir, def->parent.name) < 0) + return -1; + + return virXMLSaveFile(chkFile, NULL, "checkpoint-edit", newxml); +} + + +static int +qemuDomainCheckpointDiscard(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainMomentObjPtr chk, + bool update_parent, + bool metadata_only) +{ + virDomainMomentObjPtr parent = NULL; + virDomainMomentObjPtr moment; + virDomainCheckpointDefPtr parentdef = NULL; + size_t i, j; + VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver); + VIR_AUTOFREE(char *) chkFile = NULL; + + if (!metadata_only && !virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("cannot remove checkpoint from inactive domain")); + return -1; + } + + if (virAsprintf(&chkFile, "%s/%s/%s.xml", cfg->checkpointDir, + vm->def->name, chk->def->name) < 0) + return -1; + + if (!metadata_only) { + qemuDomainObjPrivatePtr priv = vm->privateData; + bool success = true; + bool search_parents; + virDomainCheckpointDefPtr chkdef = virDomainCheckpointObjGetDef(chk); + + qemuDomainObjEnterMonitor(driver, vm); + parent = virDomainCheckpointFindByName(vm->checkpoints, + chk->def->parent_name); + for (i = 0; i < chkdef->ndisks; i++) { + virDomainCheckpointDiskDef *disk = &chkdef->disks[i]; + const char *node; + + if (disk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP) + continue; + + node = qemuDomainDiskNodeFormatLookup(vm, disk->name); + /* If any ancestor checkpoint has a bitmap for the same + * disk, then this bitmap must be merged to the + * ancestor. */ + search_parents = true; + for (moment = parent; + search_parents && moment; + moment = virDomainCheckpointFindByName(vm->checkpoints, + parentdef->parent.parent_name)) { + parentdef = virDomainCheckpointObjGetDef(moment); + for (j = 0; j < parentdef->ndisks; j++) { + virDomainCheckpointDiskDef *disk2; + VIR_AUTOPTR(virJSONValue) arr = NULL; + + disk2 = &parentdef->disks[j]; + if (STRNEQ(disk->name, disk2->name) || + disk2->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP) + continue; + search_parents = false; + + arr = virJSONValueNewArray(); + if (!arr || + virJSONValueArrayAppendString(arr, disk->bitmap) < 0) { + success = false; + break; + } + if (chk == virDomainCheckpointGetCurrent(vm->checkpoints) && + qemuMonitorEnableBitmap(priv->mon, node, + disk2->bitmap) < 0) { + success = false; + break; + } + if (qemuMonitorMergeBitmaps(priv->mon, node, + disk2->bitmap, &arr) < 0) { + success = false; + break; + } + } + } + if (qemuMonitorDeleteBitmap(priv->mon, node, disk->bitmap) < 0) { + success = false; + break; + } + } + if (qemuDomainObjExitMonitor(driver, vm) < 0 || !success) + return -1; + } + + if (chk == virDomainCheckpointGetCurrent(vm->checkpoints)) { + virDomainCheckpointSetCurrent(vm->checkpoints, NULL); + if (update_parent && parent) { + virDomainCheckpointSetCurrent(vm->checkpoints, parent); + if (qemuCheckpointWriteMetadata(vm, parent, driver->caps, + driver->xmlopt, + cfg->checkpointDir) < 0) { + VIR_WARN("failed to set parent checkpoint '%s' as current", + chk->def->parent_name); + virDomainCheckpointSetCurrent(vm->checkpoints, NULL); + } + } + } + + if (unlink(chkFile) < 0) + VIR_WARN("Failed to unlink %s", chkFile); + if (update_parent) + virDomainMomentDropParent(chk); + virDomainCheckpointObjListRemove(vm->checkpoints, chk); + + return 0; +} + + +int +qemuDomainCheckpointDiscardAllMetadata(virQEMUDriverPtr driver, + virDomainObjPtr vm) +{ + virQEMUMomentRemove rem = { + .driver = driver, + .vm = vm, + .metadata_only = true, + .momentDiscard = qemuDomainCheckpointDiscard, + }; + + virDomainCheckpointForEach(vm->checkpoints, qemuDomainMomentDiscardAll, + &rem); + virDomainCheckpointObjListRemoveAll(vm->checkpoints); + + return rem.err; +} + + /* Called inside job lock */ static int qemuDomainCheckpointPrepare(virQEMUDriverPtr driver, virCapsPtr caps, @@ -267,9 +430,9 @@ qemuCheckpointCreateXML(virDomainPtr domain, goto endjob; if (update_current) { virDomainCheckpointSetCurrent(vm->checkpoints, NULL); - if (qemuDomainCheckpointWriteMetadata(vm, other, - driver->caps, driver->xmlopt, - cfg->checkpointDir) < 0) + if (qemuCheckpointWriteMetadata(vm, other, + driver->caps, driver->xmlopt, + cfg->checkpointDir) < 0) goto endjob; } } @@ -301,9 +464,9 @@ qemuCheckpointCreateXML(virDomainPtr domain, if (checkpoint) { if (update_current) virDomainCheckpointSetCurrent(vm->checkpoints, chk); - if (qemuDomainCheckpointWriteMetadata(vm, chk, driver->caps, - driver->xmlopt, - cfg->checkpointDir) < 0) { + if (qemuCheckpointWriteMetadata(vm, chk, driver->caps, + driver->xmlopt, + cfg->checkpointDir) < 0) { /* if writing of metadata fails, error out rather than trying * to silently carry on without completing the checkpoint */ virObjectUnref(checkpoint); @@ -384,8 +547,8 @@ qemuCheckpointReparentChildren(void *payload, return 0; } - rep->err = qemuDomainCheckpointWriteMetadata(rep->vm, moment, rep->caps, - rep->xmlopt, rep->dir); + rep->err = qemuCheckpointWriteMetadata(rep->vm, moment, rep->caps, + rep->xmlopt, rep->dir); return 0; } @@ -445,9 +608,9 @@ qemuCheckpointDelete(virDomainObjPtr vm, if (rem.found) { virDomainCheckpointSetCurrent(vm->checkpoints, chk); if (flags & VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN_ONLY) { - if (qemuDomainCheckpointWriteMetadata(vm, chk, driver->caps, - driver->xmlopt, - cfg->checkpointDir) < 0) { + if (qemuCheckpointWriteMetadata(vm, chk, driver->caps, + driver->xmlopt, + cfg->checkpointDir) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to set checkpoint '%s' as current"), chk->def->name); diff --git a/src/qemu/qemu_checkpoint.h b/src/qemu/qemu_checkpoint.h index 0d36d718d6..4cea4bcdb4 100644 --- a/src/qemu/qemu_checkpoint.h +++ b/src/qemu/qemu_checkpoint.h @@ -20,6 +20,7 @@ #include "virconftypes.h" #include "datatypes.h" +#include "qemu_conf.h" virDomainObjPtr qemuDomObjFromCheckpoint(virDomainCheckpointPtr checkpoint); @@ -32,6 +33,10 @@ virDomainMomentObjPtr qemuCheckpointObjFromName(virDomainObjPtr vm, const char *name); +int +qemuDomainCheckpointDiscardAllMetadata(virQEMUDriverPtr driver, + virDomainObjPtr vm); + virDomainCheckpointPtr qemuCheckpointCreateXML(virDomainPtr domain, virDomainObjPtr vm, diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index e8e895d9aa..19fa5420e7 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -35,6 +35,7 @@ #include "qemu_slirp.h" #include "qemu_extdevice.h" #include "qemu_blockjob.h" +#include "qemu_checkpoint.h" #include "viralloc.h" #include "virlog.h" #include "virerror.h" @@ -9600,36 +9601,6 @@ qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm, return ret; } -int -qemuDomainCheckpointWriteMetadata(virDomainObjPtr vm, - virDomainMomentObjPtr checkpoint, - virCapsPtr caps, - virDomainXMLOptionPtr xmlopt, - const char *checkpointDir) -{ - unsigned int flags = VIR_DOMAIN_CHECKPOINT_FORMAT_SECURE; - virDomainCheckpointDefPtr def = virDomainCheckpointObjGetDef(checkpoint); - VIR_AUTOFREE(char *) newxml = NULL; - VIR_AUTOFREE(char *) chkDir = NULL; - VIR_AUTOFREE(char *) chkFile = NULL; - - newxml = virDomainCheckpointDefFormat(def, caps, xmlopt, flags); - if (newxml == NULL) - return -1; - - if (virAsprintf(&chkDir, "%s/%s", checkpointDir, vm->def->name) < 0) - return -1; - if (virFileMakePath(chkDir) < 0) { - virReportSystemError(errno, _("cannot create checkpoint directory '%s'"), - chkDir); - return -1; - } - - if (virAsprintf(&chkFile, "%s/%s.xml", chkDir, def->parent.name) < 0) - return -1; - - return virXMLSaveFile(chkFile, NULL, "checkpoint-edit", newxml); -} /* The domain is expected to be locked and inactive. Return -1 on normal * failure, 1 if we skipped a disk due to try_all. */ @@ -9827,137 +9798,6 @@ qemuDomainSnapshotDiscardAllMetadata(virQEMUDriverPtr driver, } -/* Discard one checkpoint (or its metadata), without reparenting any children. */ -int -qemuDomainCheckpointDiscard(virQEMUDriverPtr driver, - virDomainObjPtr vm, - virDomainMomentObjPtr chk, - bool update_parent, - bool metadata_only) -{ - virDomainMomentObjPtr parent = NULL; - virDomainMomentObjPtr moment; - virDomainCheckpointDefPtr parentdef = NULL; - size_t i, j; - VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver); - VIR_AUTOFREE(char *) chkFile = NULL; - - if (!metadata_only && !virDomainObjIsActive(vm)) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("cannot remove checkpoint from inactive domain")); - return -1; - } - - if (virAsprintf(&chkFile, "%s/%s/%s.xml", cfg->checkpointDir, - vm->def->name, chk->def->name) < 0) - return -1; - - if (!metadata_only) { - qemuDomainObjPrivatePtr priv = vm->privateData; - bool success = true; - bool search_parents; - virDomainCheckpointDefPtr chkdef = virDomainCheckpointObjGetDef(chk); - - qemuDomainObjEnterMonitor(driver, vm); - parent = virDomainCheckpointFindByName(vm->checkpoints, - chk->def->parent_name); - for (i = 0; i < chkdef->ndisks; i++) { - virDomainCheckpointDiskDef *disk = &chkdef->disks[i]; - const char *node; - - if (disk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP) - continue; - - node = qemuDomainDiskNodeFormatLookup(vm, disk->name); - /* If any ancestor checkpoint has a bitmap for the same - * disk, then this bitmap must be merged to the - * ancestor. */ - search_parents = true; - for (moment = parent; - search_parents && moment; - moment = virDomainCheckpointFindByName(vm->checkpoints, - parentdef->parent.parent_name)) { - parentdef = virDomainCheckpointObjGetDef(moment); - for (j = 0; j < parentdef->ndisks; j++) { - virDomainCheckpointDiskDef *disk2; - VIR_AUTOPTR(virJSONValue) arr = NULL; - - disk2 = &parentdef->disks[j]; - if (STRNEQ(disk->name, disk2->name) || - disk2->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP) - continue; - search_parents = false; - - arr = virJSONValueNewArray(); - if (!arr || - virJSONValueArrayAppendString(arr, disk->bitmap) < 0) { - success = false; - break; - } - if (chk == virDomainCheckpointGetCurrent(vm->checkpoints) && - qemuMonitorEnableBitmap(priv->mon, node, - disk2->bitmap) < 0) { - success = false; - break; - } - if (qemuMonitorMergeBitmaps(priv->mon, node, - disk2->bitmap, &arr) < 0) { - success = false; - break; - } - } - } - if (qemuMonitorDeleteBitmap(priv->mon, node, disk->bitmap) < 0) { - success = false; - break; - } - } - if (qemuDomainObjExitMonitor(driver, vm) < 0 || !success) - return -1; - } - - if (chk == virDomainCheckpointGetCurrent(vm->checkpoints)) { - virDomainCheckpointSetCurrent(vm->checkpoints, NULL); - if (update_parent && parent) { - virDomainCheckpointSetCurrent(vm->checkpoints, parent); - if (qemuDomainCheckpointWriteMetadata(vm, parent, driver->caps, - driver->xmlopt, - cfg->checkpointDir) < 0) { - VIR_WARN("failed to set parent checkpoint '%s' as current", - chk->def->parent_name); - virDomainCheckpointSetCurrent(vm->checkpoints, NULL); - } - } - } - - if (unlink(chkFile) < 0) - VIR_WARN("Failed to unlink %s", chkFile); - if (update_parent) - virDomainMomentDropParent(chk); - virDomainCheckpointObjListRemove(vm->checkpoints, chk); - - return 0; -} - -int -qemuDomainCheckpointDiscardAllMetadata(virQEMUDriverPtr driver, - virDomainObjPtr vm) -{ - virQEMUMomentRemove rem = { - .driver = driver, - .vm = vm, - .metadata_only = true, - .momentDiscard = qemuDomainCheckpointDiscard, - }; - - virDomainCheckpointForEach(vm->checkpoints, qemuDomainMomentDiscardAll, - &rem); - virDomainCheckpointObjListRemoveAll(vm->checkpoints); - - return rem.err; -} - - static void qemuDomainRemoveInactiveCommon(virQEMUDriverPtr driver, virDomainObjPtr vm) diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index c740bb955a..f45da882a8 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -792,21 +792,6 @@ int qemuDomainMomentDiscardAll(void *payload, int qemuDomainSnapshotDiscardAllMetadata(virQEMUDriverPtr driver, virDomainObjPtr vm); -int qemuDomainCheckpointWriteMetadata(virDomainObjPtr vm, - virDomainMomentObjPtr checkpoint, - virCapsPtr caps, - virDomainXMLOptionPtr xmlopt, - const char *checkpointDir); - -int qemuDomainCheckpointDiscard(virQEMUDriverPtr driver, - virDomainObjPtr vm, - virDomainMomentObjPtr chk, - bool update_current, - bool metadata_only); - -int qemuDomainCheckpointDiscardAllMetadata(virQEMUDriverPtr driver, - virDomainObjPtr vm); - void qemuDomainRemoveInactive(virQEMUDriverPtr driver, virDomainObjPtr vm); -- 2.21.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list