|
|
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 |
|