render / rpms / libvirt

Forked from rpms/libvirt 8 months ago
Clone
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