File 85af0b80-qemu-adaptive-montimeout.patch of Package libvirt.6159

commit 85af0b803cd19a03f71bd01ab4e045552410368f
Author: Michal Privoznik <mprivozn@redhat.com>
Date:   Sat Mar 11 07:23:42 2017 +0100

    qemu: Adaptive timeout for connecting to monitor
    
    There were couple of reports on the list (e.g. [1]) that guests
    with huge amounts of RAM are unable to start because libvirt
    kills qemu in the initialization phase. The problem is that if
    guest is configured to use hugepages kernel has to zero them all
    out before handing over to qemu process. For instance, 402GiB
    worth of 1GiB pages took around 105 seconds (~3.8GiB/s). Since we
    do not want to make the timeout for connecting to monitor
    configurable, we have to teach libvirt to count with this
    fact. This commit implements "1s per each 1GiB of RAM" approach
    as suggested here [2].
    
    1: https://www.redhat.com/archives/libvir-list/2017-March/msg00373.html
    2: https://www.redhat.com/archives/libvir-list/2017-March/msg00405.html
    
    Signed-off-by: Michal Privoznik <mprivozn@redhat.com>

Index: libvirt-2.0.0/src/qemu/qemu_capabilities.c
===================================================================
--- libvirt-2.0.0.orig/src/qemu/qemu_capabilities.c
+++ libvirt-2.0.0/src/qemu/qemu_capabilities.c
@@ -3658,7 +3658,7 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCa
 
     vm->pid = pid;
 
-    if (!(mon = qemuMonitorOpen(vm, &config, true, &callbacks, NULL))) {
+    if (!(mon = qemuMonitorOpen(vm, &config, true, 0, &callbacks, NULL))) {
         ret = 0;
         goto cleanup;
     }
Index: libvirt-2.0.0/src/qemu/qemu_monitor.c
===================================================================
--- libvirt-2.0.0.orig/src/qemu/qemu_monitor.c
+++ libvirt-2.0.0/src/qemu/qemu_monitor.c
@@ -324,11 +324,13 @@ qemuMonitorDispose(void *obj)
 
 
 static int
-qemuMonitorOpenUnix(const char *monitor, pid_t cpid)
+qemuMonitorOpenUnix(const char *monitor,
+                    pid_t cpid,
+                    unsigned long long timeout)
 {
     struct sockaddr_un addr;
     int monfd;
-    virTimeBackOffVar timeout;
+    virTimeBackOffVar timebackoff;
     int ret = -1;
 
     if ((monfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
@@ -345,9 +347,9 @@ qemuMonitorOpenUnix(const char *monitor,
         goto error;
     }
 
-    if (virTimeBackOffStart(&timeout, 1, 30*1000 /* ms */) < 0)
+    if (virTimeBackOffStart(&timebackoff, 1, timeout * 1000) < 0)
         goto error;
-    while (virTimeBackOffWait(&timeout)) {
+    while (virTimeBackOffWait(&timebackoff)) {
         ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr));
 
         if (ret == 0)
@@ -868,10 +870,30 @@ qemuMonitorOpenInternal(virDomainObjPtr
 }
 
 
+#define QEMU_DEFAULT_MONITOR_WAIT 30
+
+/**
+ * qemuMonitorOpen:
+ * @vm: domain object
+ * @config: monitor configuration
+ * @json: enable JSON on the monitor
+ * @timeout: number of seconds to add to default timeout
+ * @cb: monitor event handles
+ * @opaque: opaque data for @cb
+ *
+ * Opens the monitor for running qemu. It may happen that it
+ * takes some time for qemu to create the monitor socket (e.g.
+ * because kernel is zeroing configured hugepages), therefore we
+ * wait up to default + timeout seconds for the monitor to show
+ * up after which a failure is claimed.
+ *
+ * Returns monitor object, NULL on error.
+ */
 qemuMonitorPtr
 qemuMonitorOpen(virDomainObjPtr vm,
                 virDomainChrSourceDefPtr config,
                 bool json,
+                unsigned long long timeout,
                 qemuMonitorCallbacksPtr cb,
                 void *opaque)
 {
@@ -879,10 +901,14 @@ qemuMonitorOpen(virDomainObjPtr vm,
     bool hasSendFD = false;
     qemuMonitorPtr ret;
 
+    timeout += QEMU_DEFAULT_MONITOR_WAIT;
+
     switch (config->type) {
     case VIR_DOMAIN_CHR_TYPE_UNIX:
         hasSendFD = true;
-        if ((fd = qemuMonitorOpenUnix(config->data.nix.path, vm ? vm->pid : 0)) < 0)
+        if ((fd = qemuMonitorOpenUnix(config->data.nix.path,
+                                      vm ? vm->pid : 0,
+                                      timeout)) < 0)
             return NULL;
         break;
 
Index: libvirt-2.0.0/src/qemu/qemu_monitor.h
===================================================================
--- libvirt-2.0.0.orig/src/qemu/qemu_monitor.h
+++ libvirt-2.0.0/src/qemu/qemu_monitor.h
@@ -246,6 +246,7 @@ char *qemuMonitorUnescapeArg(const char
 qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm,
                                virDomainChrSourceDefPtr config,
                                bool json,
+                               unsigned long long timeout,
                                qemuMonitorCallbacksPtr cb,
                                void *opaque)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4);
Index: libvirt-2.0.0/src/qemu/qemu_process.c
===================================================================
--- libvirt-2.0.0.orig/src/qemu/qemu_process.c
+++ libvirt-2.0.0/src/qemu/qemu_process.c
@@ -1675,6 +1675,7 @@ qemuConnectMonitor(virQEMUDriverPtr driv
     qemuDomainObjPrivatePtr priv = vm->privateData;
     int ret = -1;
     qemuMonitorPtr mon = NULL;
+    unsigned long long timeout = 0;
 
     if (virSecurityManagerSetDaemonSocketLabel(driver->securityManager,
                                                vm->def) < 0) {
@@ -1683,6 +1684,12 @@ qemuConnectMonitor(virQEMUDriverPtr driv
         return -1;
     }
 
+    /* When using hugepages, kernel zeroes them out before
+     * handing them over to qemu. This can be very time
+     * consuming. Therefore, add a second to timeout for each
+     * 1GiB of guest RAM. */
+    timeout = vm->def->mem.total_memory / (1024 * 1024);
+
     /* Hold an extra reference because we can't allow 'vm' to be
      * deleted unitl the monitor gets its own reference. */
     virObjectRef(vm);
@@ -1693,6 +1700,7 @@ qemuConnectMonitor(virQEMUDriverPtr driv
     mon = qemuMonitorOpen(vm,
                           priv->monConfig,
                           priv->monJSON,
+                          timeout,
                           &monitorCallbacks,
                           driver);
 
Index: libvirt-2.0.0/tests/qemumonitortestutils.c
===================================================================
--- libvirt-2.0.0.orig/tests/qemumonitortestutils.c
+++ libvirt-2.0.0/tests/qemumonitortestutils.c
@@ -902,6 +902,7 @@ qemuMonitorTestNew(bool json,
     if (!(test->mon = qemuMonitorOpen(test->vm,
                                       &src,
                                       json,
+                                      0,
                                       &qemuMonitorTestCallbacks,
                                       driver)))
         goto error;