Signed-off-by: Povilas Kanapickas
---
src/qemu/qemu_driver.c | 89 ++
1 file changed, 89 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 227ec1c6d9..a3ffc19122 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -16590,6 +16590,7 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr
snapshot,
typedef struct _virQEMUSnapReparent virQEMUSnapReparent;
typedef virQEMUSnapReparent *virQEMUSnapReparentPtr;
struct _virQEMUSnapReparent {
+virQEMUDriverPtr driver;
virQEMUDriverConfigPtr cfg;
virDomainSnapshotObjPtr parent;
virDomainObjPtr vm;
@@ -16617,6 +16618,88 @@
qemuDomainSnapshotReparentChildrenMetadata(virDomainSnapshotObjPtr snap,
rep->cfg->snapshotDir);
}
+static int
+qemuDomainSnapshotReparentDiskExternal(virQEMUDriverPtr driver,
+ virDomainSnapshotObjPtr parent_snap,
+ virDomainSnapshotDiskDefPtr disk)
+{
+const char* qemu_img_path = NULL;
+virCommandPtr cmd = NULL;
+int i;
+int ret = -1;
+const char* parent_disk_path = NULL;
+
+// Find the path to the disk we should use as the base when reparenting
+// FIXME: what if there's no parent snapshot? i.e. we need to reparent on
+// "empty" disk?
+for (i = 0; i < parent_snap->def->dom->ndisks; ++i) {
+if (STREQ(parent_snap->def->dom->disks[i]->dst, disk->name)) {
+parent_disk_path = parent_snap->def->dom->disks[i]->src->path;
+break;
+}
+}
+
+if (parent_disk_path == NULL) {
+virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not find disk to reparent '%s' to"),
+ disk->src->path);
+goto cleanup;
+}
+
+if (!(qemu_img_path = qemuFindQemuImgBinary(driver))) {
+goto cleanup;
+}
+
+if (!(cmd = virCommandNewArgList(qemu_img_path,
+ "rebase", "-b", parent_disk_path,
+ disk->src->path,
+ NULL))) {
+goto cleanup;
+}
+
+if (virCommandRun(cmd, NULL) < 0)
+goto cleanup;
+
+ret = 0;
+cleanup:
+virCommandFree(cmd);
+return ret;
+}
+
+static int
+qemuDomainSnapshotReparentDisks(virDomainSnapshotObjPtr snap,
+virQEMUSnapReparentPtr rep)
+{
+int i;
+virDomainSnapshotDiskDefPtr snap_disk;
+
+if (!snap->def->dom) {
+VIR_WARN("Any external disk snapshots in a snapshot created with "
+ "pre-0.9.5 libvirt will not be correctly reparented.");
+// In snapshots created with pre-0.9.5 libvirt we don't have
information
+// needed to correctly reparent external disk snapshots but we also
+// don't even know whether external disk snapshots were used so that
+// we could report this as an error. We can only emit a warning in that
+// case.
+return 0;
+}
+
+for (i = 0; i < snap->def->ndisks; ++i) {
+snap_disk = &(snap->def->disks[i]);
+
+// FIXME: do we need to explicitly reparent internal snapshots to
+// e.g. prevent long non-visible snapshot chains that might affect
+// performance?
+if (snap_disk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL)
+continue;
+
+if (qemuDomainSnapshotReparentDiskExternal(rep->driver, rep->parent,
+ snap_disk) < 0)
+return -1;
+}
+return 0;
+}
+
static int
qemuDomainSnapshotReparentChildren(void *payload,
const void *name ATTRIBUTE_UNUSED,
@@ -16628,6 +16711,11 @@ qemuDomainSnapshotReparentChildren(void *payload,
if (rep->err < 0)
return 0;
+if (qemuDomainSnapshotReparentDisks(snap, rep) < 0) {
+rep->err = -1;
+goto cleanup;
+}
+
if (qemuDomainSnapshotReparentChildrenMetadata(snap, rep) < 0) {
rep->err = -1;
goto cleanup;
@@ -16718,6 +16806,7 @@ qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
vm->current_snapshot = snap;
}
} else if (snap->nchildren) {
+rep.driver = driver;
rep.cfg = cfg;
rep.parent = snap->parent;
rep.vm = vm;
--
2.17.1
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list