[libvirt] [PATCHv3] snapshot: qemu: Add support for external inactive snapshots
Eric Blake
eblake at redhat.com
Thu Nov 8 00:48:58 UTC 2012
On 11/07/2012 04:06 PM, Peter Krempa wrote:
> This patch adds support for external disk snapshots of inactive domains.
> The snapshot is created by calling using qemu-img by calling:
>
> qemu-img create -f format_of_snapshot -o
> backing_file=/path/to/src,backing_fmt=format_of_backing_image
> /path/to/snapshot
>
> +qemuDomainSnapshotCreateInactiveExternal(struct qemud_driver *driver,
> + virDomainObjPtr vm,
> + virDomainSnapshotObjPtr snap,
> + bool reuse)
> + /* no-op if reuse is true and file exists and is valid */
> + if (reuse) {
> + if (stat(snapdisk->file, &st) < 0) {
> + if (errno != ENOENT) {
> + virReportSystemError(errno,
> + _("unable to stat snapshot image %s"),
> + snapdisk->file);
> + goto cleanup;
> + }
> + } else if (!S_ISBLK(st.st_mode) && st.st_size > 0) {
> + /* the existing image is reused */
> + continue;
Hey, I just realized that the logic I want here (if reuse, then check
that it exists; if !reuse, then check that we aren't nuking unrelated
data) was already run during qemuDomainSnapshotPrepare. So we can
simplify this - if we got here, then we already know that the file
exists and is ready to reuse, so we can simplify this code.
> +
> + /* 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))) {
> + /* we cannot rollback here in a sane way */
> + virReportOOMError();
True, but OOM is enough of a corner case that I'm not too bothered by this.
> + return -1;
> + }
> + defdisk->format = snapdisk->format;
> + }
> + }
> +
> + ret = 0;
> +
> +cleanup:
> + virCommandFree(cmd);
> +
> + /* 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)
Possible NULL deref, if you have a disk with no snapshot earlier in the
array than a disk with an external snapshot. Also, we don't want to
unlink() pre-existing block devices, so it may make more sense to pay
attention to whether we actually created a file.
ACK with this squashed in:
diff --git i/src/qemu/qemu_driver.c w/src/qemu/qemu_driver.c
index 17de98e..cea1c2f 100644
--- i/src/qemu/qemu_driver.c
+++ w/src/qemu/qemu_driver.c
@@ -10677,31 +10677,26 @@
qemuDomainSnapshotCreateInactiveExternal(struct qemud_driver *driver,
virDomainDiskDefPtr defdisk;
virCommandPtr cmd = NULL;
const char *qemuImgPath;
- struct stat st;
+ virBitmapPtr created;
int ret = -1;
if (!(qemuImgPath = qemuFindQemuImgBinary(driver)))
return -1;
- for (i = 0; i < snap->def->ndisks; i++) {
+ if (!(created = virBitmapNew(snap->def->ndisks))) {
+ virReportOOMError();
+ return -1;
+ }
+
+ /* If reuse is true, then qemuDomainSnapshotPrepare already
+ * ensured that the new files exist, and it was up to the user to
+ * create them correctly. */
+ for (i = 0; i < snap->def->ndisks && !reuse; i++) {
snapdisk = &(snap->def->disks[i]);
defdisk = snap->def->dom->disks[snapdisk->index];
-
- /* no-op if reuse is true and file exists and is valid */
- if (reuse) {
- if (stat(snapdisk->file, &st) < 0) {
- if (errno != ENOENT) {
- virReportSystemError(errno,
- _("unable to stat snapshot
image %s"),
- snapdisk->file);
- goto cleanup;
- }
- } else if (!S_ISBLK(st.st_mode) && st.st_size > 0) {
- /* the existing image is reused */
- continue;
- }
- }
+ if (snapdisk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL)
+ continue;
if (!snapdisk->format)
snapdisk->format = VIR_STORAGE_FILE_QCOW2;
@@ -10736,6 +10731,9 @@ qemuDomainSnapshotCreateInactiveExternal(struct
qemud_driver *driver,
/* adds cmd line args: /path/to/target/file */
virCommandAddArg(cmd, snapdisk->file);
+ if (!virFileExists(snapdisk->file))
+ ignore_value(virBitmapSetBit(created, i));
+
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
@@ -10753,7 +10751,8 @@ qemuDomainSnapshotCreateInactiveExternal(struct
qemud_driver *driver,
if (!(defdisk->src = strdup(snapdisk->file))) {
/* we cannot rollback here in a sane way */
virReportOOMError();
- return -1;
+ i = snap->def->ndisks;
+ goto cleanup;
}
defdisk->format = snapdisk->format;
}
@@ -10765,14 +10764,16 @@ cleanup:
virCommandFree(cmd);
/* unlink images if creation has failed */
- if (ret < 0 && i > 0) {
- for (; i > 0; i--) {
- snapdisk = &(snap->def->disks[i]);
+ if (ret < 0) {
+ ssize_t bit = -1;
+ while ((bit = virBitmapNextSetBit(created, bit)) >= 0) {
+ snapdisk = &(snap->def->disks[bit]);
if (unlink(snapdisk->file) < 0)
VIR_WARN("Failed to remove snapshot image '%s'",
snapdisk->file);
}
}
+ virBitmapFree(created);
return ret;
}
struct stat st;
--
Eric Blake eblake at redhat.com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 617 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20121107/d314da6b/attachment-0001.sig>
More information about the libvir-list
mailing list