c401cc
From 7968d4cc1504076a3b28601ef896909961d06444 Mon Sep 17 00:00:00 2001
c401cc
Message-Id: <7968d4cc1504076a3b28601ef896909961d06444@dist-git>
c401cc
From: John Ferlan <jferlan@redhat.com>
c401cc
Date: Fri, 14 Feb 2014 16:33:32 -0500
c401cc
Subject: [PATCH] Block info query: Add check for transient domain
c401cc
c401cc
https://bugzilla.redhat.com/show_bug.cgi?id=1065531
c401cc
c401cc
Currently the qemuDomainGetBlockInfo will return allocation == physical
c401cc
for most backing stores. For a qcow2 block backed device it's possible
c401cc
to return the highest lv extent allocated from qemu for an active guest.
c401cc
That is a value where allocation != physical and one would hope be less.
c401cc
However, if the guest is not running, then the code falls back to returning
c401cc
allocation == physical. This turns out to be problematic for rhev which
c401cc
monitors the size of the backing store. During a migration, before the
c401cc
VM has been started on the target and while it is deemed inactive on the
c401cc
source, there's a small window of time where the allocation is returned
c401cc
as physical triggering the code to extend the file unnecessarily.
c401cc
c401cc
Since rhev uses transient domains and this is edge condition for a transient
c401cc
domain, rather than returning good status and allocation == physical when
c401cc
this "window of opportunity" exists, this patch will check for a transient
c401cc
(or non persistent) domain and return a failure to the caller rather than
c401cc
returning the defaults. For a persistent domain, the defaults will be
c401cc
returned. The description for the virDomainGetBlockInfo has been updated
c401cc
to describe the phenomena.
c401cc
c401cc
(cherry picked from commit 46a0737e13cec06a6b7cb0afdcdd200c2bec317f)
c401cc
Signed-off-by: John Ferlan <jferlan@redhat.com>
c401cc
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c401cc
---
c401cc
 include/libvirt/libvirt.h.in |  8 ++++---
c401cc
 src/libvirt.c                | 53 ++++++++++++++++++++++++++++++++++++++++++++
c401cc
 src/qemu/qemu_driver.c       | 29 +++++++++++++++++++-----
c401cc
 3 files changed, 82 insertions(+), 8 deletions(-)
