These functions mostly used from the qemu_snapshot.c and also
semantically they belong to this source file.
At the same time rename qemuDomainSnapshot* to qemuSnaphot*.
Signed-off-by: Nikolay Shirokovskiy <nikolay.shirokovskiy(a)openvz.org>
---
src/qemu/qemu_domain.c | 241 +----------------------------------
src/qemu/qemu_domain.h | 19 ---
src/qemu/qemu_driver.c | 8 +-
src/qemu/qemu_snapshot.c | 268 ++++++++++++++++++++++++++++++++++++---
src/qemu/qemu_snapshot.h | 10 ++
5 files changed, 269 insertions(+), 277 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 18d403e099..56cf0c3f68 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -38,6 +38,7 @@
#include "qemu_checkpoint.h"
#include "qemu_validate.h"
#include "qemu_namespace.h"
+#include "qemu_snapshot.h"
#include "viralloc.h"
#include "virlog.h"
#include "virerror.h"
@@ -64,7 +65,6 @@
#include "virsecret.h"
#include "logging/log_manager.h"
#include "locking/domain_lock.h"
-#include "virdomainsnapshotobjlist.h"
#include "virdomaincheckpointobjlist.h"
#include "backup_conf.h"
#include "virutil.h"
@@ -7041,243 +7041,6 @@ qemuFindQemuImgBinary(virQEMUDriver *driver)
return driver->qemuImgBinary;
}
-int
-qemuDomainSnapshotWriteMetadata(virDomainObj *vm,
- virDomainMomentObj *snapshot,
- virDomainXMLOption *xmlopt,
- const char *snapshotDir)
-{
- g_autofree char *newxml = NULL;
- g_autofree char *snapDir = NULL;
- g_autofree char *snapFile = NULL;
- char uuidstr[VIR_UUID_STRING_BUFLEN];
- unsigned int flags = VIR_DOMAIN_SNAPSHOT_FORMAT_SECURE |
- VIR_DOMAIN_SNAPSHOT_FORMAT_INTERNAL;
- virDomainSnapshotDef *def = virDomainSnapshotObjGetDef(snapshot);
-
- if (virDomainSnapshotGetCurrent(vm->snapshots) == snapshot)
- flags |= VIR_DOMAIN_SNAPSHOT_FORMAT_CURRENT;
- virUUIDFormat(vm->def->uuid, uuidstr);
- newxml = virDomainSnapshotDefFormat(uuidstr, def, xmlopt, flags);
- if (newxml == NULL)
- return -1;
-
- snapDir = g_strdup_printf("%s/%s", snapshotDir, vm->def->name);
- if (g_mkdir_with_parents(snapDir, 0777) < 0) {
- virReportSystemError(errno, _("cannot create snapshot directory
'%s'"),
- snapDir);
- return -1;
- }
-
- snapFile = g_strdup_printf("%s/%s.xml", snapDir, def->parent.name);
-
- return virXMLSaveFile(snapFile, NULL, "snapshot-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. */
-static int
-qemuDomainSnapshotForEachQcow2Raw(virQEMUDriver *driver,
- virDomainDef *def,
- virDomainMomentObj *snap,
- const char *op,
- bool try_all,
- int ndisks)
-{
- virDomainSnapshotDef *snapdef = virDomainSnapshotObjGetDef(snap);
- const char *qemuimgbin;
- size_t i;
- bool skipped = false;
-
- qemuimgbin = qemuFindQemuImgBinary(driver);
- if (qemuimgbin == NULL) {
- /* qemuFindQemuImgBinary set the error */
- return -1;
- }
-
- for (i = 0; i < ndisks; i++) {
- g_autoptr(virCommand) cmd = virCommandNewArgList(qemuimgbin,
"snapshot",
- op, snap->def->name,
NULL);
- int format = virDomainDiskGetFormat(def->disks[i]);
-
- /* FIXME: we also need to handle LVM here */
- if (def->disks[i]->device != VIR_DOMAIN_DISK_DEVICE_DISK ||
- snapdef->disks[i].snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL)
- continue;
-
- if (!virStorageSourceIsLocalStorage(def->disks[i]->src)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("can't manipulate inactive snapshots of disk
'%s'"),
- def->disks[i]->dst);
- return -1;
- }
-
- if (format > 0 && format != VIR_STORAGE_FILE_QCOW2) {
- if (try_all) {
- /* Continue on even in the face of error, since other
- * disks in this VM may have the same snapshot name.
- */
- VIR_WARN("skipping snapshot action on %s",
- def->disks[i]->dst);
- skipped = true;
- continue;
- } else if (STREQ(op, "-c") && i) {
- /* We must roll back partial creation by deleting
- * all earlier snapshots. */
- qemuDomainSnapshotForEachQcow2Raw(driver, def, snap,
- "-d", false, i);
- }
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("Disk device '%s' does not support
snapshotting"),
- def->disks[i]->dst);
- return -1;
- }
-
- virCommandAddArg(cmd, virDomainDiskGetSource(def->disks[i]));
-
- if (virCommandRun(cmd, NULL) < 0) {
- if (try_all) {
- VIR_WARN("skipping snapshot action on %s",
- def->disks[i]->dst);
- skipped = true;
- continue;
- } else if (STREQ(op, "-c") && i) {
- /* We must roll back partial creation by deleting
- * all earlier snapshots. */
- qemuDomainSnapshotForEachQcow2Raw(driver, def, snap,
- "-d", false, i);
- }
- return -1;
- }
- }
-
- return skipped ? 1 : 0;
-}
-
-/* The domain is expected to be locked and inactive. Return -1 on normal
- * failure, 1 if we skipped a disk due to try_all. */
-int
-qemuDomainSnapshotForEachQcow2(virQEMUDriver *driver,
- virDomainDef *def,
- virDomainMomentObj *snap,
- const char *op,
- bool try_all)
-{
- return qemuDomainSnapshotForEachQcow2Raw(driver, def, snap,
- op, try_all, def->ndisks);
-}
-
-/* Discard one snapshot (or its metadata), without reparenting any children. */
-int
-qemuDomainSnapshotDiscard(virQEMUDriver *driver,
- virDomainObj *vm,
- virDomainMomentObj *snap,
- bool update_parent,
- bool metadata_only)
-{
- g_autofree char *snapFile = NULL;
- qemuDomainObjPrivate *priv;
- virDomainMomentObj *parentsnap = NULL;
- g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
-
- if (!metadata_only) {
- if (!virDomainObjIsActive(vm)) {
- size_t i;
- /* Ignore any skipped disks */
-
- /* Prefer action on the disks in use at the time the snapshot was
- * created; but fall back to current definition if dealing with a
- * snapshot created prior to libvirt 0.9.5. */
- virDomainDef *def = snap->def->dom;
-
- if (!def)
- def = vm->def;
-
- for (i = 0; i < def->ndisks; i++) {
- if (virDomainDiskTranslateSourcePool(def->disks[i]) < 0)
- return -1;
- }
-
- if (qemuDomainSnapshotForEachQcow2(driver, def, snap, "-d", true)
< 0)
- return -1;
- } else {
- priv = vm->privateData;
- qemuDomainObjEnterMonitor(driver, vm);
- /* we continue on even in the face of error */
- qemuMonitorDeleteSnapshot(priv->mon, snap->def->name);
- qemuDomainObjExitMonitor(vm);
- }
- }
-
- snapFile = g_strdup_printf("%s/%s/%s.xml", cfg->snapshotDir,
vm->def->name,
- snap->def->name);
-
- if (snap == virDomainSnapshotGetCurrent(vm->snapshots)) {
- virDomainSnapshotSetCurrent(vm->snapshots, NULL);
- if (update_parent && snap->def->parent_name) {
- parentsnap = virDomainSnapshotFindByName(vm->snapshots,
- snap->def->parent_name);
- if (!parentsnap) {
- VIR_WARN("missing parent snapshot matching name '%s'",
- snap->def->parent_name);
- } else {
- virDomainSnapshotSetCurrent(vm->snapshots, parentsnap);
- if (qemuDomainSnapshotWriteMetadata(vm, parentsnap,
- driver->xmlopt,
- cfg->snapshotDir) < 0) {
- VIR_WARN("failed to set parent snapshot '%s' as
current",
- snap->def->parent_name);
- virDomainSnapshotSetCurrent(vm->snapshots, NULL);
- }
- }
- }
- }
-
- if (unlink(snapFile) < 0)
- VIR_WARN("Failed to unlink %s", snapFile);
- if (update_parent)
- virDomainMomentDropParent(snap);
- virDomainSnapshotObjListRemove(vm->snapshots, snap);
-
- return 0;
-}
-
-/* Hash iterator callback to discard multiple snapshots. */
-int qemuDomainMomentDiscardAll(void *payload,
- const char *name G_GNUC_UNUSED,
- void *data)
-{
- virDomainMomentObj *moment = payload;
- virQEMUMomentRemove *curr = data;
- int err;
-
- if (!curr->found && curr->current == moment)
- curr->found = true;
- err = curr->momentDiscard(curr->driver, curr->vm, moment, false,
- curr->metadata_only);
- if (err && !curr->err)
- curr->err = err;
- return 0;
-}
-
-int
-qemuDomainSnapshotDiscardAllMetadata(virQEMUDriver *driver,
- virDomainObj *vm)
-{
- virQEMUMomentRemove rem = {
- .driver = driver,
- .vm = vm,
- .metadata_only = true,
- .momentDiscard = qemuDomainSnapshotDiscard,
- };
-
- virDomainSnapshotForEach(vm->snapshots, qemuDomainMomentDiscardAll, &rem);
- virDomainSnapshotObjListRemoveAll(vm->snapshots);
-
- return rem.err;
-}
-
static void
qemuDomainRemoveInactiveCommon(virQEMUDriver *driver,
@@ -7288,7 +7051,7 @@ qemuDomainRemoveInactiveCommon(virQEMUDriver *driver,
g_autofree char *chkDir = NULL;
/* Remove any snapshot metadata prior to removing the domain */
- if (qemuDomainSnapshotDiscardAllMetadata(driver, vm) < 0) {
+ if (qemuSnapshotDiscardAllMetadata(driver, vm) < 0) {
VIR_WARN("unable to remove all snapshots for domain %s",
vm->def->name);
} else {
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index a41d8308e3..494a276212 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -633,22 +633,6 @@ int qemuDomainLogAppendMessage(virQEMUDriver *driver,
const char *qemuFindQemuImgBinary(virQEMUDriver *driver);
-int qemuDomainSnapshotWriteMetadata(virDomainObj *vm,
- virDomainMomentObj *snapshot,
- virDomainXMLOption *xmlopt,
- const char *snapshotDir);
-
-int qemuDomainSnapshotForEachQcow2(virQEMUDriver *driver,
- virDomainDef *def,
- virDomainMomentObj *snap,
- const char *op,
- bool try_all);
-
-int qemuDomainSnapshotDiscard(virQEMUDriver *driver,
- virDomainObj *vm,
- virDomainMomentObj *snap,
- bool update_current,
- bool metadata_only);
typedef struct _virQEMUMomentRemove virQEMUMomentRemove;
struct _virQEMUMomentRemove {
@@ -666,9 +650,6 @@ int qemuDomainMomentDiscardAll(void *payload,
const char *name,
void *data);
-int qemuDomainSnapshotDiscardAllMetadata(virQEMUDriver *driver,
- virDomainObj *vm);
-
void qemuDomainRemoveInactive(virQEMUDriver *driver,
virDomainObj *vm);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 77012eb527..74bc2c7bf4 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6568,7 +6568,7 @@ qemuDomainUndefineFlags(virDomainPtr dom,
nsnapshots);
goto endjob;
}
- if (qemuDomainSnapshotDiscardAllMetadata(driver, vm) < 0)
+ if (qemuSnapshotDiscardAllMetadata(driver, vm) < 0)
goto endjob;
}
if (!virDomainObjIsActive(vm) &&
@@ -19132,9 +19132,9 @@ qemuDomainSnapshotWriteMetadataIter(void *payload,
virQEMUDriverConfig *cfg = virQEMUDriverGetConfig(data->driver);
int ret;
- ret = qemuDomainSnapshotWriteMetadata(data->vm, payload,
- data->driver->xmlopt,
- cfg->snapshotDir);
+ ret = qemuSnapshotWriteMetadata(data->vm, payload,
+ data->driver->xmlopt,
+ cfg->snapshotDir);
virObjectUnref(cfg);
return ret;
diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c
index 5d622592c3..878a0abb34 100644
--- a/src/qemu/qemu_snapshot.c
+++ b/src/qemu/qemu_snapshot.c
@@ -49,6 +49,175 @@
VIR_LOG_INIT("qemu.qemu_snapshot");
+/* The domain is expected to be locked and inactive. Return -1 on normal
+ * failure, 1 if we skipped a disk due to try_all. */
+static int
+qemuSnapshotForEachQcow2Raw(virQEMUDriver *driver,
+ virDomainDef *def,
+ virDomainMomentObj *snap,
+ const char *op,
+ bool try_all,
+ int ndisks)
+{
+ virDomainSnapshotDef *snapdef = virDomainSnapshotObjGetDef(snap);
+ const char *qemuimgbin;
+ size_t i;
+ bool skipped = false;
+
+ qemuimgbin = qemuFindQemuImgBinary(driver);
+ if (qemuimgbin == NULL) {
+ /* qemuFindQemuImgBinary set the error */
+ return -1;
+ }
+
+ for (i = 0; i < ndisks; i++) {
+ g_autoptr(virCommand) cmd = virCommandNewArgList(qemuimgbin,
"snapshot",
+ op, snap->def->name,
NULL);
+ int format = virDomainDiskGetFormat(def->disks[i]);
+
+ /* FIXME: we also need to handle LVM here */
+ if (def->disks[i]->device != VIR_DOMAIN_DISK_DEVICE_DISK ||
+ snapdef->disks[i].snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL)
+ continue;
+
+ if (!virStorageSourceIsLocalStorage(def->disks[i]->src)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("can't manipulate inactive snapshots of disk
'%s'"),
+ def->disks[i]->dst);
+ return -1;
+ }
+
+ if (format > 0 && format != VIR_STORAGE_FILE_QCOW2) {
+ if (try_all) {
+ /* Continue on even in the face of error, since other
+ * disks in this VM may have the same snapshot name.
+ */
+ VIR_WARN("skipping snapshot action on %s",
+ def->disks[i]->dst);
+ skipped = true;
+ continue;
+ } else if (STREQ(op, "-c") && i) {
+ /* We must roll back partial creation by deleting
+ * all earlier snapshots. */
+ qemuSnapshotForEachQcow2Raw(driver, def, snap, "-d", false,
i);
+ }
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("Disk device '%s' does not support
snapshotting"),
+ def->disks[i]->dst);
+ return -1;
+ }
+
+ virCommandAddArg(cmd, virDomainDiskGetSource(def->disks[i]));
+
+ if (virCommandRun(cmd, NULL) < 0) {
+ if (try_all) {
+ VIR_WARN("skipping snapshot action on %s",
+ def->disks[i]->dst);
+ skipped = true;
+ continue;
+ } else if (STREQ(op, "-c") && i) {
+ /* We must roll back partial creation by deleting
+ * all earlier snapshots. */
+ qemuSnapshotForEachQcow2Raw(driver, def, snap, "-d", false,
i);
+ }
+ return -1;
+ }
+ }
+
+ return skipped ? 1 : 0;
+}
+
+
+/* The domain is expected to be locked and inactive. Return -1 on normal
+ * failure, 1 if we skipped a disk due to try_all. */
+static int
+qemuSnapshotForEachQcow2(virQEMUDriver *driver,
+ virDomainDef *def,
+ virDomainMomentObj *snap,
+ const char *op,
+ bool try_all)
+{
+ return qemuSnapshotForEachQcow2Raw(driver, def, snap,
+ op, try_all, def->ndisks);
+}
+
+
+/* Discard one snapshot (or its metadata), without reparenting any children. */
+static int
+qemuSnapshotDiscard(virQEMUDriver *driver,
+ virDomainObj *vm,
+ virDomainMomentObj *snap,
+ bool update_parent,
+ bool metadata_only)
+{
+ g_autofree char *snapFile = NULL;
+ qemuDomainObjPrivate *priv;
+ virDomainMomentObj *parentsnap = NULL;
+ g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+
+ if (!metadata_only) {
+ if (!virDomainObjIsActive(vm)) {
+ size_t i;
+ /* Ignore any skipped disks */
+
+ /* Prefer action on the disks in use at the time the snapshot was
+ * created; but fall back to current definition if dealing with a
+ * snapshot created prior to libvirt 0.9.5. */
+ virDomainDef *def = snap->def->dom;
+
+ if (!def)
+ def = vm->def;
+
+ for (i = 0; i < def->ndisks; i++) {
+ if (virDomainDiskTranslateSourcePool(def->disks[i]) < 0)
+ return -1;
+ }
+
+ if (qemuSnapshotForEachQcow2(driver, def, snap, "-d", true) <
0)
+ return -1;
+ } else {
+ priv = vm->privateData;
+ qemuDomainObjEnterMonitor(driver, vm);
+ /* we continue on even in the face of error */
+ qemuMonitorDeleteSnapshot(priv->mon, snap->def->name);
+ qemuDomainObjExitMonitor(vm);
+ }
+ }
+
+ snapFile = g_strdup_printf("%s/%s/%s.xml", cfg->snapshotDir,
vm->def->name,
+ snap->def->name);
+
+ if (snap == virDomainSnapshotGetCurrent(vm->snapshots)) {
+ virDomainSnapshotSetCurrent(vm->snapshots, NULL);
+ if (update_parent && snap->def->parent_name) {
+ parentsnap = virDomainSnapshotFindByName(vm->snapshots,
+ snap->def->parent_name);
+ if (!parentsnap) {
+ VIR_WARN("missing parent snapshot matching name '%s'",
+ snap->def->parent_name);
+ } else {
+ virDomainSnapshotSetCurrent(vm->snapshots, parentsnap);
+ if (qemuSnapshotWriteMetadata(vm, parentsnap,
+ driver->xmlopt,
+ cfg->snapshotDir) < 0) {
+ VIR_WARN("failed to set parent snapshot '%s' as
current",
+ snap->def->parent_name);
+ virDomainSnapshotSetCurrent(vm->snapshots, NULL);
+ }
+ }
+ }
+ }
+
+ if (unlink(snapFile) < 0)
+ VIR_WARN("Failed to unlink %s", snapFile);
+ if (update_parent)
+ virDomainMomentDropParent(snap);
+ virDomainSnapshotObjListRemove(vm->snapshots, snap);
+
+ return 0;
+}
+
+
/**
* qemuSnapshotSetCurrent: Set currently active snapshot
*
@@ -73,7 +242,7 @@ qemuSnapshotSetCurrent(virDomainObj *vm,
* 'active' property */
if (oldcurrent &&
oldcurrent != newcurrent) {
- if (qemuDomainSnapshotWriteMetadata(vm, oldcurrent, driver->xmlopt,
cfg->snapshotDir) < 0)
+ if (qemuSnapshotWriteMetadata(vm, oldcurrent, driver->xmlopt,
cfg->snapshotDir) < 0)
VIR_WARN("failed to update old current snapshot");
}
}
@@ -167,7 +336,7 @@ qemuSnapshotCreateInactiveInternal(virQEMUDriver *driver,
virDomainObj *vm,
virDomainMomentObj *snap)
{
- return qemuDomainSnapshotForEachQcow2(driver, vm->def, snap, "-c",
false);
+ return qemuSnapshotForEachQcow2(driver, vm->def, snap, "-c", false);
}
@@ -1691,9 +1860,8 @@ qemuSnapshotCreateWriteMetadata(virDomainObj *vm,
virQEMUDriver *driver,
virQEMUDriverConfig *cfg)
{
- if (qemuDomainSnapshotWriteMetadata(vm, snap,
- driver->xmlopt,
- cfg->snapshotDir) < 0) {
+ if (qemuSnapshotWriteMetadata(vm, snap, driver->xmlopt,
+ cfg->snapshotDir) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unable to save metadata for snapshot %s"),
snap->def->name);
@@ -2005,9 +2173,8 @@ qemuSnapshotRevertWriteMetadata(virDomainObj *vm,
bool defined)
{
qemuSnapshotSetCurrent(vm, snap);
- if (qemuDomainSnapshotWriteMetadata(vm, snap,
- driver->xmlopt,
- cfg->snapshotDir) < 0) {
+ if (qemuSnapshotWriteMetadata(vm, snap, driver->xmlopt,
+ cfg->snapshotDir) < 0) {
virDomainSnapshotSetCurrent(vm->snapshots, NULL);
return -1;
}
@@ -2146,7 +2313,7 @@ qemuSnapshotInternalRevertInactive(virQEMUDriver *driver,
}
/* Try all disks, but report failure if we skipped any. */
- if (qemuDomainSnapshotForEachQcow2(driver, def, snap, "-a", true) != 0)
+ if (qemuSnapshotForEachQcow2(driver, def, snap, "-a", true) != 0)
return -1;
return 0;
@@ -2415,7 +2582,7 @@ qemuSnapshotDelete(virDomainObj *vm,
rem.err = 0;
rem.current = virDomainSnapshotGetCurrent(vm->snapshots);
rem.found = false;
- rem.momentDiscard = qemuDomainSnapshotDiscard;
+ rem.momentDiscard = qemuSnapshotDiscard;
virDomainMomentForEachDescendant(snap, qemuDomainMomentDiscardAll,
&rem);
if (rem.err < 0)
@@ -2424,9 +2591,8 @@ qemuSnapshotDelete(virDomainObj *vm,
qemuSnapshotSetCurrent(vm, snap);
if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
- if (qemuDomainSnapshotWriteMetadata(vm, snap,
- driver->xmlopt,
- cfg->snapshotDir) < 0) {
+ if (qemuSnapshotWriteMetadata(vm, snap, driver->xmlopt,
+ cfg->snapshotDir) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to set snapshot '%s' as
current"),
snap->def->name);
@@ -2441,7 +2607,7 @@ qemuSnapshotDelete(virDomainObj *vm,
rep.vm = vm;
rep.err = 0;
rep.xmlopt = driver->xmlopt;
- rep.writeMetadata = qemuDomainSnapshotWriteMetadata;
+ rep.writeMetadata = qemuSnapshotWriteMetadata;
virDomainMomentForEachChild(snap,
qemuSnapshotChildrenReparent,
&rep);
@@ -2454,7 +2620,7 @@ qemuSnapshotDelete(virDomainObj *vm,
virDomainMomentDropChildren(snap);
ret = 0;
} else {
- ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
+ ret = qemuSnapshotDiscard(driver, vm, snap, true, metadata_only);
}
endjob:
@@ -2462,3 +2628,75 @@ qemuSnapshotDelete(virDomainObj *vm,
return ret;
}
+
+
+int
+qemuSnapshotWriteMetadata(virDomainObj *vm,
+ virDomainMomentObj *snapshot,
+ virDomainXMLOption *xmlopt,
+ const char *snapshotDir)
+{
+ g_autofree char *newxml = NULL;
+ g_autofree char *snapDir = NULL;
+ g_autofree char *snapFile = NULL;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ unsigned int flags = VIR_DOMAIN_SNAPSHOT_FORMAT_SECURE |
+ VIR_DOMAIN_SNAPSHOT_FORMAT_INTERNAL;
+ virDomainSnapshotDef *def = virDomainSnapshotObjGetDef(snapshot);
+
+ if (virDomainSnapshotGetCurrent(vm->snapshots) == snapshot)
+ flags |= VIR_DOMAIN_SNAPSHOT_FORMAT_CURRENT;
+ virUUIDFormat(vm->def->uuid, uuidstr);
+ newxml = virDomainSnapshotDefFormat(uuidstr, def, xmlopt, flags);
+ if (newxml == NULL)
+ return -1;
+
+ snapDir = g_strdup_printf("%s/%s", snapshotDir, vm->def->name);
+ if (g_mkdir_with_parents(snapDir, 0777) < 0) {
+ virReportSystemError(errno, _("cannot create snapshot directory
'%s'"),
+ snapDir);
+ return -1;
+ }
+
+ snapFile = g_strdup_printf("%s/%s.xml", snapDir, def->parent.name);
+
+ return virXMLSaveFile(snapFile, NULL, "snapshot-edit", newxml);
+}
+
+
+/* Hash iterator callback to discard multiple snapshots. */
+int
+qemuDomainMomentDiscardAll(void *payload,
+ const char *name G_GNUC_UNUSED,
+ void *data)
+{
+ virDomainMomentObj *moment = payload;
+ virQEMUMomentRemove *curr = data;
+ int err;
+
+ if (!curr->found && curr->current == moment)
+ curr->found = true;
+ err = curr->momentDiscard(curr->driver, curr->vm, moment, false,
+ curr->metadata_only);
+ if (err && !curr->err)
+ curr->err = err;
+ return 0;
+}
+
+
+int
+qemuSnapshotDiscardAllMetadata(virQEMUDriver *driver,
+ virDomainObj *vm)
+{
+ virQEMUMomentRemove rem = {
+ .driver = driver,
+ .vm = vm,
+ .metadata_only = true,
+ .momentDiscard = qemuSnapshotDiscard,
+ };
+
+ virDomainSnapshotForEach(vm->snapshots, qemuDomainMomentDiscardAll, &rem);
+ virDomainSnapshotObjListRemoveAll(vm->snapshots);
+
+ return rem.err;
+}
diff --git a/src/qemu/qemu_snapshot.h b/src/qemu/qemu_snapshot.h
index 0cc38c0039..016d18449a 100644
--- a/src/qemu/qemu_snapshot.h
+++ b/src/qemu/qemu_snapshot.h
@@ -81,3 +81,13 @@ qemuSnapshotDiskCreate(qemuSnapshotDiskContext *snapctxt);
virDomainSnapshotDiskDef *
qemuSnapshotGetTransientDiskDef(virDomainDiskDef *domdisk,
const char *suffix);
+
+int
+qemuSnapshotWriteMetadata(virDomainObj *vm,
+ virDomainMomentObj *snapshot,
+ virDomainXMLOption *xmlopt,
+ const char *snapshotDir);
+
+int
+qemuSnapshotDiscardAllMetadata(virQEMUDriver *driver,
+ virDomainObj *vm);
--
2.35.1