On 11/01/2012 10:22 AM, Peter Krempa wrote:
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
Still didn't match the code:
qemu-img create -f format_of_snapshot -o
backing_file=/path/to/backing,backing_fmt=format_of_backing
/path/to/snapshot
If disk->format is unspecified, then what we do should depend on
driver->allowDiskFormatProbing; if true, omit the argument (it's okay
for qemu to do the probing); if false, error out.
on each of the disks selected for snapshotting.
---
Diff to v1:
-added probing of backing file type
-switched to virCommand
+qemuDomainSnapshotCreateInactiveExternal(struct qemud_driver
*driver,
+ virDomainObjPtr vm,
+ virDomainSnapshotObjPtr snap,
+ bool reuse)
+{
+ int i = 0;
Unused assignment, given...
+ 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++) {
...this initialization.
+ 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;
+ }
Missing the converse check: if the file exists but reuse is not okay,
then it had better be a block device or an empty file; similar to online
disk snapshots, we don't want to allow the user to accidentally
overwrite files that contain data.
+
+ 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);
I don't think we need to probe here. If we don't know the current disk
format, then if driver->allowDiskFormatProbing, just omit the
backing_fmt listing; if not, error out and prevent the snapshot creation.
+ if (defdisk->format < 0)
+ goto cleanup;
+ }
+
+ if (virAsprintf(&backingFileArg,
"backing_file=%s,backing_fmt=%s",
+ defdisk->src,
+ virStorageFileFormatTypeToString(defdisk->format)) <
0) {
+ virReportOOMError();
+ goto cleanup;
+ }
Rather than allocating into a temporary, it may be easier to rearrange
things to use virCommandAddArgFormat.
+
+ 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 */
This covers rollbacks if qemu-img fails, but leaves things a bit awkward
if we hit OOM. In particular...
+ 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);
...you end up corrupting the diskdef to point to an unlinked file on OOM.
+ }
+ }
+
+ 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;
If the domain is offline, I'd treat def->state as VIR_DOMAIN_SHUTOFF,
saving VIR_DOMAIN_DISK_SNAPSHOT for the case where we know the domain
was running at the time but no memory was saved.
@@ -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;
+ }
This isn't quite right. For offline snapshots, we can mix and match
internal and external snapshots at will, which means we should call both
functions, and ensure that the internal version does nothing unless an
internal snapshot is requested. Also, shouldn't you be passing (flags &
VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXTERNAL) != 0 rather than false?
I'll work up some proposed fixes; some of them can be deferred to
followup patches, so I'll try to come up with the minimum squash for
what I would ack.
--
Eric Blake eblake(a)redhat.com +1-919-301-3266
Libvirt virtualization library
http://libvirt.org