[libvirt] [PATCH 3/5] logging: introduce log handling protocol

Daniel P. Berrange berrange at redhat.com
Tue Nov 3 16:04:22 UTC 2015


Define a new RPC protocol for the virtlogd daemon that provides
for handling of logs. The initial RPC method defined allows a
client to obtain a file handle to use for writing to a log
file for a guest domain. The file handle passed back will not
actually refer to the log file, but rather an anonymous pipe.
The virtlogd daemon will forward I/O between them, ensuring
file rotation happens when required.

Initially the log setup is hardcoded to cap log files at
128 KB, and keep 2 backups when rolling over.

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 po/POTFILES.in                    |   1 +
 src/Makefile.am                   |   4 +
 src/logging/log_daemon.c          |  30 +++
 src/logging/log_daemon.h          |   3 +
 src/logging/log_daemon_dispatch.c |  32 ++-
 src/logging/log_handler.c         | 429 ++++++++++++++++++++++++++++++++++++++
 src/logging/log_handler.h         |  46 ++++
 src/logging/log_protocol.x        |  49 +++++
 8 files changed, 593 insertions(+), 1 deletion(-)
 create mode 100644 src/logging/log_handler.c
 create mode 100644 src/logging/log_handler.h

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 33bc258..55baaae 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -80,6 +80,7 @@ src/locking/lock_manager.c
 src/locking/sanlock_helper.c
 src/logging/log_daemon.c
 src/logging/log_daemon_config.c
+src/logging/log_handler.c
 src/lxc/lxc_cgroup.c
 src/lxc/lxc_fuse.c
 src/lxc/lxc_hostdev.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 9f80f2b..b305cab 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -268,6 +268,8 @@ LOG_PROTOCOL_GENERATED = \
 		logging/log_protocol.c \
 		$(NULL)
 
+DRIVER_SOURCES += $(LOG_PROTOCOL_GENERATED)
+
 LOG_PROTOCOL = $(srcdir)/logging/log_protocol.x
 EXTRA_DIST += $(LOG_PROTOCOL) \
 	$(LOG_PROTOCOL_GENERATED)
@@ -289,6 +291,8 @@ LOG_DAEMON_SOURCES = \
 		logging/log_daemon_config.c \
 		logging/log_daemon_dispatch.c \
 		logging/log_daemon_dispatch.h \
+		logging/log_handler.c \
+		logging/log_handler.h \
 		$(NULL)
 
 logging/log_daemon_dispatch_stubs.h: $(LOG_PROTOCOL) \
diff --git a/src/logging/log_daemon.c b/src/logging/log_daemon.c
index 184076c..bc13257 100644
--- a/src/logging/log_daemon.c
+++ b/src/logging/log_daemon.c
@@ -60,6 +60,7 @@ struct _virLogDaemon {
     virMutex lock;
     virNetDaemonPtr dmn;
     virNetServerPtr srv;
+    virLogHandlerPtr handler;
 };
 
 virLogDaemonPtr logDaemon = NULL;
@@ -114,6 +115,7 @@ virLogDaemonFree(virLogDaemonPtr logd)
     if (!logd)
         return;
 
+    virObjectUnref(logd->handler);
     virObjectUnref(logd->srv);
     virObjectUnref(logd->dmn);
 
@@ -149,6 +151,9 @@ virLogDaemonNew(virLogDaemonConfigPtr config, bool privileged)
         virNetDaemonAddServer(logd->dmn, logd->srv) < 0)
         goto error;
 
+    if (!(logd->handler = virLogHandlerNew(privileged)))
+        goto error;
+
     return logd;
 
  error:
@@ -157,6 +162,12 @@ virLogDaemonNew(virLogDaemonConfigPtr config, bool privileged)
 }
 
 
