c401cc
From 6c5f4650f23dba2188ceba75a36f40bbf895216e Mon Sep 17 00:00:00 2001
c401cc
Message-Id: <6c5f4650f23dba2188ceba75a36f40bbf895216e.1386932212.git.jdenemar@redhat.com>
c401cc
From: Michal Privoznik <mprivozn@redhat.com>
c401cc
Date: Tue, 10 Dec 2013 15:42:40 +0100
c401cc
Subject: [PATCH] qemu_process: Read errors from child
c401cc
c401cc
https://bugzilla.redhat.com/show_bug.cgi?id=1035955
c401cc
c401cc
There's a window when starting a qemu process between fork() and exec()
c401cc
during which we are doing things that may fail but not tunnelling the
c401cc
error to the daemon. This is basically all within qemuProcessHook().
c401cc
So whenever we fail in something, e.g. placing a process onto numa node,
c401cc
users are left with:
c401cc
c401cc
    error: Child quit during startup handshake: Input/output error
c401cc
c401cc
while the original error is thrown into the domain log:
c401cc
c401cc
    libvirt:  error : internal error: NUMA memory tuning in 'preferred'
c401cc
    mode only supports single node
c401cc
c401cc
Hence, we should read the log file and search for the error message and
c401cc
report it to users.
c401cc
c401cc
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
c401cc
(cherry picked from commit 11e44d66fd93a8614332e46977cafc1d5fbebe7a)
c401cc
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c401cc
---
c401cc
 src/qemu/qemu_process.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
c401cc
 1 file changed, 66 insertions(+)
c401cc
c401cc
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
c401cc
index 40e3754..a4b757c 100644
c401cc
--- a/src/qemu/qemu_process.c
c401cc
+++ b/src/qemu/qemu_process.c
c401cc
@@ -1543,6 +1543,70 @@ cleanup:
c401cc
 
c401cc
 
c401cc
 /*
c401cc
+ * Read domain log and probably overwrite error if there's one in
c401cc
+ * the domain log file. This function exists to cover the small
c401cc
+ * window between fork() and exec() during which child may fail
c401cc
+ * by libvirt's hand, e.g. placing onto a NUMA node failed.
c401cc
+ */
c401cc
+static int
c401cc
+qemuProcessReadChildErrors(virQEMUDriverPtr driver,
c401cc
+                           virDomainObjPtr vm,
c401cc
+                           off_t originalOff)
c401cc
+{
c401cc
+    int ret = -1;
c401cc
+    int logfd;
c401cc
+    off_t off = 0;
c401cc
+    ssize_t bytes;
c401cc
+    char buf[1024] = {0};
c401cc
+    char *eol, *filter_next = buf;
c401cc
+
c401cc
+    if ((logfd = qemuDomainOpenLog(driver, vm, originalOff)) < 0)
c401cc
+        goto cleanup;
c401cc
+
c401cc
+    while (off < sizeof(buf) - 1) {
c401cc
+        bytes = saferead(logfd, buf + off, sizeof(buf) - off - 1);
c401cc
+        if (bytes < 0) {
c401cc
+            VIR_WARN("unable to read from log file: %s",
c401cc
+                     virStrerror(errno, buf, sizeof(buf)));
c401cc
+            goto cleanup;
c401cc
+        }
c401cc
+
c401cc
+        off += bytes;
c401cc
+        buf[off] = '\0';
c401cc
+
c401cc
+        if (bytes == 0)
c401cc
+            break;
c401cc
+
c401cc
+        while ((eol = strchr(filter_next, '\n'))) {
c401cc
+            *eol = '\0';
c401cc
+            if (STRPREFIX(filter_next, "libvirt: ")) {
c401cc
+                filter_next = eol + 1;
c401cc
+                *eol = '\n';
c401cc
+                break;
c401cc
+            } else {
c401cc
+                memmove(filter_next, eol + 1, off - (eol - buf));
c401cc
+                off -= eol + 1 - filter_next;
c401cc
+            }
c401cc
+        }
c401cc
+    }
c401cc
+
c401cc
+    if (off > 0) {
c401cc
+        /* Found an error in the log. Report it */
c401cc
+        virResetLastError();
c401cc
+        virReportError(VIR_ERR_INTERNAL_ERROR,
c401cc
+                       _("Process exited prior to exec: %s"),
c401cc
+                       buf);
c401cc
+    }
c401cc
+
c401cc
+    ret = 0;
c401cc
+
c401cc
+cleanup:
c401cc
+    VIR_FORCE_CLOSE(logfd);
c401cc
+    return ret;
c401cc
+}
c401cc
+
c401cc
+
c401cc
+/*
c401cc
  * Look at a chunk of data from the QEMU stdout logs and try to
c401cc
  * find a TTY device, as indicated by a line like
c401cc
  *
c401cc
@@ -3877,6 +3941,8 @@ int qemuProcessStart(virConnectPtr conn,
c401cc
 
c401cc
     VIR_DEBUG("Waiting for handshake from child");
c401cc
     if (virCommandHandshakeWait(cmd) < 0) {
c401cc
+        /* Read errors from child that occurred between fork and exec. */
c401cc
+        qemuProcessReadChildErrors(driver, vm, pos);
c401cc
         goto cleanup;
c401cc
     }
c401cc
 
c401cc
-- 
c401cc
1.8.5.1
c401cc