This patch adds support for external disk snapshots of inactive domains.
The snapshot is created by calling
qemu-img create -o backing_file=/path/to/disk /path/snapshot_file -f
backing_file=/path/to/backing/file,backing_fmt=format_of_backing_file
on each of the disks selected for snapshotting.
---
Diff to v1:
-added probing of backing file type
-switched to virCommand
---
src/qemu/qemu_driver.c | 124 ++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 113 insertions(+), 11 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 04906d4..4cea78f 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10663,13 +10663,116 @@ qemuDomainSnapshotFSThaw(struct qemud_driver *driver,
/* The domain is expected to be locked and inactive. */
static int
-qemuDomainSnapshotCreateInactive(struct qemud_driver *driver,
- virDomainObjPtr vm,
- virDomainSnapshotObjPtr snap)
+qemuDomainSnapshotCreateInactiveInternal(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainSnapshotObjPtr snap)
{
return qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-c", false);
}
+/* The domain is expected to be locked and inactive. */
+static int
+qemuDomainSnapshotCreateInactiveExternal(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainSnapshotObjPtr snap,
+ bool reuse)
+{
+ int i = 0;
+ char *backingFileArg = NULL;
+ virDomainSnapshotDiskDefPtr snapdisk;
+ virDomainDiskDefPtr defdisk;
+ virCommandPtr cmd = NULL;
+ const char *qemuImgPath;
+
+ int ret = -1;
+
+ if (!(qemuImgPath = qemuFindQemuImgBinary(driver)))
+ return -1;
+
+ for (i = 0; i < snap->def->ndisks; i++) {
+ snapdisk = &(snap->def->disks[i]);
+ defdisk = snap->def->dom->disks[snapdisk->index];
+
+ if (snapdisk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
+ /* check if destination file exists */
+ if (reuse && virFileExists(snapdisk->file)) {
+ VIR_DEBUG("Skipping snapshot creation: File exists: %s",
+ snapdisk->file);
+ continue;
+ }
+
+ if (!snapdisk->format)
+ snapdisk->format = VIR_STORAGE_FILE_QCOW2;
+
+ /* probe the disk format */
+ if (defdisk->format <= 0) {
+ defdisk->format = virStorageFileProbeFormat(defdisk->src,
+ driver->user,
+ driver->group);
+ if (defdisk->format < 0)
+ goto cleanup;
+ }
+
+ if (virAsprintf(&backingFileArg,
"backing_file=%s,backing_fmt=%s",
+ defdisk->src,
+ virStorageFileFormatTypeToString(defdisk->format)) < 0)
{
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (!(cmd = virCommandNewArgList(qemuImgPath,
+ "create",
+ "-f",
+
virStorageFileFormatTypeToString(snapdisk->format),
+ "-o",
+ backingFileArg,
+ snapdisk->file,
+ NULL)))
+ goto cleanup;
+
+ if (virCommandRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ virCommandFree(cmd);
+ VIR_FREE(backingFileArg);
+ cmd = NULL;
+ }
+ }
+
+ /* update disk definitions */
+ for (i = 0; i < snap->def->ndisks; i++) {
+ snapdisk = &(snap->def->disks[i]);
+ defdisk = vm->def->disks[snapdisk->index];
+
+ if (snapdisk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
+ VIR_FREE(defdisk->src);
+ if (!(defdisk->src = strdup(snapdisk->file))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ defdisk->format = snapdisk->format;
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ /* unlink images if creation has failed */
+ if (ret < 0 && i > 0) {
+ for (; i > 0; i--) {
+ snapdisk = &(snap->def->disks[i]);
+ if (unlink(snapdisk->file) < 0)
+ VIR_WARN("Failed to remove snapshot image '%s'",
+ snapdisk->file);
+ }
+ }
+
+ VIR_FREE(backingFileArg);
+ virCommandFree(cmd);
+
+ return ret;
+}
+
/* The domain is expected to be locked and active. */
static int
@@ -11462,12 +11565,6 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
goto cleanup;
if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
- if (!virDomainObjIsActive(vm)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("disk snapshots of inactive domains not "
- "implemented yet"));
- goto cleanup;
- }
align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
align_match = false;
def->state = VIR_DOMAIN_DISK_SNAPSHOT;
@@ -11540,8 +11637,13 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
}
} else {
/* inactive */
- if (qemuDomainSnapshotCreateInactive(driver, vm, snap) < 0)
- goto cleanup;
+ if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT) {
+ if (qemuDomainSnapshotCreateInactiveExternal(driver, vm, snap, false) <
0)
+ goto cleanup;
+ } else {
+ if (qemuDomainSnapshotCreateInactiveInternal(driver, vm, snap) < 0)
+ goto cleanup;
+ }
}
/* If we fail after this point, there's not a whole lot we can
--
1.7.12.4