|
|
c401cc |
From 97a61920326f228c3963820a51c2c582d208cd98 Mon Sep 17 00:00:00 2001
|
|
|
c401cc |
Message-Id: <97a61920326f228c3963820a51c2c582d208cd98@dist-git>
|
|
|
c401cc |
From: Peter Krempa <pkrempa@redhat.com>
|
|
|
c401cc |
Date: Wed, 26 Feb 2014 14:55:03 +0100
|
|
|
c401cc |
Subject: [PATCH] qemu: snapshots: Declare supported and unsupported snapshot
|
|
|
c401cc |
configs
|
|
|
c401cc |
|
|
|
c401cc |
https://bugzilla.redhat.com/show_bug.cgi?id=1032370
|
|
|
c401cc |
|
|
|
c401cc |
Currently the snapshot code did not check if it actually supports
|
|
|
c401cc |
snapshots on various disk backends for domains. To avoid future problems
|
|
|
c401cc |
add checkers that whitelist the supported configurations.
|
|
|
c401cc |
|
|
|
c401cc |
(cherry picked from commit 26fb96d8c04ef87d432ccb5a98bea472b04e5dd6)
|
|
|
c401cc |
|
|
|
c401cc |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
c401cc |
---
|
|
|
c401cc |
src/qemu/qemu_driver.c | 254 +++++++++++++++++++++++++++++++++++++++++++------
|
|
|
c401cc |
1 file changed, 224 insertions(+), 30 deletions(-)
|
|
|
c401cc |
|
|
|
c401cc |
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
|
|
c401cc |
index ef253f4..2fe128e 100644
|
|
|
c401cc |
--- a/src/qemu/qemu_driver.c
|
|
|
c401cc |
+++ b/src/qemu/qemu_driver.c
|
|
|
c401cc |
@@ -12141,13 +12141,216 @@ endjob:
|
|
|
c401cc |
}
|
|
|
c401cc |
|
|
|
c401cc |
static int
|
|
|
c401cc |
-qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def,
|
|
|
c401cc |
+qemuDomainSnapshotPrepareDiskExternalBacking(virDomainDiskDefPtr disk)
|
|
|
c401cc |
+{
|
|
|
c401cc |
+ int actualType = qemuDiskGetActualType(disk);
|
|
|
c401cc |
+
|
|
|
c401cc |
+ switch ((enum virDomainDiskType) actualType) {
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_BLOCK:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_FILE:
|
|
|
c401cc |
+ return 0;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_NETWORK:
|
|
|
c401cc |
+ switch ((enum virDomainDiskProtocol) disk->protocol) {
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_NBD:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_RBD:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_ISCSI:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_LAST:
|
|
|
c401cc |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
c401cc |
+ _("external inactive snapshots are not supported on "
|
|
|
c401cc |
+ "'network' disks using '%s' protocol"),
|
|
|
c401cc |
+ virDomainDiskProtocolTypeToString(disk->protocol));
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+ break;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_DIR:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_VOLUME:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_LAST:
|
|
|
c401cc |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
c401cc |
+ _("external inactive snapshots are not supported on "
|
|
|
c401cc |
+ "'%s' disks"), virDomainDiskTypeToString(actualType));
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+
|
|
|
c401cc |
+ return 0;
|
|
|
c401cc |
+}
|
|
|
c401cc |
+
|
|
|
c401cc |
+
|
|
|
c401cc |
+static int
|
|
|
c401cc |
+qemuDomainSnapshotPrepareDiskExternalOverlayActive(virDomainSnapshotDiskDefPtr disk)
|
|
|
c401cc |
+{
|
|
|
c401cc |
+ int actualType = qemuSnapshotDiskGetActualType(disk);
|
|
|
c401cc |
+
|
|
|
c401cc |
+ switch ((enum virDomainDiskType) actualType) {
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_BLOCK:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_FILE:
|
|
|
c401cc |
+ return 0;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_NETWORK:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_DIR:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_VOLUME:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_LAST:
|
|
|
c401cc |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
c401cc |
+ _("external active snapshots are not supported on "
|
|
|
c401cc |
+ "'%s' disks"), virDomainDiskTypeToString(actualType));
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+
|
|
|
c401cc |
+ return 0;
|
|
|
c401cc |
+}
|
|
|
c401cc |
+
|
|
|
c401cc |
+
|
|
|
c401cc |
+static int
|
|
|
c401cc |
+qemuDomainSnapshotPrepareDiskExternalOverlayInactive(virDomainSnapshotDiskDefPtr disk)
|
|
|
c401cc |
+{
|
|
|
c401cc |
+ int actualType = qemuSnapshotDiskGetActualType(disk);
|
|
|
c401cc |
+
|
|
|
c401cc |
+ switch ((enum virDomainDiskType) actualType) {
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_BLOCK:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_FILE:
|
|
|
c401cc |
+ return 0;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_NETWORK:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_DIR:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_VOLUME:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_LAST:
|
|
|
c401cc |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
c401cc |
+ _("external inactive snapshots are not supported on "
|
|
|
c401cc |
+ "'%s' disks"), virDomainDiskTypeToString(actualType));
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+
|
|
|
c401cc |
+ return 0;
|
|
|
c401cc |
+}
|
|
|
c401cc |
+
|
|
|
c401cc |
+
|
|
|
c401cc |
+
|
|
|
c401cc |
+static int
|
|
|
c401cc |
+qemuDomainSnapshotPrepareDiskExternal(virConnectPtr conn,
|
|
|
c401cc |
+ virDomainDiskDefPtr disk,
|
|
|
c401cc |
+ virDomainSnapshotDiskDefPtr snapdisk,
|
|
|
c401cc |
+ bool active,
|
|
|
c401cc |
+ bool reuse)
|
|
|
c401cc |
+{
|
|
|
c401cc |
+ int actualType;
|
|
|
c401cc |
+ struct stat st;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ if (qemuTranslateSnapshotDiskSourcePool(conn, snapdisk) < 0)
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ if (!active) {
|
|
|
c401cc |
+ if (qemuTranslateDiskSourcePool(conn, disk) < 0)
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ if (qemuDomainSnapshotPrepareDiskExternalBacking(disk) < 0)
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ if (qemuDomainSnapshotPrepareDiskExternalOverlayInactive(snapdisk) < 0)
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+ } else {
|
|
|
c401cc |
+ if (qemuDomainSnapshotPrepareDiskExternalOverlayActive(snapdisk) < 0)
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+
|
|
|
c401cc |
+ actualType = qemuSnapshotDiskGetActualType(snapdisk);
|
|
|
c401cc |
+
|
|
|
c401cc |
+ switch ((enum virDomainDiskType) actualType) {
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_BLOCK:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_FILE:
|
|
|
c401cc |
+ if (stat(snapdisk->file, &st) < 0) {
|
|
|
c401cc |
+ if (errno != ENOENT) {
|
|
|
c401cc |
+ virReportSystemError(errno,
|
|
|
c401cc |
+ _("unable to stat for disk %s: %s"),
|
|
|
c401cc |
+ snapdisk->name, snapdisk->file);
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+ } else if (reuse) {
|
|
|
c401cc |
+ virReportSystemError(errno,
|
|
|
c401cc |
+ _("missing existing file for disk %s: %s"),
|
|
|
c401cc |
+ snapdisk->name, snapdisk->file);
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+ } else if (!S_ISBLK(st.st_mode) && st.st_size && !reuse) {
|
|
|
c401cc |
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
c401cc |
+ _("external snapshot file for disk %s already "
|
|
|
c401cc |
+ "exists and is not a block device: %s"),
|
|
|
c401cc |
+ snapdisk->name, snapdisk->file);
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+ break;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_NETWORK:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_DIR:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_VOLUME:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_LAST:
|
|
|
c401cc |
+ break;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+
|
|
|
c401cc |
+ return 0;
|
|
|
c401cc |
+}
|
|
|
c401cc |
+
|
|
|
c401cc |
+
|
|
|
c401cc |
+static int
|
|
|
c401cc |
+qemuDomainSnapshotPrepareDiskInternal(virConnectPtr conn,
|
|
|
c401cc |
+ virDomainDiskDefPtr disk,
|
|
|
c401cc |
+ bool active)
|
|
|
c401cc |
+{
|
|
|
c401cc |
+ int actualType;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ /* active disks are handeled by qemu itself so no need to worry about those */
|
|
|
c401cc |
+ if (active)
|
|
|
c401cc |
+ return 0;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ if (qemuTranslateDiskSourcePool(conn, disk) < 0)
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ actualType = qemuDiskGetActualType(disk);
|
|
|
c401cc |
+
|
|
|
c401cc |
+ switch ((enum virDomainDiskType) actualType) {
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_BLOCK:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_FILE:
|
|
|
c401cc |
+ return 0;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_NETWORK:
|
|
|
c401cc |
+ switch ((enum virDomainDiskProtocol) disk->protocol) {
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_NBD:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_RBD:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_ISCSI:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_PROTOCOL_LAST:
|
|
|
c401cc |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
c401cc |
+ _("internal inactive snapshots are not supported on "
|
|
|
c401cc |
+ "'network' disks using '%s' protocol"),
|
|
|
c401cc |
+ virDomainDiskProtocolTypeToString(disk->protocol));
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+ break;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_DIR:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_VOLUME:
|
|
|
c401cc |
+ case VIR_DOMAIN_DISK_TYPE_LAST:
|
|
|
c401cc |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
c401cc |
+ _("internal inactive snapshots are not supported on "
|
|
|
c401cc |
+ "'%s' disks"), virDomainDiskTypeToString(actualType));
|
|
|
c401cc |
+ return -1;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+
|
|
|
c401cc |
+ return 0;
|
|
|
c401cc |
+}
|
|
|
c401cc |
+
|
|
|
c401cc |
+
|
|
|
c401cc |
+static int
|
|
|
c401cc |
+qemuDomainSnapshotPrepare(virConnectPtr conn,
|
|
|
c401cc |
+ virDomainObjPtr vm,
|
|
|
c401cc |
+ virDomainSnapshotDefPtr def,
|
|
|
c401cc |
unsigned int *flags)
|
|
|
c401cc |
{
|
|
|
c401cc |
int ret = -1;
|
|
|
c401cc |
size_t i;
|
|
|
c401cc |
bool active = virDomainObjIsActive(vm);
|
|
|
c401cc |
- struct stat st;
|
|
|
c401cc |
bool reuse = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
|
|
|
c401cc |
bool atomic = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC) != 0;
|
|
|
c401cc |
bool found_internal = false;
|
|
|
c401cc |
@@ -12169,8 +12372,19 @@ qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def,
|
|
|
c401cc |
case VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL:
|
|
|
c401cc |
found_internal = true;
|
|
|
c401cc |
|
|
|
c401cc |
- if (def->state != VIR_DOMAIN_DISK_SNAPSHOT &&
|
|
|
c401cc |
- dom_disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
|
|
|
c401cc |
+ if (def->state == VIR_DOMAIN_DISK_SNAPSHOT && active) {
|
|
|
c401cc |
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
c401cc |
+ _("active qemu domains require external disk "
|
|
|
c401cc |
+ "snapshots; disk %s requested internal"),
|
|
|
c401cc |
+ disk->name);
|
|
|
c401cc |
+ goto cleanup;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+
|
|
|
c401cc |
+ if (qemuDomainSnapshotPrepareDiskInternal(conn, dom_disk,
|
|
|
c401cc |
+ active) < 0)
|
|
|
c401cc |
+ goto cleanup;
|
|
|
c401cc |
+
|
|
|
c401cc |
+ if (dom_disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
|
|
|
c401cc |
(dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG ||
|
|
|
c401cc |
dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD)) {
|
|
|
c401cc |
break;
|
|
|
c401cc |
@@ -12185,13 +12399,6 @@ qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def,
|
|
|
c401cc |
vm->def->disks[i]->format));
|
|
|
c401cc |
goto cleanup;
|
|
|
c401cc |
}
|
|
|
c401cc |
- if (def->state == VIR_DOMAIN_DISK_SNAPSHOT && active) {
|
|
|
c401cc |
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
c401cc |
- _("active qemu domains require external disk "
|
|
|
c401cc |
- "snapshots; disk %s requested internal"),
|
|
|
c401cc |
- disk->name);
|
|
|
c401cc |
- goto cleanup;
|
|
|
c401cc |
- }
|
|
|
c401cc |
break;
|
|
|
c401cc |
|
|
|
c401cc |
case VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL:
|
|
|
c401cc |
@@ -12206,25 +12413,11 @@ qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def,
|
|
|
c401cc |
virStorageFileFormatTypeToString(disk->format));
|
|
|
c401cc |
goto cleanup;
|
|
|
c401cc |
}
|
|
|
c401cc |
- if (stat(disk->file, &st) < 0) {
|
|
|
c401cc |
- if (errno != ENOENT) {
|
|
|
c401cc |
- virReportSystemError(errno,
|
|
|
c401cc |
- _("unable to stat for disk %s: %s"),
|
|
|
c401cc |
- disk->name, disk->file);
|
|
|
c401cc |
- goto cleanup;
|
|
|
c401cc |
- } else if (reuse) {
|
|
|
c401cc |
- virReportSystemError(errno,
|
|
|
c401cc |
- _("missing existing file for disk %s: %s"),
|
|
|
c401cc |
- disk->name, disk->file);
|
|
|
c401cc |
- goto cleanup;
|
|
|
c401cc |
- }
|
|
|
c401cc |
- } else if (!S_ISBLK(st.st_mode) && st.st_size && !reuse) {
|
|
|
c401cc |
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
c401cc |
- _("external snapshot file for disk %s already "
|
|
|
c401cc |
- "exists and is not a block device: %s"),
|
|
|
c401cc |
- disk->name, disk->file);
|
|
|
c401cc |
+
|
|
|
c401cc |
+ if (qemuDomainSnapshotPrepareDiskExternal(conn, dom_disk, disk,
|
|
|
c401cc |
+ active, reuse) < 0)
|
|
|
c401cc |
goto cleanup;
|
|
|
c401cc |
- }
|
|
|
c401cc |
+
|
|
|
c401cc |
external++;
|
|
|
c401cc |
break;
|
|
|
c401cc |
|
|
|
c401cc |
@@ -12729,6 +12922,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
|
|
|
c401cc |
const char *xmlDesc,
|
|
|
c401cc |
unsigned int flags)
|
|
|
c401cc |
{
|
|
|
c401cc |
+ virConnectPtr conn = domain->conn;
|
|
|
c401cc |
virQEMUDriverPtr driver = domain->conn->privateData;
|
|
|
c401cc |
virDomainObjPtr vm = NULL;
|
|
|
c401cc |
char *xml = NULL;
|
|
|
c401cc |
@@ -12994,7 +13188,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
|
|
|
c401cc |
}
|
|
|
c401cc |
if (virDomainSnapshotAlignDisks(def, align_location,
|
|
|
c401cc |
align_match) < 0 ||
|
|
|
c401cc |
- qemuDomainSnapshotPrepare(vm, def, &flags) < 0)
|
|
|
c401cc |
+ qemuDomainSnapshotPrepare(conn, vm, def, &flags) < 0)
|
|
|
c401cc |
goto cleanup;
|
|
|
c401cc |
}
|
|
|
c401cc |
|
|
|
c401cc |
--
|
|
|
c401cc |
1.9.0
|
|
|
c401cc |
|