c401cc
c401cc
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
c401cc
index 1bc6624..91d89ec 100644
c401cc
--- a/include/libvirt/libvirt.h.in
c401cc
+++ b/include/libvirt/libvirt.h.in
c401cc
@@ -2079,7 +2079,8 @@ int                     virDomainBlockResize (virDomainPtr dom,
c401cc
 
c401cc
 /** virDomainBlockInfo:
c401cc
  *
c401cc
- * This struct provides information about the size of a block device backing store
c401cc
+ * This struct provides information about the size of a block device
c401cc
+ * backing store
c401cc
  *
c401cc
  * Examples:
c401cc
  *
c401cc
@@ -2092,11 +2093,12 @@ int                     virDomainBlockResize (virDomainPtr dom,
c401cc
  *
c401cc
  *  - qcow2 file in filesystem
c401cc
  *       * capacity: logical size from qcow2 header
c401cc
- *       * allocation, physical: logical size of the file / highest qcow extent (identical)
c401cc
+ *       * allocation, physical: logical size of the file /
c401cc
+ *                               highest qcow extent (identical)
c401cc
  *
c401cc
  *  - qcow2 file in a block device
c401cc
  *       * capacity: logical size from qcow2 header
c401cc
- *       * allocation: highest qcow extent written
c401cc
+ *       * allocation: highest qcow extent written for an active domain
c401cc
  *       * physical: size of the block device container
c401cc
  */
c401cc
 typedef struct _virDomainBlockInfo virDomainBlockInfo;
c401cc
diff --git a/src/libvirt.c b/src/libvirt.c
c401cc
index 61cae03..af94326 100644
c401cc
--- a/src/libvirt.c
c401cc
+++ b/src/libvirt.c
c401cc
@@ -9028,6 +9028,59 @@ error:
c401cc
  * can be found by calling virDomainGetXMLDesc() and inspecting
c401cc
  * elements within //domain/devices/disk.
c401cc
  *
c401cc
+ * For QEMU domains, the allocation and physical virDomainBlockInfo
c401cc
+ * values returned will generally be the same, except when using a
c401cc
+ * non raw, block backing device, such as qcow2 for an active domain.
c401cc
+ * When the persistent domain is not active, QEMU will return the
c401cc
+ * default which is the same value for allocation and physical.
c401cc
+ *
c401cc
+ * Active QEMU domains can return an allocation value which is more
c401cc
+ * representative of the currently used blocks by the device compared
c401cc
+ * to the physical size of the device. Applications can use/monitor
c401cc
+ * the allocation value with the understanding that if the domain
c401cc
+ * becomes inactive during an attempt to get the value, the default
c401cc
+ * values will be returned. Thus, the application should check
c401cc
+ * after the call for the domain being inactive if the values are
c401cc
+ * the same. Optionally, the application could be watching for a
c401cc
+ * shutdown event and then ignore any values received afterwards.
c401cc
+ * This can be an issue when a domain is being migrated and the
c401cc
+ * exact timing of the domain being made inactive and check of
c401cc
+ * the allocation value results the default being returned. For
c401cc
+ * a transient domain in the similar situation, this call will return
c401cc
+ * -1 and an error message indicating the "domain is not running".
c401cc
+ *
c401cc
+ * The following is some pseudo code illustrating the call sequence:
c401cc
+ *
c401cc
+ *   ...
c401cc
+ *   virDomainPtr dom;
c401cc
+ *   virDomainBlockInfo info;
c401cc
+ *   char *device;
c401cc
+ *   ...
c401cc
+ *   // Either get a list of all domains or a specific domain
c401cc
+ *   // via a virDomainLookupBy*() call.
c401cc
+ *   //
c401cc
+ *   // It's also required to fill in the device pointer, but that's
c401cc
+ *   // specific to the implementation. For the purposes of this example
c401cc
+ *   // a qcow2 backed device name string would need to be provided.
c401cc
+ *   ...
c401cc
+ *   // If the following call is made on a persistent domain with a
c401cc
+ *   // qcow2 block backed block device, then it's possible the returned
c401cc
+ *   // allocation equals the physical value. In that case, the domain
c401cc
+ *   // that may have been active prior to calling has become inactive,
c401cc
+ *   // such as is the case during a domain migration. Thus once we
c401cc
+ *   // get data returned, check for active domain when the values are
c401cc
+ *   // the same.
c401cc
+ *   if (virDomainGetBlockInfo(dom, device, &info, 0) < 0)
c401cc
+ *       goto failure;
c401cc
+ *   if (info.allocation == info.physical) {
c401cc
+ *       // If the domain is no longer active,
c401cc
+ *       // then the defaults are being returned.
c401cc
+ *       if (!virDomainIsActive())
c401cc
+ *               goto ignore_return;
c401cc
+ *   }
c401cc
+ *   // Do something with the allocation and physical values
c401cc
+ *   ...
c401cc
+ *
c401cc
  * Returns 0 in case of success and -1 in case of failure.
c401cc
  */
c401cc
 int
c401cc
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
c401cc
index ee622a2..a7da257 100644
c401cc
--- a/src/qemu/qemu_driver.c
c401cc
+++ b/src/qemu/qemu_driver.c
c401cc
@@ -10084,6 +10084,7 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
c401cc
     struct stat sb;
c401cc
     int idx;
c401cc
     int format;
c401cc
+    int activeFail = false;
c401cc
     virQEMUDriverConfigPtr cfg = NULL;
c401cc
     char *alias = NULL;
c401cc
 
c401cc
@@ -10183,15 +10184,23 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
c401cc
     /* Set default value .. */
c401cc
     info->allocation = info->physical;
c401cc
 
c401cc
-    /* ..but if guest is running & not using raw
c401cc
-       disk format and on a block device, then query
c401cc
-       highest allocated extent from QEMU */
c401cc
+    /* ..but if guest is not using raw disk format and on a block device,
c401cc
+     * then query highest allocated extent from QEMU
c401cc
+     */
c401cc
     if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
c401cc
         format != VIR_STORAGE_FILE_RAW &&
c401cc
-        S_ISBLK(sb.st_mode) &&
c401cc
-        virDomainObjIsActive(vm)) {
c401cc
+        S_ISBLK(sb.st_mode)) {
c401cc
         qemuDomainObjPrivatePtr priv = vm->privateData;
c401cc
 
c401cc
+        /* If the guest is not running, then success/failure return
c401cc
+         * depends on whether domain is persistent
c401cc
+         */
c401cc
+        if (!virDomainObjIsActive(vm)) {
c401cc
+            activeFail = true;
c401cc
+            ret = 0;
c401cc
+            goto cleanup;
c401cc
+        }
c401cc
+
c401cc
         if (VIR_STRDUP(alias, disk->info.alias) < 0)
c401cc
             goto cleanup;
c401cc
 
c401cc
@@ -10205,6 +10214,7 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
c401cc
                                             &info->allocation);
c401cc
             qemuDomainObjExitMonitor(driver, vm);
c401cc
         } else {
c401cc
+            activeFail = true;
c401cc
             ret = 0;
c401cc
         }
c401cc
 
c401cc
@@ -10218,6 +10228,15 @@ cleanup:
c401cc
     VIR_FREE(alias);
c401cc
     virStorageFileFreeMetadata(meta);
c401cc
     VIR_FORCE_CLOSE(fd);
c401cc
+
c401cc
+    /* If we failed to get data from a domain because it's inactive and
c401cc
+     * it's not a persistent domain, then force failure.
c401cc
+     */
c401cc
+    if (activeFail && vm && !vm->persistent) {
c401cc
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
c401cc
+                       _("domain is not running"));
c401cc
+        ret = -1;
c401cc
+    }
c401cc
     if (vm)
c401cc
         virObjectUnlock(vm);
c401cc
     virObjectUnref(cfg);
c401cc
-- 
c401cc
1.9.0
c401cc