[libvirt] [PATCH] Block info query: Add flag to allow failure if not active

John Ferlan jferlan at redhat.com
Wed Dec 18 11:58:10 UTC 2013


Currently the qemuDomainGetBlockInfo will return allocation == physical
for most backing stores. For a qcow2 block backed device it's possible
to return the highest lv extent allocated from qemu for an active guest.
That is a value where allocation != physical and one would hope be less.
However, if the guest is not running, then the code falls back to returning
allocation == physical. This turns out to be problematic for rhev which
monitors the size of the backing store. During a migration, before the
VM has been started on the target and while it is deemed inactive on the
source, allocation is returned as physical triggering the code to extend
the file unnecessarily.

Thus, this patch will check a new flag to the call to determine whether
a failure should be returned to indicate to the caller that the code is
unable to fetch the allocation value. This will allow the caller to decide
how to proceed.

Note that I chose not to return a failure as a more general rule mostly
because of backwards compatability and current expectations reasons.
Changing a default return action could be an unexpected action. Although
returning allocation == physical perhaps is incorrect, it is how the
code has been functioning. Having a 'virsh domblkinfo' return a failure
for "some" inactive domains while succeeding for others could be confusing.
A flag forces the caller to decide how to operate.

As it turns out, there seems to be quite a bit of history regarding this.
Details can be found in the BZ:

https://bugzilla.redhat.com/show_bug.cgi?id=1040507
Signed-off-by: John Ferlan <jferlan at redhat.com>
---
NOTE:
Trying to keep this as simple as possible since it needs to be backported.
If someone has a better idea for a flag name - I'm open to suggestions...

 include/libvirt/libvirt.h.in | 23 ++++++++++++++++++++---
 src/libvirt.c                | 11 ++++++++++-
 src/qemu/qemu_driver.c       | 33 +++++++++++++++++++++++++++------
 3 files changed, 57 insertions(+), 10 deletions(-)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 6f79c49..420642b 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2095,7 +2095,8 @@ int                     virDomainBlockResize (virDomainPtr dom,
 
 /** virDomainBlockInfo:
  *
- * This struct provides information about the size of a block device backing store
+ * This struct provides information about the size of a block device
+ * backing store
  *
  * Examples:
  *
@@ -2108,13 +2109,29 @@ int                     virDomainBlockResize (virDomainPtr dom,
  *
  *  - qcow2 file in filesystem
  *       * capacity: logical size from qcow2 header
- *       * allocation, physical: logical size of the file / highest qcow extent (identical)
+ *       * allocation, physical: logical size of the file /
+ *                               highest qcow extent (identical)
  *
  *  - qcow2 file in a block device
  *       * capacity: logical size from qcow2 header
- *       * allocation: highest qcow extent written
+ *       * allocation: highest qcow extent written for an active domain
  *       * physical: size of the block device container
  */
+
+/**
+ * virDomainGetBlockInfoFlags:
+ *
+ * Flags available for virDomainGetBlockInfo().
+ */
+typedef enum {
+    VIR_DOMAIN_BLOCK_CHECK_ACTIVE = 1 << 0, /* If not active, then return
+                                             * failure when attempting to
+                                             * fetch data from an inactive
+                                             * domain, such as allocation
+                                             * from a qcow2 block device
+                                             */
+} virDomainGetBlockInfoFlags;
+
 typedef struct _virDomainBlockInfo virDomainBlockInfo;
 typedef virDomainBlockInfo *virDomainBlockInfoPtr;
 struct _virDomainBlockInfo {
diff --git a/src/libvirt.c b/src/libvirt.c
index d15d617..2159eaf 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -9027,7 +9027,7 @@ error:
  * @domain: a domain object
  * @disk: path to the block device, or device shorthand
  * @info: pointer to a virDomainBlockInfo structure allocated by the user
- * @flags: extra flags; not used yet, so callers should always pass 0
+ * @flags: bitwise-OR of supported virDomainGetBlockInfoFlags
  *
  * Extract information about a domain's block device.
  *
@@ -9038,6 +9038,15 @@ error:
  * can be found by calling virDomainGetXMLDesc() and inspecting
  * elements within //domain/devices/disk.
  *
+ * If the VIR_DOMAIN_BLOCK_CHECK_ACTIVE flag is set, then for any block
+ * information data that could differ depending on whether the domain was
+ * active or not, the hypervisor will return a failure when the domain
+ * is deemed to be inactive or unable to provide the data, such as may be
+ * the case during a migration. For example, the 'allocation' value for
+ * a qcow2 block device backed storage can return the highest extent written.
+ * However, this can only be determined if the domain is active. For an
+ * inactive domain, the allocation and physical values would be returned
+ * as identical.
  * Returns 0 in case of success and -1 in case of failure.
  */
 int
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 45d11cd..6303ce2 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -9799,9 +9799,10 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
     struct stat sb;
     int idx;
     int format;
+    int activeFail = false;
     virQEMUDriverConfigPtr cfg = NULL;
 
-    virCheckFlags(0, -1);
+    virCheckFlags(VIR_DOMAIN_BLOCK_CHECK_ACTIVE, -1);
 
     if (!(vm = qemuDomObjFromDomain(dom)))
         goto cleanup;
@@ -9897,15 +9898,24 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
     /* Set default value .. */
     info->allocation = info->physical;
 
-    /* ..but if guest is running & not using raw
-       disk format and on a block device, then query
-       highest allocated extent from QEMU */
+    /* ..but if guest is not using raw disk format and on a block device,
+     * then query highest allocated extent from QEMU
+     */
     if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
         format != VIR_STORAGE_FILE_RAW &&
-        S_ISBLK(sb.st_mode) &&
-        virDomainObjIsActive(vm)) {
+        S_ISBLK(sb.st_mode)) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
 
+        /* If the guest is not running, then success/failure return
+         * depends on whether the caller requested a failure on an
+         * inactive domain.
+         */
+        if (!virDomainObjIsActive(vm)) {
+            activeFail = true;
+            ret = 0;
+            goto cleanup;
+        }
+
         if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
             goto cleanup;
 
@@ -9916,6 +9926,7 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
                                             &info->allocation);
             qemuDomainObjExitMonitor(driver, vm);
         } else {
+            activeFail = true;
             ret = 0;
         }
 
@@ -9931,6 +9942,16 @@ cleanup:
     if (vm)
         virObjectUnlock(vm);
     virObjectUnref(cfg);
+
+    /* If we failed to get data from a domain because it's inactive and
+     * this flag is set, then we'll return failure
+     */
+    if (activeFail && (flags & VIR_DOMAIN_BLOCK_CHECK_ACTIVE)) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("unable to get allocation, domain is not running"));
+        ret = -1;
+    }
+
     return ret;
 }
 
-- 
1.8.3.1




More information about the libvir-list mailing list