+virLogHandlerPtr virLogDaemonGetHandler(virLogDaemonPtr daemon)
+{
+    return daemon->handler;
+}
+
+
 static virLogDaemonPtr
 virLogDaemonNewPostExecRestart(virJSONValuePtr object, bool privileged)
 {
@@ -190,6 +201,16 @@ virLogDaemonNewPostExecRestart(virJSONValuePtr object, bool privileged)
                                                     (void*)(intptr_t)(privileged ? 0x1 : 0x0))))
         goto error;
 
+    if (!(child = virJSONValueObjectGet(object, "handler"))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Malformed daemon data from JSON file"));
+        goto error;
+    }
+
+    if (!(logd->handler = virLogHandlerNewPostExecRestart(child,
+                                                          privileged)))
+        goto error;
+
     return logd;
 
  error:
@@ -778,6 +799,15 @@ virLogDaemonPreExecRestart(const char *state_file,
         goto cleanup;
     }
 
+    if (!(child = virLogHandlerPreExecRestart(logDaemon->handler)))
+        goto cleanup;
+
+    if (virJSONValueObjectAppend(object, "handler", child) < 0) {
+        virJSONValueFree(child);
+        goto cleanup;
+    }
+
+
     if (!(state = virJSONValueToString(object, true)))
         goto cleanup;
 
diff --git a/src/logging/log_daemon.h b/src/logging/log_daemon.h
index a153160..b076a4f 100644
--- a/src/logging/log_daemon.h
+++ b/src/logging/log_daemon.h
@@ -24,6 +24,7 @@
 # define __VIR_LOG_DAEMON_H__
 
 # include "virthread.h"
+# include "log_handler.h"
 
 typedef struct _virLogDaemon virLogDaemon;
 typedef virLogDaemon *virLogDaemonPtr;
