]> xenbits.xensource.com Git - libvirt.git/commitdiff
virDomainGetBlockJobInfo: Fix corner case when qemu reports no info
authorMichal Privoznik <mprivozn@redhat.com>
Fri, 2 Sep 2016 07:45:44 +0000 (09:45 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Wed, 14 Sep 2016 10:44:42 +0000 (12:44 +0200)
https://bugzilla.redhat.com/show_bug.cgi?id=1372613

Apparently, some management applications use the following code
pattern when waiting for a block job to finish:

  while (1) {
    virDomainGetBlockJobInfo(dom, disk, info, flags);

    if (info.cur == info.end)
        break;

    sleep(1);
  }

Problem with this approach is in its corner cases. In case of
QEMU, libvirt merely pass what has been reported on the monitor.
However, if the block job hasn't started yet, qemu reports cur ==
end == 0 which tricks mgmt apps into thinking job is complete.

The solution is to mangle cur/end values as described here [1].

1: https://www.redhat.com/archives/libvir-list/2016-September/msg00017.html

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
src/libvirt-domain.c
src/qemu/qemu_driver.c

index 46f0318207c5953a2b202d8799a49dbba7a20e04..fa82e49b7173cd22e29972161dc420b1e89ec3e7 100644 (file)
@@ -9896,6 +9896,13 @@ virDomainBlockJobAbort(virDomainPtr dom, const char *disk,
  * can be found by calling virDomainGetXMLDesc() and inspecting
  * elements within //domain/devices/disk.
  *
+ * As a corner case underlying hypervisor may report cur == 0 and
+ * end == 0 when the block job hasn't been started yet. In this
+ * case libvirt reports cur = 0 and end = 1. However, hypervisor
+ * may return cur == 0 and end == 0 if the block job has finished
+ * and was no-op. In this case libvirt reports cur = 1 and end = 1.
+ * Since 2.3.0.
+ *
  * Returns -1 in case of failure, 0 when nothing found, 1 when info was found.
  */
 int
index 6b3a35540ab435be3559cabf804169e6c7502db1..e29180da4e75c6ae194ff0b81d640c2e44dc8014 100644 (file)
@@ -16318,6 +16318,18 @@ qemuBlockJobInfoTranslate(qemuMonitorBlockJobInfoPtr rawInfo,
     info->cur = rawInfo->cur;
     info->end = rawInfo->end;
 
+    /* Fix job completeness reporting. If cur == end mgmt
+     * applications think job is completed. Except when both cur
+     * and end are zero, in which case qemu hasn't started the
+     * job yet. */
+    if (!info->cur && !info->end) {
+        if (rawInfo->ready > 0) {
+            info->cur = info->end = 1;
+        } else if (!rawInfo->ready) {
+            info->end = 1;
+        }
+    }
+
     info->type = rawInfo->type;
     if (info->type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT &&
         disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT)