[libvirt] [PATCH 2/2] log: drain log of exiting qemu process carefully

Nikolay Shirokovskiy nshirokovskiy at virtuozzo.com
Mon Sep 12 11:12:10 UTC 2016


Read API call of logger daemon is used to get extra
information from terminated qemu process. For this purpose
we need to wait until qemu process finishes its writing to log.
We need to:

1. Read until EOF.
2. Don't stop reading on hangup.

virtlogd will not receive EOF as both qemu and libvirtd
keep logging pipe descriptor. Thus let's close it after
qemu process startup is finished as it will not be used
anymore. All following logging on behalf of qemu by libvirt
is done either thru daemon API or by receiving new
writing descriptor.

Beware, qemuDomainLogContextFree is unref actually.
---
 src/logging/log_handler.c | 39 +++++++++++++++++++++++++++++++++++++--
 src/qemu/qemu_domain.c    |  4 ++++
 src/qemu/qemu_domain.h    |  1 +
 src/qemu/qemu_process.c   |  2 ++
 4 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/src/logging/log_handler.c b/src/logging/log_handler.c
index cd0ba6e..d0479c9 100644
--- a/src/logging/log_handler.c
+++ b/src/logging/log_handler.c
@@ -54,10 +54,12 @@ struct _virLogHandlerLogFile {
     char *driver;
     unsigned char domuuid[VIR_UUID_BUFLEN];
     char *domname;
+    char *path;
 };
 
 struct _virLogHandler {
     virObjectLockable parent;
+    virCond condition;
 
     bool privileged;
     size_t max_size;
@@ -102,6 +104,7 @@ virLogHandlerLogFileFree(virLogHandlerLogFilePtr file)
 
     VIR_FREE(file->driver);
     VIR_FREE(file->domname);
+    VIR_FREE(file->path);
     VIR_FREE(file);
 }
 
@@ -137,6 +140,21 @@ virLogHandlerGetLogFileFromWatch(virLogHandlerPtr handler,
 }
 
 
+static virLogHandlerLogFilePtr
+virLogHandlerGetLogFileFromPath(virLogHandlerPtr handler,
+                                const char* path)
+{
+    size_t i;
+
+    for (i = 0; i < handler->nfiles; i++) {
+        if (STREQ(handler->files[i]->path, path))
+            return handler->files[i];
+    }
+
+    return NULL;
+}
+
+
 static void
 virLogHandlerDomainLogFileEvent(int watch,
                                 int fd,
@@ -167,11 +185,14 @@ virLogHandlerDomainLogFileEvent(int watch,
         goto error;
     }
 
+    if (len == 0)
+        goto error;
+
     if (virRotatingFileWriterAppend(logfile->file, buf, len) != len)
         goto error;
 
     if (events & VIR_EVENT_HANDLE_HANGUP)
-        goto error;
+        goto reread;
 
     virObjectUnlock(handler);
     return;
@@ -179,6 +200,7 @@ virLogHandlerDomainLogFileEvent(int watch,
  error:
     handler->inhibitor(false, handler->opaque);
     virLogHandlerLogFileClose(handler, logfile);
+    virCondBroadcast(&handler->condition);
     virObjectUnlock(handler);
 }
 
@@ -198,6 +220,9 @@ virLogHandlerNew(bool privileged,
     if (!(handler = virObjectLockableNew(virLogHandlerClass)))
         goto error;
 
+    if (virCondInit(&handler->condition) < 0)
+        goto error;
+
     handler->privileged = privileged;
     handler->max_size = max_size;
     handler->max_backups = max_backups;
@@ -357,6 +382,7 @@ virLogHandlerDispose(void *obj)
         virLogHandlerLogFileFree(handler->files[i]);
     }
     VIR_FREE(handler->files);
+    virCondDestroy(&handler->condition);
 }
 
 
@@ -401,7 +427,8 @@ virLogHandlerDomainOpenLogFile(virLogHandlerPtr handler,
     pipefd[0] = -1;
     memcpy(file->domuuid, domuuid, VIR_UUID_BUFLEN);
     if (VIR_STRDUP(file->driver, driver) < 0 ||
-        VIR_STRDUP(file->domname, domname) < 0)
+        VIR_STRDUP(file->domname, domname) < 0 ||
+        VIR_STRDUP(file->path, path) < 0)
         goto error;
 
     if ((file->file = virRotatingFileWriterNew(path,
@@ -496,6 +523,14 @@ virLogHandlerDomainReadLogFile(virLogHandlerPtr handler,
 
     virObjectLock(handler);
 
+    while (virLogHandlerGetLogFileFromPath(handler, path)) {
+        if (virCondWait(&handler->condition, &handler->parent.lock) < 0) {
+            virReportSystemError(errno, "%s",
+                                 _("failed to wait for EOF"));
+            goto error;
+        }
+    }
+
     if (!(file = virRotatingFileReaderNew(path, handler->max_backups)))
         goto error;
 
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index fd79390..26a0255 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -3974,6 +3974,10 @@ virLogManagerPtr qemuDomainLogContextGetManager(qemuDomainLogContextPtr ctxt)
     return ctxt->manager;
 }
 
+void qemuDomainLogContextHalfClose(qemuDomainLogContextPtr ctxt)
+{
+    VIR_FORCE_CLOSE(ctxt->writefd);
+}
 
 void qemuDomainLogContextFree(qemuDomainLogContextPtr ctxt)
 {
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 13c0372..71fe6ad 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -499,6 +499,7 @@ ssize_t qemuDomainLogContextRead(qemuDomainLogContextPtr ctxt,
 int qemuDomainLogContextGetWriteFD(qemuDomainLogContextPtr ctxt);
 void qemuDomainLogContextMarkPosition(qemuDomainLogContextPtr ctxt);
 void qemuDomainLogContextRef(qemuDomainLogContextPtr ctxt);
+void qemuDomainLogContextHalfClose(qemuDomainLogContextPtr ctxt);
 void qemuDomainLogContextFree(qemuDomainLogContextPtr ctxt);
 
 virLogManagerPtr qemuDomainLogContextGetManager(qemuDomainLogContextPtr ctxt);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 7596579..737b2e0 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -5493,6 +5493,8 @@ qemuProcessLaunch(virConnectPtr conn,
  cleanup:
     qemuDomainSecretDestroy(vm);
     virCommandFree(cmd);
+    if (logCtxt)
+        qemuDomainLogContextHalfClose(logCtxt);
     qemuDomainLogContextFree(logCtxt);
     virObjectUnref(cfg);
     virObjectUnref(caps);
-- 
1.8.3.1




More information about the libvir-list mailing list