[PATCH 03/11] qemu: move snapshot related funcs from domain.c to snapshot.c

Nikolay Shirokovskiy nikolay.shirokovskiy at openvz.org
Thu Mar 31 11:19:13 UTC 2022


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 at 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



More information about the libvir-list mailing list