@@ -39,4 +40,6 @@ struct _virLogDaemonClient {
 
 extern virLogDaemonPtr logDaemon;
 
+virLogHandlerPtr virLogDaemonGetHandler(virLogDaemonPtr daemon);
+
 #endif /* __VIR_LOG_DAEMON_H__ */
diff --git a/src/logging/log_daemon_dispatch.c b/src/logging/log_daemon_dispatch.c
index 98df178..d3464dd 100644
--- a/src/logging/log_daemon_dispatch.c
+++ b/src/logging/log_daemon_dispatch.c
@@ -1,7 +1,7 @@
 /*
  * log_daemon_dispatch.c: log management daemon dispatch
  *
- * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2015 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -29,9 +29,39 @@
 #include "log_daemon.h"
 #include "log_protocol.h"
 #include "virerror.h"
+#include "virthreadjob.h"
+#include "virfile.h"
 
 #define VIR_FROM_THIS VIR_FROM_RPC
 
 VIR_LOG_INIT("logging.log_daemon_dispatch");
 
 #include "log_daemon_dispatch_stubs.h"
+
+static int
+virLogManagerProtocolDispatchDomainOpenLogFile(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                               virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                               virNetMessagePtr msg,
+                                               virNetMessageErrorPtr rerr,
+                                               virLogManagerProtocolDomainOpenLogFileArgs *args)
+{
+    int fd = -1;
+    int ret = -1;
+
+    if ((fd = virLogHandlerDomainOpenLogFile(virLogDaemonGetHandler(logDaemon),
+                                             args->driver,
+                                             (unsigned char *)args->dom.uuid,
+                                             args->dom.name)) < 0)
+        goto cleanup;
+
+    if (virNetMessageAddFD(msg, fd) < 0)
+        goto cleanup;
+
+    ret = 1; /* '1' tells caller we added some FDs */
+
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+    if (ret < 0)
+        virNetMessageSaveError(rerr);
+    return ret;
+}
diff --git a/src/logging/log_handler.c b/src/logging/log_handler.c
new file mode 100644
index 0000000..b85f9e8
--- /dev/null
+++ b/src/logging/log_handler.c
@@ -0,0 +1,429 @@
+/*
+ * log_handler.c: log management daemon handler
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+#include "log_handler.h"
+#include "virerror.h"
+#include "virobject.h"
+#include "virfile.h"
+#include "viralloc.h"
+#include "virstring.h"
+#include "virlog.h"
+#include "virrotatingfile.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "configmake.h"
+
+VIR_LOG_INIT("logging.log_handler");
+
+#define VIR_FROM_THIS VIR_FROM_LOGGING
+
+typedef struct _virLogHandlerLogFile virLogHandlerLogFile;
+typedef virLogHandlerLogFile *virLogHandlerLogFilePtr;
+
+struct _virLogHandlerLogFile {
+    virRotatingFilePtr file;
+    int watch;
+    int pipefd; /* Read from QEMU via this */
+};
+
+struct _virLogHandler {
+    virObjectLockable parent;
+
+    bool privileged;
+    virLogHandlerLogFilePtr *files;
+    size_t nfiles;
+};
+
+static virClassPtr virLogHandlerClass;
+static void virLogHandlerDispose(void *obj);
+
+static int virLogHandlerOnceInit(void)
+{
+    if (!(virLogHandlerClass = virClassNew(virClassForObjectLockable(),
+                                          "virLogHandler",
+                                          sizeof(virLogHandler),
+                                          virLogHandlerDispose)))
+        return -1;
+
+    return 0;
+}
+
+VIR_ONCE_GLOBAL_INIT(virLogHandler)
+
+
+
+static void virLogHandlerLogFileFree(virLogHandlerLogFilePtr file)
+{
+    if (!file)
+        return;
+
+    VIR_FORCE_CLOSE(file->pipefd);
+    virRotatingFileFree(file->file);
+
+    if (file->watch != -1)
+        virEventRemoveHandle(file->watch);
+    VIR_FREE(file);
+}
+
+
+static void virLogHandlerLogFileClose(virLogHandlerPtr handler,
+                                      virLogHandlerLogFilePtr file)
+{
+    size_t i;
+
+    for (i = 0; i < handler->nfiles; i++) {
+        if (handler->files[i] == file) {
+            VIR_DELETE_ELEMENT(handler->files, i, handler->nfiles);
+            virLogHandlerLogFileFree(file);
+            break;
+        }
+    }
+}
+
+
+static virLogHandlerLogFilePtr
+virLogHandlerGetLogFileFromWatch(virLogHandlerPtr handler,
+                                 int watch)
+{
+    size_t i;
+
+    for (i = 0; i < handler->nfiles; i++) {
+        if (handler->files[i]->watch == watch)
+            return handler->files[i];
+    }
+
+    return NULL;
+}
+
+
+static void
+virLogHandlerDomainLogFileEvent(int watch,
+                                int fd,
+                                int events,
+                                void *opaque)
+{
+    virLogHandlerPtr handler = opaque;
+    virLogHandlerLogFilePtr logfile;
+    char buf[1024];
+    ssize_t len;
+
+    virObjectLock(handler);
+    logfile = virLogHandlerGetLogFileFromWatch(handler, watch);
+    if (!logfile || logfile->pipefd != fd) {
+        virEventRemoveHandle(watch);
+        return;
+    }
+
+ reread:
+    len = read(fd, buf, sizeof(buf));
+    if (len < 0) {
+        if (errno == EINTR)
+            goto reread;
+
+        virReportSystemError(errno, "%s",
+                             _("Unable to read from log pipe"));
+        goto error;
+    }
+
+    if (virRotatingFileWrite(logfile->file, buf, len) != len)
+        goto error;
+
+    if (events & VIR_EVENT_HANDLE_HANGUP)
+        goto error;
+
+    virObjectUnlock(handler);
+    return;
+
+ error:
+    virLogHandlerLogFileClose(handler, logfile);
+    virObjectUnlock(handler);
+}
+
+
+virLogHandlerPtr virLogHandlerNew(bool privileged)
+{
+    virLogHandlerPtr handler;
+
+    if (virLogHandlerInitialize() < 0)
+        goto error;
+
+    if (!(handler = virObjectLockableNew(virLogHandlerClass)))
+        goto error;
+
+    handler->privileged = privileged;
+
+    return handler;
+
+ error:
+    return NULL;
+}
+
+
+static virLogHandlerLogFilePtr virLogHandlerLogFilePostExecRestart(virJSONValuePtr object)
+{
+    virLogHandlerLogFilePtr file;
+    const char *path;
+
+    if (VIR_ALLOC(file) < 0)
+        return NULL;
+
+    if ((path = virJSONValueObjectGetString(object, "path")) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Missing file path in JSON document"));
+        goto error;
+    }
+
+    if ((file->file = virRotatingFileNew(path, 128 * 1024, 2, false, 0600)) == NULL)
+        goto error;
+
+    if (virJSONValueObjectGetNumberInt(object, "pipefd", &file->pipefd) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Missing file pipefd in JSON document"));
+        goto error;
+    }
+    if (virSetInherit(file->pipefd, false) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Cannot enable close-on-exec flag"));
+        goto error;
+    }
+
+    return file;
+
+ error:
+    virLogHandlerLogFileFree(file);
+    return NULL;
+}
+
+virLogHandlerPtr virLogHandlerNewPostExecRestart(virJSONValuePtr object,
+                                                 bool privileged)
+{
+    virLogHandlerPtr handler;
+    virJSONValuePtr files;
+    ssize_t n;
+    size_t i;
+
+    if (!(handler = virLogHandlerNew(privileged)))
+        return NULL;
+
+    if (!(files = virJSONValueObjectGet(object, "files"))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Missing files data from JSON file"));
+        goto error;
+    }
+
+    if ((n = virJSONValueArraySize(files)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Malformed files data from JSON file"));
+        goto error;
+    }
+
+    for (i = 0; i < n; i++) {
+        virLogHandlerLogFilePtr file;
+        virJSONValuePtr child = virJSONValueArrayGet(files, i);
+
+        if (!(file = virLogHandlerLogFilePostExecRestart(child)))
+            goto error;
+
+        if (VIR_APPEND_ELEMENT_COPY(handler->files, handler->nfiles, file) < 0)
+            goto error;
+
+        if ((file->watch = virEventAddHandle(file->pipefd,
+                                             VIR_EVENT_HANDLE_READABLE,
+                                             virLogHandlerDomainLogFileEvent,
+                                             handler,
+                                             NULL)) < 0) {
+            VIR_DELETE_ELEMENT(handler->files, handler->nfiles - 1, handler->nfiles);
+            goto error;
+        }
+    }
+
+
+    return handler;
+
+ error:
+    virObjectUnref(handler);
+    return NULL;
+}
+
+
+static void virLogHandlerDispose(void *obj)
+{
+    virLogHandlerPtr handler = obj;
+    size_t i;
+
+    for (i = 0; i < handler->nfiles; i++)
+        virLogHandlerLogFileFree(handler->files[i]);
+    VIR_FREE(handler->files);
+}
+
+
+static char *
+virLogHandlerGetLogFilePathForDomain(virLogHandlerPtr handler,
+                                    const char *driver,
+                                    const unsigned char *domuuid ATTRIBUTE_UNUSED,
+                                    const char *domname)
+{
+    char *path;
+    if (handler->privileged) {
+        if (virAsprintf(&path,
+                        LOCALSTATEDIR "/log/libvirt/%s/%s.log",
+                        driver, domname) < 0)
+            return NULL;
+    } else {
+        char *cachedir;
+
+        cachedir = virGetUserCacheDirectory();
+        if (!cachedir)
+            return NULL;
+
+        if (virAsprintf(&path,
+                        "%s/%s/log/%s.log", cachedir, driver, domname) < 0) {
+            VIR_FREE(cachedir);
+            return NULL;
+        }
+
+    }
+    return path;
+}
+
+int virLogHandlerDomainOpenLogFile(virLogHandlerPtr handler,
+                                   const char *driver,
+                                   const unsigned char *domuuid ATTRIBUTE_UNUSED,
+                                   const char *domname)
+{
+    size_t i;
+    virLogHandlerLogFilePtr file = NULL;
+    int pipefd[2] = { -1, -1 };
+    char *path;
+
+    virObjectLock(handler);
+
+    if (!(path = virLogHandlerGetLogFilePathForDomain(handler,
+                                                      driver,
+                                                      domuuid,
+                                                      domname)))
+        goto error;
+
+    for (i = 0; i < handler->nfiles; i++) {
+        if (STREQ(virRotatingFileGetPath(handler->files[i]->file),
+                  path)) {
+            virReportSystemError(EBUSY,
+                                 _("Cannot open log file: '%s'"),
+                                 path);
+            goto error;
+        }
+    }
+
+    if (pipe(pipefd) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Cannot open fifo pipe"));
+        goto error;
+    }
+    if (VIR_ALLOC(file) < 0)
+        goto error;
+
+    file->watch = -1;
+    file->pipefd = pipefd[0];
+    pipefd[0] = -1;
+
+    if ((file->file = virRotatingFileNew(path, 128 * 1024, 2, false, 0600)) == NULL)
+        goto error;
+
+    if (VIR_APPEND_ELEMENT_COPY(handler->files, handler->nfiles, file) < 0)
+        goto error;
+
+    if ((file->watch = virEventAddHandle(file->pipefd,
+                                         VIR_EVENT_HANDLE_READABLE,
+                                         virLogHandlerDomainLogFileEvent,
+                                         handler,
+                                         NULL)) < 0) {
+        VIR_DELETE_ELEMENT(handler->files, handler->nfiles - 1, handler->nfiles);
+        goto error;
+    }
+
+    VIR_FREE(path);
+
+    virObjectUnlock(handler);
+    return pipefd[1];
+
+ error:
+    VIR_FREE(path);
+    VIR_FORCE_CLOSE(pipefd[0]);
+    VIR_FORCE_CLOSE(pipefd[1]);
+    virLogHandlerLogFileFree(file);
+    virObjectUnlock(handler);
+    return -1;
+}
+
+
+virJSONValuePtr virLogHandlerPreExecRestart(virLogHandlerPtr handler)
+{
+    virJSONValuePtr ret = virJSONValueNewObject();
+    virJSONValuePtr files;
+    size_t i;
+
+    if (!ret)
+        return NULL;
+
+    if (!(files = virJSONValueNewArray()))
+        goto error;
+
+    if (virJSONValueObjectAppend(ret, "files", files) < 0) {
+        virJSONValueFree(files);
+        goto error;
+    }
+
+    for (i = 0; i < handler->nfiles; i++) {
+        virJSONValuePtr file = virJSONValueNewObject();
+        if (!file)
+            goto error;
+
+        if (virJSONValueArrayAppend(files, file) < 0) {
+            virJSONValueFree(file);
+            goto error;
+        }
+
+        if (virJSONValueObjectAppendNumberInt(file, "pipefd",
+                                              handler->files[i]->pipefd) < 0)
+            goto error;
+
+        if (virJSONValueObjectAppendString(file, "path",
+                                           virRotatingFileGetPath(handler->files[i]->file)) < 0)
+            goto error;
+
+        if (virSetInherit(handler->files[i]->pipefd, true) < 0) {
+            virReportSystemError(errno, "%s",
+                                 _("Cannot disable close-on-exec flag"));
+            goto error;
+        }
+    }
+
+    return ret;
+
+ error:
+    virJSONValueFree(ret);
+    return NULL;
+}
diff --git a/src/logging/log_handler.h b/src/logging/log_handler.h
new file mode 100644
index 0000000..300a177
--- /dev/null
+++ b/src/logging/log_handler.h
@@ -0,0 +1,46 @@
+/*
+ * log_handler.h: log management daemon handler
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#ifndef __VIR_LOG_HANDLER_H__
+# define __VIR_LOG_HANDLER_H__
+
+# include "internal.h"
+# include "virjson.h"
+
+typedef struct _virLogHandler virLogHandler;
+typedef virLogHandler *virLogHandlerPtr;
+
+
+virLogHandlerPtr virLogHandlerNew(bool privileged);
+virLogHandlerPtr virLogHandlerNewPostExecRestart(virJSONValuePtr child,
+                                                 bool privileged);
+
+void virLogHandlerFree(virLogHandlerPtr handler);
+
+int virLogHandlerDomainOpenLogFile(virLogHandlerPtr handler,
+                                   const char *driver,
+                                   const unsigned char *domuuid,
+                                   const char *domname);
+
+virJSONValuePtr virLogHandlerPreExecRestart(virLogHandlerPtr handler);
+
+#endif /** __VIR_LOG_HANDLER_H__ */
diff --git a/src/logging/log_protocol.x b/src/logging/log_protocol.x
index 9b8fa41..4fbcd41 100644
--- a/src/logging/log_protocol.x
+++ b/src/logging/log_protocol.x
@@ -17,6 +17,55 @@ typedef string virLogManagerProtocolNonNullString<VIR_LOG_MANAGER_PROTOCOL_STRIN
 /* A long string, which may be NULL. */
 typedef virLogManagerProtocolNonNullString *virLogManagerProtocolString;
 
+struct virLogManagerProtocolDomain {
+    virLogManagerProtocolUUID uuid;
+    virLogManagerProtocolNonNullString name;
+};
+typedef struct virLogManagerProtocolDomain virLogManagerProtocolDomain;
+
+/* Obtain a file handle suitable for writing to a
+ * log file for a domain
+ */
+struct virLogManagerProtocolDomainOpenLogFileArgs {
+    virLogManagerProtocolNonNullString driver;
+    virLogManagerProtocolDomain dom;
+    unsigned int flags;
+};
+
 /* Define the program number, protocol version and procedure numbers here. */
 const VIR_LOG_MANAGER_PROTOCOL_PROGRAM = 0x87539319;
 const VIR_LOG_MANAGER_PROTOCOL_PROGRAM_VERSION = 1;
+
+enum virLogManagerProtocolProcedure {
+    /* Each function must be preceded by a comment providing one or
+     * more annotations:
+     *
+     * - @generate: none|client|server|both
+     *
+     *   Whether to generate the dispatch stubs for the server
+     *   and/or client code.
+     *
+     * - @readstream: paramnumber
+     * - @writestream: paramnumber
+     *
+     *   The @readstream or @writestream annotations let daemon and src/remote
+     *   create a stream.  The direction is defined from the src/remote point
+     *   of view.  A readstream transfers data from daemon to src/remote.  The
+     *   <paramnumber> specifies at which offset the stream parameter is inserted
+     *   in the function parameter list.
+     *
+     * - @priority: low|high
+     *
+     *   Each API that might eventually access hypervisor's  monitor (and thus
+     *   block) MUST fall into low priority. However, there are some exceptions
+     *   to this rule, e.g. domainDestroy. Other APIs MAY  be marked as high
+     *   priority. If in doubt, it's safe to choose low. Low is taken as default,
+     *   and thus can be left out.
+     */
+
+    /**
+     * @generate: none
+     * @acl: none
+     */
+    VIR_LOG_MANAGER_PROTOCOL_PROC_DOMAIN_OPEN_LOG_FILE = 1
+};
-- 
2.5.0




More information about the libvir-list mailing list