[PATCH 00/10] Enabling logging for ch guests

LogContext management is now moved from Qemu driver to hypervisor. After migrating Qemu to use domain_logcontext, I extended ch driver to use also use domain_logcontext to capture early boot failures within domain specific log files. Changes in V2: * refactored the patches to ensure all of them build. Praveen K Paladugu (10): hypervisor: copy qemu log context mgmt to hypervisor hypervisor: rename reference to qemu in domain_logcontext hypervisor: drop qemu specific args in domainLogContextNew hypervisor: Build domain_logcontext libvirt_private: export symbols from domain_logcontext qemu: Modify qemu driver to use domainLogContext qemu: delete qemu_logcontext files ch: Enable logging for ch domains ch: move curl_data and curl_callback definitions ch: Enable logging curl responses from ch po/POTFILES | 2 +- src/ch/ch_conf.h | 2 + src/ch/ch_monitor.c | 84 ++++++++++++------- src/ch/ch_monitor.h | 6 +- src/ch/ch_process.c | 36 ++++++-- .../domain_logcontext.c} | 78 +++++++++-------- src/hypervisor/domain_logcontext.h | 45 ++++++++++ src/hypervisor/meson.build | 1 + src/libvirt_private.syms | 6 ++ src/qemu/meson.build | 1 - src/qemu/qemu_domain.c | 28 +++---- src/qemu/qemu_domain.h | 12 +-- src/qemu/qemu_logcontext.h | 41 --------- src/qemu/qemu_nbdkit.c | 12 ++- src/qemu/qemu_process.c | 45 +++++----- 15 files changed, 235 insertions(+), 164 deletions(-) rename src/{qemu/qemu_logcontext.c => hypervisor/domain_logcontext.c} (79%) create mode 100644 src/hypervisor/domain_logcontext.h delete mode 100644 src/qemu/qemu_logcontext.h -- 2.47.0

Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- po/POTFILES | 1 + src/hypervisor/domain_logcontext.c | 329 +++++++++++++++++++++++++++++ src/hypervisor/domain_logcontext.h | 41 ++++ 3 files changed, 371 insertions(+) create mode 100644 src/hypervisor/domain_logcontext.c create mode 100644 src/hypervisor/domain_logcontext.h diff --git a/po/POTFILES b/po/POTFILES index 3514aa3dca..1d3c3c0a81 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -94,6 +94,7 @@ src/hyperv/hyperv_util.c src/hyperv/hyperv_wmi.c src/hypervisor/domain_cgroup.c src/hypervisor/domain_driver.c +src/hypervisor/domain_logcontext.c src/hypervisor/domain_interface.c src/hypervisor/virhostdev.c src/interface/interface_backend_netcf.c diff --git a/src/hypervisor/domain_logcontext.c b/src/hypervisor/domain_logcontext.c new file mode 100644 index 0000000000..7932cf7712 --- /dev/null +++ b/src/hypervisor/domain_logcontext.c @@ -0,0 +1,329 @@ +/* + * domain_logcontext.c: QEMU log context + * + * 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/>. + */ + +#include <config.h> + +#include "qemu_logcontext.h" +#include "viralloc.h" +#include "virlog.h" +#include "virstring.h" +#include "virutil.h" + +#include <fcntl.h> + +#define VIR_FROM_THIS VIR_FROM_QEMU + +VIR_LOG_INIT("qemu.qemu_logcontext"); + + +struct _qemuLogContext { + GObject parent; + + int writefd; + int readfd; /* Only used if manager == NULL */ + off_t pos; + ino_t inode; /* Only used if manager != NULL */ + char *path; + virLogManager *manager; +}; + +G_DEFINE_TYPE(qemuLogContext, qemu_log_context, G_TYPE_OBJECT); + +static void +qemuLogContextFinalize(GObject *obj); + + +static void +qemu_log_context_init(qemuLogContext *logctxt G_GNUC_UNUSED) +{ +} + + +static void +qemu_log_context_class_init(qemuLogContextClass *klass) +{ + GObjectClass *obj = G_OBJECT_CLASS(klass); + + obj->finalize = qemuLogContextFinalize; +} + + +static void +qemuLogContextFinalize(GObject *object) +{ + qemuLogContext *ctxt = QEMU_LOG_CONTEXT(object); + VIR_DEBUG("ctxt=%p", ctxt); + + virLogManagerFree(ctxt->manager); + VIR_FREE(ctxt->path); + VIR_FORCE_CLOSE(ctxt->writefd); + VIR_FORCE_CLOSE(ctxt->readfd); + G_OBJECT_CLASS(qemu_log_context_parent_class)->finalize(object); +} + + +qemuLogContext * +qemuLogContextNew(virQEMUDriver *driver, + virDomainObj *vm, + const char *basename) +{ + g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); + qemuLogContext *ctxt = QEMU_LOG_CONTEXT(g_object_new(QEMU_TYPE_LOG_CONTEXT, NULL)); + + VIR_DEBUG("Context new %p stdioLogD=%d", ctxt, cfg->stdioLogD); + ctxt->writefd = -1; + ctxt->readfd = -1; + + ctxt->path = g_strdup_printf("%s/%s.log", cfg->logDir, basename); + + if (cfg->stdioLogD) { + ctxt->manager = virLogManagerNew(driver->privileged); + if (!ctxt->manager) + goto error; + + ctxt->writefd = virLogManagerDomainOpenLogFile(ctxt->manager, + "qemu", + vm->def->uuid, + vm->def->name, + ctxt->path, + 0, + &ctxt->inode, + &ctxt->pos); + if (ctxt->writefd < 0) + goto error; + } else { + if ((ctxt->writefd = open(ctxt->path, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)) < 0) { + virReportSystemError(errno, _("failed to create logfile %1$s"), + ctxt->path); + goto error; + } + if (virSetCloseExec(ctxt->writefd) < 0) { + virReportSystemError(errno, _("failed to set close-on-exec flag on %1$s"), + ctxt->path); + goto error; + } + + /* For unprivileged startup we must truncate the file since + * we can't rely on logrotate. We don't use O_TRUNC since + * it is better for SELinux policy if we truncate afterwards */ + if (!driver->privileged && + ftruncate(ctxt->writefd, 0) < 0) { + virReportSystemError(errno, _("failed to truncate %1$s"), + ctxt->path); + goto error; + } + + if ((ctxt->readfd = open(ctxt->path, O_RDONLY)) < 0) { + virReportSystemError(errno, _("failed to open logfile %1$s"), + ctxt->path); + goto error; + } + if (virSetCloseExec(ctxt->readfd) < 0) { + virReportSystemError(errno, _("failed to set close-on-exec flag on %1$s"), + ctxt->path); + goto error; + } + + if ((ctxt->pos = lseek(ctxt->writefd, 0, SEEK_END)) < 0) { + virReportSystemError(errno, _("failed to seek in log file %1$s"), + ctxt->path); + goto error; + } + } + + return ctxt; + + error: + g_clear_object(&ctxt); + return NULL; +} + + +int +qemuLogContextWrite(qemuLogContext *ctxt, + const char *fmt, ...) +{ + va_list argptr; + g_autofree char *message = NULL; + int ret = -1; + + va_start(argptr, fmt); + + message = g_strdup_vprintf(fmt, argptr); + if (!ctxt->manager && + lseek(ctxt->writefd, 0, SEEK_END) < 0) { + virReportSystemError(errno, "%s", + _("Unable to seek to end of domain logfile")); + goto cleanup; + } + if (safewrite(ctxt->writefd, message, strlen(message)) < 0) { + virReportSystemError(errno, "%s", + _("Unable to write to domain logfile")); + goto cleanup; + } + + ret = 0; + + cleanup: + va_end(argptr); + return ret; +} + + +ssize_t +qemuLogContextRead(qemuLogContext *ctxt, + char **msg) +{ + char *buf; + size_t buflen; + + VIR_DEBUG("Context read %p manager=%p inode=%llu pos=%llu", + ctxt, ctxt->manager, + (unsigned long long)ctxt->inode, + (unsigned long long)ctxt->pos); + + if (ctxt->manager) { + buf = virLogManagerDomainReadLogFile(ctxt->manager, + ctxt->path, + ctxt->inode, + ctxt->pos, + 1024 * 128, + 0); + if (!buf) + return -1; + buflen = strlen(buf); + } else { + ssize_t got; + + buflen = 1024 * 128; + + /* Best effort jump to start of messages */ + ignore_value(lseek(ctxt->readfd, ctxt->pos, SEEK_SET)); + + buf = g_new0(char, buflen); + + got = saferead(ctxt->readfd, buf, buflen - 1); + if (got < 0) { + VIR_FREE(buf); + virReportSystemError(errno, "%s", + _("Unable to read from log file")); + return -1; + } + + buf[got] = '\0'; + + buf = g_renew(char, buf, got + 1); + buflen = got; + } + + *msg = buf; + + return buflen; +} + + +/** + * qemuLogContextFilter: Read and filter log for relevant messages + * @ctxt: the domain log context + * @msg: pointer to buffer to store the read messages in + * @max: maximum length of the message returned in @msg after filtering + * + * Reads log output from @ctxt and filters it. Skips messages not produced by + * the target executable or irrelevant messages. If @max is not zero, @buf will + * contain at most @max characters from the end of the log and @buf will start + * after a new line if possible. + */ +int +qemuLogContextReadFiltered(qemuLogContext *ctxt, + char **msg, + size_t max) +{ + char *buf; + char *eol; + char *filter_next; + size_t skip; + ssize_t got; + + if ((got = qemuLogContextRead(ctxt, &buf)) < 0) + return -1; + + /* Filter out debug messages from intermediate libvirt process */ + filter_next = buf; + while ((eol = strchr(filter_next, '\n'))) { + *eol = '\0'; + if (virLogProbablyLogMessage(filter_next) || + strstr(filter_next, "char device redirected to")) { + skip = (eol + 1) - filter_next; + memmove(filter_next, eol + 1, buf + got - eol); + got -= skip; + } else { + filter_next = eol + 1; + *eol = '\n'; + } + } + + if (got > 0 && + buf[got - 1] == '\n') { + buf[got - 1] = '\0'; + got--; + } + + if (max > 0 && got > max) { + skip = got - max; + + if (buf[skip - 1] != '\n' && + (eol = strchr(buf + skip, '\n')) && + !virStringIsEmpty(eol + 1)) + skip = eol + 1 - buf; + + memmove(buf, buf + skip, got - skip + 1); + got -= skip; + } + + buf = g_renew(char, buf, got + 1); + *msg = buf; + return 0; +} + + +int +qemuLogContextGetWriteFD(qemuLogContext *ctxt) +{ + return ctxt->writefd; +} + + +void +qemuLogContextMarkPosition(qemuLogContext *ctxt) +{ + if (ctxt->manager) + virLogManagerDomainGetLogFilePosition(ctxt->manager, + ctxt->path, + 0, + &ctxt->inode, + &ctxt->pos); + else + ctxt->pos = lseek(ctxt->writefd, 0, SEEK_END); +} + + +virLogManager * +qemuLogContextGetManager(qemuLogContext *ctxt) +{ + return ctxt->manager; +} diff --git a/src/hypervisor/domain_logcontext.h b/src/hypervisor/domain_logcontext.h new file mode 100644 index 0000000000..572ac1026e --- /dev/null +++ b/src/hypervisor/domain_logcontext.h @@ -0,0 +1,41 @@ +/* + * domain_logcontext.h: QEMU log context + * + * 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/>. + */ + +#pragma once + +#include <glib-object.h> +#include "qemu_conf.h" +#include "logging/log_manager.h" + +#define QEMU_TYPE_LOG_CONTEXT qemu_log_context_get_type() +G_DECLARE_FINAL_TYPE(qemuLogContext, qemu_log_context, QEMU, LOG_CONTEXT, GObject); + +qemuLogContext *qemuLogContextNew(virQEMUDriver *driver, + virDomainObj *vm, + const char *basename); +int qemuLogContextWrite(qemuLogContext *ctxt, + const char *fmt, ...) G_GNUC_PRINTF(2, 3); +ssize_t qemuLogContextRead(qemuLogContext *ctxt, + char **msg); +int qemuLogContextReadFiltered(qemuLogContext *ctxt, + char **msg, + size_t max); +int qemuLogContextGetWriteFD(qemuLogContext *ctxt); +void qemuLogContextMarkPosition(qemuLogContext *ctxt); + +virLogManager *qemuLogContextGetManager(qemuLogContext *ctxt); -- 2.47.0

Rename all references to qemu within domain_logcontext files. Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/hypervisor/domain_logcontext.c | 60 +++++++++++++++--------------- src/hypervisor/domain_logcontext.h | 32 ++++++++-------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/hypervisor/domain_logcontext.c b/src/hypervisor/domain_logcontext.c index 7932cf7712..3776d68ab9 100644 --- a/src/hypervisor/domain_logcontext.c +++ b/src/hypervisor/domain_logcontext.c @@ -1,5 +1,5 @@ /* - * domain_logcontext.c: QEMU log context + * domain_logcontext.c: Domain log context * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,7 +18,7 @@ #include <config.h> -#include "qemu_logcontext.h" +#include "domain_logcontext.h" #include "viralloc.h" #include "virlog.h" #include "virstring.h" @@ -26,12 +26,12 @@ #include <fcntl.h> -#define VIR_FROM_THIS VIR_FROM_QEMU +#define VIR_FROM_THIS VIR_FROM_DOMAIN -VIR_LOG_INIT("qemu.qemu_logcontext"); +VIR_LOG_INIT("domain.domain_logcontext"); -struct _qemuLogContext { +struct _domainLogContext { GObject parent; int writefd; @@ -42,48 +42,48 @@ struct _qemuLogContext { virLogManager *manager; }; -G_DEFINE_TYPE(qemuLogContext, qemu_log_context, G_TYPE_OBJECT); +G_DEFINE_TYPE(domainLogContext, domain_log_context, G_TYPE_OBJECT); static void -qemuLogContextFinalize(GObject *obj); +domainLogContextFinalize(GObject *obj); static void -qemu_log_context_init(qemuLogContext *logctxt G_GNUC_UNUSED) +domain_log_context_init(domainLogContext *logctxt G_GNUC_UNUSED) { } static void -qemu_log_context_class_init(qemuLogContextClass *klass) +domain_log_context_class_init(domainLogContextClass *klass) { GObjectClass *obj = G_OBJECT_CLASS(klass); - obj->finalize = qemuLogContextFinalize; + obj->finalize = domainLogContextFinalize; } static void -qemuLogContextFinalize(GObject *object) +domainLogContextFinalize(GObject *object) { - qemuLogContext *ctxt = QEMU_LOG_CONTEXT(object); + domainLogContext *ctxt = DOMAIN_LOG_CONTEXT(object); VIR_DEBUG("ctxt=%p", ctxt); virLogManagerFree(ctxt->manager); VIR_FREE(ctxt->path); VIR_FORCE_CLOSE(ctxt->writefd); VIR_FORCE_CLOSE(ctxt->readfd); - G_OBJECT_CLASS(qemu_log_context_parent_class)->finalize(object); + G_OBJECT_CLASS(domain_log_context_parent_class)->finalize(object); } -qemuLogContext * -qemuLogContextNew(virQEMUDriver *driver, - virDomainObj *vm, - const char *basename) +domainLogContext * +domainLogContextNew(virQEMUDriver *driver, + virDomainObj *vm, + const char *basename) { g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); - qemuLogContext *ctxt = QEMU_LOG_CONTEXT(g_object_new(QEMU_TYPE_LOG_CONTEXT, NULL)); + domainLogContext *ctxt = DOMAIN_LOG_CONTEXT(g_object_new(DOMAIN_TYPE_LOG_CONTEXT, NULL)); VIR_DEBUG("Context new %p stdioLogD=%d", ctxt, cfg->stdioLogD); ctxt->writefd = -1; @@ -155,8 +155,8 @@ qemuLogContextNew(virQEMUDriver *driver, int -qemuLogContextWrite(qemuLogContext *ctxt, - const char *fmt, ...) +domainLogContextWrite(domainLogContext *ctxt, + const char *fmt, ...) { va_list argptr; g_autofree char *message = NULL; @@ -186,8 +186,8 @@ qemuLogContextWrite(qemuLogContext *ctxt, ssize_t -qemuLogContextRead(qemuLogContext *ctxt, - char **msg) +domainLogContextRead(domainLogContext *ctxt, + char **msg) { char *buf; size_t buflen; @@ -238,7 +238,7 @@ qemuLogContextRead(qemuLogContext *ctxt, /** - * qemuLogContextFilter: Read and filter log for relevant messages + * domainLogContextFilter: Read and filter log for relevant messages * @ctxt: the domain log context * @msg: pointer to buffer to store the read messages in * @max: maximum length of the message returned in @msg after filtering @@ -249,9 +249,9 @@ qemuLogContextRead(qemuLogContext *ctxt, * after a new line if possible. */ int -qemuLogContextReadFiltered(qemuLogContext *ctxt, - char **msg, - size_t max) +domainLogContextReadFiltered(domainLogContext *ctxt, + char **msg, + size_t max) { char *buf; char *eol; @@ -259,7 +259,7 @@ qemuLogContextReadFiltered(qemuLogContext *ctxt, size_t skip; ssize_t got; - if ((got = qemuLogContextRead(ctxt, &buf)) < 0) + if ((got = domainLogContextRead(ctxt, &buf)) < 0) return -1; /* Filter out debug messages from intermediate libvirt process */ @@ -302,14 +302,14 @@ qemuLogContextReadFiltered(qemuLogContext *ctxt, int -qemuLogContextGetWriteFD(qemuLogContext *ctxt) +domainLogContextGetWriteFD(domainLogContext *ctxt) { return ctxt->writefd; } void -qemuLogContextMarkPosition(qemuLogContext *ctxt) +domainLogContextMarkPosition(domainLogContext *ctxt) { if (ctxt->manager) virLogManagerDomainGetLogFilePosition(ctxt->manager, @@ -323,7 +323,7 @@ qemuLogContextMarkPosition(qemuLogContext *ctxt) virLogManager * -qemuLogContextGetManager(qemuLogContext *ctxt) +domainLogContextGetManager(domainLogContext *ctxt) { return ctxt->manager; } diff --git a/src/hypervisor/domain_logcontext.h b/src/hypervisor/domain_logcontext.h index 572ac1026e..8bb7c3d217 100644 --- a/src/hypervisor/domain_logcontext.h +++ b/src/hypervisor/domain_logcontext.h @@ -1,5 +1,5 @@ /* - * domain_logcontext.h: QEMU log context + * domain_logcontext.h: Domain log context * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,20 +22,20 @@ #include "qemu_conf.h" #include "logging/log_manager.h" -#define QEMU_TYPE_LOG_CONTEXT qemu_log_context_get_type() -G_DECLARE_FINAL_TYPE(qemuLogContext, qemu_log_context, QEMU, LOG_CONTEXT, GObject); +#define DOMAIN_TYPE_LOG_CONTEXT domain_log_context_get_type() +G_DECLARE_FINAL_TYPE(domainLogContext, domain_log_context, DOMAIN, LOG_CONTEXT, GObject); -qemuLogContext *qemuLogContextNew(virQEMUDriver *driver, - virDomainObj *vm, - const char *basename); -int qemuLogContextWrite(qemuLogContext *ctxt, - const char *fmt, ...) G_GNUC_PRINTF(2, 3); -ssize_t qemuLogContextRead(qemuLogContext *ctxt, - char **msg); -int qemuLogContextReadFiltered(qemuLogContext *ctxt, - char **msg, - size_t max); -int qemuLogContextGetWriteFD(qemuLogContext *ctxt); -void qemuLogContextMarkPosition(qemuLogContext *ctxt); +domainLogContext *domainLogContextNew(virQEMUDriver *driver, + virDomainObj *vm, + const char *basename); +int domainLogContextWrite(domainLogContext *ctxt, + const char *fmt, ...) G_GNUC_PRINTF(2, 3); +ssize_t domainLogContextRead(domainLogContext *ctxt, + char **msg); +int domainLogContextReadFiltered(domainLogContext *ctxt, + char **msg, + size_t max); +int domainLogContextGetWriteFD(domainLogContext *ctxt); +void domainLogContextMarkPosition(domainLogContext *ctxt); -virLogManager *qemuLogContextGetManager(qemuLogContext *ctxt); +virLogManager *domainLogContextGetManager(domainLogContext *ctxt); -- 2.47.0

Drop Qemu specific arguments from domainLogContextNew and replace them with hypervisor agnostic ones. Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/hypervisor/domain_logcontext.c | 20 ++++++++++++-------- src/hypervisor/domain_logcontext.h | 8 ++++++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/hypervisor/domain_logcontext.c b/src/hypervisor/domain_logcontext.c index 3776d68ab9..41d1bbdf64 100644 --- a/src/hypervisor/domain_logcontext.c +++ b/src/hypervisor/domain_logcontext.c @@ -23,6 +23,8 @@ #include "virlog.h" #include "virstring.h" #include "virutil.h" +#include "virfile.h" +#include "virerror.h" #include <fcntl.h> @@ -78,26 +80,28 @@ domainLogContextFinalize(GObject *object) domainLogContext * -domainLogContextNew(virQEMUDriver *driver, +domainLogContextNew(bool stdioLogD, + char *logDir, + const char *driver_name, virDomainObj *vm, + bool privileged, const char *basename) { - g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); domainLogContext *ctxt = DOMAIN_LOG_CONTEXT(g_object_new(DOMAIN_TYPE_LOG_CONTEXT, NULL)); - VIR_DEBUG("Context new %p stdioLogD=%d", ctxt, cfg->stdioLogD); + VIR_DEBUG("Context new %p stdioLogD=%d", ctxt, stdioLogD); ctxt->writefd = -1; ctxt->readfd = -1; - ctxt->path = g_strdup_printf("%s/%s.log", cfg->logDir, basename); + ctxt->path = g_strdup_printf("%s/%s.log", logDir, basename); - if (cfg->stdioLogD) { - ctxt->manager = virLogManagerNew(driver->privileged); + if (stdioLogD) { + ctxt->manager = virLogManagerNew(privileged); if (!ctxt->manager) goto error; ctxt->writefd = virLogManagerDomainOpenLogFile(ctxt->manager, - "qemu", + driver_name, vm->def->uuid, vm->def->name, ctxt->path, @@ -121,7 +125,7 @@ domainLogContextNew(virQEMUDriver *driver, /* For unprivileged startup we must truncate the file since * we can't rely on logrotate. We don't use O_TRUNC since * it is better for SELinux policy if we truncate afterwards */ - if (!driver->privileged && + if (!privileged && ftruncate(ctxt->writefd, 0) < 0) { virReportSystemError(errno, _("failed to truncate %1$s"), ctxt->path); diff --git a/src/hypervisor/domain_logcontext.h b/src/hypervisor/domain_logcontext.h index 8bb7c3d217..07c93fcf65 100644 --- a/src/hypervisor/domain_logcontext.h +++ b/src/hypervisor/domain_logcontext.h @@ -19,14 +19,18 @@ #pragma once #include <glib-object.h> -#include "qemu_conf.h" #include "logging/log_manager.h" +#include "virconftypes.h" +#include "domain_conf.h" #define DOMAIN_TYPE_LOG_CONTEXT domain_log_context_get_type() G_DECLARE_FINAL_TYPE(domainLogContext, domain_log_context, DOMAIN, LOG_CONTEXT, GObject); -domainLogContext *domainLogContextNew(virQEMUDriver *driver, +domainLogContext *domainLogContextNew(bool stdioLogD, + char *logDir, + const char *driver_name, virDomainObj *vm, + bool privileged, const char *basename); int domainLogContextWrite(domainLogContext *ctxt, const char *fmt, ...) G_GNUC_PRINTF(2, 3); -- 2.47.0

Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/hypervisor/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hypervisor/meson.build b/src/hypervisor/meson.build index 819a9a82a2..c32703af88 100644 --- a/src/hypervisor/meson.build +++ b/src/hypervisor/meson.build @@ -2,6 +2,7 @@ hypervisor_sources = [ 'domain_cgroup.c', 'domain_driver.c', 'domain_interface.c', + 'domain_logcontext.c', 'virclosecallbacks.c', 'virhostdev.c', ] -- 2.47.0

Export required symbols from domain_logcontext.c. Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/libvirt_private.syms | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c931003fad..ad90f46c18 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1665,6 +1665,12 @@ virDomainInterfaceStopDevice; virDomainInterfaceStopDevices; virDomainInterfaceVportRemove; +# hypervisor/domain_logcontext.h +domainLogContextGetWriteFD; +domainLogContextMarkPosition; +domainLogContextNew; +domainLogContextReadFiltered; +domainLogContextWrite; # hypervisor/virclosecallbacks.h virCloseCallbacksDomainAdd; -- 2.47.0

Modify qemu driver to use domainLogcontext instead of qemuLogContext. Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/qemu/qemu_domain.c | 28 ++++++++++++------------- src/qemu/qemu_domain.h | 12 +++++------ src/qemu/qemu_nbdkit.c | 12 +++++++---- src/qemu/qemu_process.c | 45 ++++++++++++++++++++++------------------- 4 files changed, 52 insertions(+), 45 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index f15ba58179..c7d7ac26ce 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -5399,7 +5399,7 @@ static void G_GNUC_PRINTF(5, 6) qemuDomainObjTaintMsg(virQEMUDriver *driver, virDomainObj *obj, virDomainTaintFlags taint, - qemuLogContext *logCtxt, + domainLogContext *logCtxt, const char *fmt, ...) { virErrorPtr orig_err = NULL; @@ -5452,12 +5452,12 @@ qemuDomainObjTaintMsg(virQEMUDriver *driver, goto cleanup; if (logCtxt) { - rc = qemuLogContextWrite(logCtxt, - "%s: Domain id=%d is tainted: %s%s%s%s\n", - timestamp, - obj->def->id, - virDomainTaintTypeToString(taint), - extraprefix, extramsg, extrasuffix); + rc = domainLogContextWrite(logCtxt, + "%s: Domain id=%d is tainted: %s%s%s%s\n", + timestamp, + obj->def->id, + virDomainTaintTypeToString(taint), + extraprefix, extramsg, extrasuffix); } else { rc = qemuDomainLogAppendMessage(driver, obj, "%s: Domain id=%d is tainted: %s%s%s%s\n", @@ -5478,7 +5478,7 @@ qemuDomainObjTaintMsg(virQEMUDriver *driver, void qemuDomainObjTaint(virQEMUDriver *driver, virDomainObj *obj, virDomainTaintFlags taint, - qemuLogContext *logCtxt) + domainLogContext *logCtxt) { qemuDomainObjTaintMsg(driver, obj, taint, logCtxt, NULL); qemuDomainSaveStatus(obj); @@ -5487,7 +5487,7 @@ void qemuDomainObjTaint(virQEMUDriver *driver, static void qemuDomainObjCheckMachineTaint(virQEMUDriver *driver, virDomainObj *obj, - qemuLogContext *logCtxt) + domainLogContext *logCtxt) { qemuDomainObjPrivate *priv = obj->privateData; virQEMUCaps *qemuCaps = priv->qemuCaps; @@ -5505,7 +5505,7 @@ qemuDomainObjCheckMachineTaint(virQEMUDriver *driver, static void qemuDomainObjCheckCPUTaint(virQEMUDriver *driver, virDomainObj *obj, - qemuLogContext *logCtxt, + domainLogContext *logCtxt, bool incomingMigration) { qemuDomainObjPrivate *priv = obj->privateData; @@ -5537,7 +5537,7 @@ qemuDomainObjCheckCPUTaint(virQEMUDriver *driver, void qemuDomainObjCheckTaint(virQEMUDriver *driver, virDomainObj *obj, - qemuLogContext *logCtxt, + domainLogContext *logCtxt, bool incomingMigration) { size_t i; @@ -5593,7 +5593,7 @@ void qemuDomainObjCheckTaint(virQEMUDriver *driver, void qemuDomainObjCheckDiskTaint(virQEMUDriver *driver, virDomainObj *obj, virDomainDiskDef *disk, - qemuLogContext *logCtxt) + domainLogContext *logCtxt) { if (disk->rawio == VIR_TRISTATE_BOOL_YES) qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_HIGH_PRIVILEGES, @@ -5610,7 +5610,7 @@ void qemuDomainObjCheckDiskTaint(virQEMUDriver *driver, void qemuDomainObjCheckHostdevTaint(virQEMUDriver *driver, virDomainObj *obj, virDomainHostdevDef *hostdev, - qemuLogContext *logCtxt) + domainLogContext *logCtxt) { if (!virHostdevIsSCSIDevice(hostdev)) return; @@ -5623,7 +5623,7 @@ void qemuDomainObjCheckHostdevTaint(virQEMUDriver *driver, void qemuDomainObjCheckNetTaint(virQEMUDriver *driver, virDomainObj *obj, virDomainNetDef *net, - qemuLogContext *logCtxt) + domainLogContext *logCtxt) { /* script is only useful for NET_TYPE_ETHERNET (qemu) and * NET_TYPE_BRIDGE (xen), but could be (incorrectly) specified for diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 86e24ad54b..04577f1297 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -26,13 +26,13 @@ #include "virperf.h" #include "domain_addr.h" #include "domain_conf.h" +#include "domain_logcontext.h" #include "qemu_monitor.h" #include "qemu_agent.h" #include "qemu_blockjob.h" #include "qemu_domainjob.h" #include "qemu_conf.h" #include "qemu_capabilities.h" -#include "qemu_logcontext.h" #include "qemu_migration_params.h" #include "qemu_nbdkit.h" #include "qemu_slirp.h" @@ -641,24 +641,24 @@ char *qemuDomainDefFormatLive(virQEMUDriver *driver, void qemuDomainObjTaint(virQEMUDriver *driver, virDomainObj *obj, virDomainTaintFlags taint, - qemuLogContext *logCtxt); + domainLogContext *logCtxt); void qemuDomainObjCheckTaint(virQEMUDriver *driver, virDomainObj *obj, - qemuLogContext *logCtxt, + domainLogContext *logCtxt, bool incomingMigration); void qemuDomainObjCheckDiskTaint(virQEMUDriver *driver, virDomainObj *obj, virDomainDiskDef *disk, - qemuLogContext *logCtxt); + domainLogContext *logCtxt); void qemuDomainObjCheckHostdevTaint(virQEMUDriver *driver, virDomainObj *obj, virDomainHostdevDef *disk, - qemuLogContext *logCtxt); + domainLogContext *logCtxt); void qemuDomainObjCheckNetTaint(virQEMUDriver *driver, virDomainObj *obj, virDomainNetDef *net, - qemuLogContext *logCtxt); + domainLogContext *logCtxt); int qemuDomainLogAppendMessage(virQEMUDriver *driver, virDomainObj *vm, diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c index f099f35e1e..65c98de017 100644 --- a/src/qemu/qemu_nbdkit.c +++ b/src/qemu/qemu_nbdkit.c @@ -1177,6 +1177,7 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc, virQEMUDriver *driver) { g_autoptr(virCommand) cmd = NULL; + g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); int rc; int exitstatus = 0; g_autofree char *errbuf = NULL; @@ -1185,7 +1186,7 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc, g_autofree char *uristring = NULL; g_autofree char *basename = g_strdup_printf("%s-nbdkit-%i", vm->def->name, proc->source->id); int logfd = -1; - g_autoptr(qemuLogContext) logContext = NULL; + g_autoptr(domainLogContext) logContext = NULL; #if WITH_NBDKIT struct nbd_handle *nbd = NULL; #endif @@ -1200,12 +1201,15 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc, if (!(cmd = qemuNbdkitProcessBuildCommand(proc))) return -1; - if (!(logContext = qemuLogContextNew(driver, vm, basename))) { + if (!(logContext = domainLogContextNew(cfg->stdioLogD, cfg->logDir, + QEMU_DRIVER_NAME, + vm, driver->privileged, + basename))) { virLastErrorPrefixMessage("%s", _("can't connect to virtlogd")); return -1; } - logfd = qemuLogContextGetWriteFD(logContext); + logfd = domainLogContextGetWriteFD(logContext); VIR_DEBUG("starting nbdkit process for %s", qemuBlockStorageSourceGetStorageNodename(proc->source)); virCommandSetErrorFD(cmd, &logfd); @@ -1283,7 +1287,7 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc, if ((uri = qemuBlockStorageSourceGetURI(proc->source))) uristring = virURIFormat(uri); - if (qemuLogContextReadFiltered(logContext, &errbuf, 1024) < 0) + if (domainLogContextReadFiltered(logContext, &errbuf, 1024) < 0) VIR_WARN("Unable to read from nbdkit log"); virReportError(VIR_ERR_OPERATION_FAILED, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 5f2e278156..c7240f3ae4 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1840,7 +1840,7 @@ qemuProcessMonitorReportLogError(qemuMonitor *mon, static void qemuProcessMonitorLogFree(void *opaque) { - qemuLogContext *logCtxt = opaque; + domainLogContext *logCtxt = opaque; g_clear_object(&logCtxt); } @@ -1866,7 +1866,7 @@ static int qemuConnectMonitor(virQEMUDriver *driver, virDomainObj *vm, int asyncJob, - qemuLogContext *logCtxt, + domainLogContext *logCtxt, bool reconnect) { qemuDomainObjPrivate *priv = vm->privateData; @@ -1918,13 +1918,13 @@ qemuConnectMonitor(virQEMUDriver *driver, static int -qemuProcessReportLogError(qemuLogContext *logCtxt, +qemuProcessReportLogError(domainLogContext *logCtxt, const char *msgprefix) { g_autofree char *logmsg = NULL; /* assume that 1024 chars of qemu log is the right balance */ - if (qemuLogContextReadFiltered(logCtxt, &logmsg, 1024) < 0) + if (domainLogContextReadFiltered(logCtxt, &logmsg, 1024) < 0) return -1; virResetLastError(); @@ -1943,7 +1943,7 @@ qemuProcessMonitorReportLogError(qemuMonitor *mon G_GNUC_UNUSED, const char *msg, void *opaque) { - qemuLogContext *logCtxt = opaque; + domainLogContext *logCtxt = opaque; qemuProcessReportLogError(logCtxt, msg); } @@ -2244,7 +2244,7 @@ static int qemuProcessWaitForMonitor(virQEMUDriver *driver, virDomainObj *vm, int asyncJob, - qemuLogContext *logCtxt) + domainLogContext *logCtxt) { int ret = -1; g_autoptr(GHashTable) info = NULL; @@ -4740,7 +4740,7 @@ static void qemuLogOperation(virDomainObj *vm, const char *msg, virCommand *cmd, - qemuLogContext *logCtxt) + domainLogContext *logCtxt) { g_autofree char *timestamp = NULL; qemuDomainObjPrivate *priv = vm->privateData; @@ -4754,20 +4754,20 @@ qemuLogOperation(virDomainObj *vm, if ((timestamp = virTimeStringNow()) == NULL) return; - if (qemuLogContextWrite(logCtxt, - "%s: %s %s, qemu version: %d.%d.%d%s, kernel: %s, hostname: %s\n", - timestamp, msg, VIR_LOG_VERSION_STRING, - (qemuVersion / 1000000) % 1000, - (qemuVersion / 1000) % 1000, - qemuVersion % 1000, - NULLSTR_EMPTY(package), - uts.release, - NULLSTR_EMPTY(hostname)) < 0) + if (domainLogContextWrite(logCtxt, + "%s: %s %s, qemu version: %d.%d.%d%s, kernel: %s, hostname: %s\n", + timestamp, msg, VIR_LOG_VERSION_STRING, + (qemuVersion / 1000000) % 1000, + (qemuVersion / 1000) % 1000, + qemuVersion % 1000, + NULLSTR_EMPTY(package), + uts.release, + NULLSTR_EMPTY(hostname)) < 0) return; if (cmd) { g_autofree char *args = virCommandToString(cmd, true); - qemuLogContextWrite(logCtxt, "%s\n", args); + domainLogContextWrite(logCtxt, "%s\n", args); } } @@ -7776,7 +7776,7 @@ qemuProcessLaunch(virConnectPtr conn, int ret = -1; int rv; int logfile = -1; - g_autoptr(qemuLogContext) logCtxt = NULL; + g_autoptr(domainLogContext) logCtxt = NULL; qemuDomainObjPrivate *priv = vm->privateData; g_autoptr(virCommand) cmd = NULL; struct qemuProcessHookData hookData; @@ -7826,11 +7826,14 @@ qemuProcessLaunch(virConnectPtr conn, hookData.cfg = cfg; VIR_DEBUG("Creating domain log file"); - if (!(logCtxt = qemuLogContextNew(driver, vm, vm->def->name))) { + if (!(logCtxt = domainLogContextNew(cfg->stdioLogD, cfg->logDir, + QEMU_DRIVER_NAME, + vm, driver->privileged, + vm->def->name))) { virLastErrorPrefixMessage("%s", _("can't connect to virtlogd")); goto cleanup; } - logfile = qemuLogContextGetWriteFD(logCtxt); + logfile = domainLogContextGetWriteFD(logCtxt); if (qemuProcessGenID(vm, flags) < 0) goto cleanup; @@ -7866,7 +7869,7 @@ qemuProcessLaunch(virConnectPtr conn, qemuDomainObjCheckTaint(driver, vm, logCtxt, incoming != NULL); - qemuLogContextMarkPosition(logCtxt); + domainLogContextMarkPosition(logCtxt); if (qemuProcessEnableDomainNamespaces(driver, vm) < 0) goto cleanup; -- 2.47.0

Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- po/POTFILES | 1 - src/qemu/meson.build | 1 - src/qemu/qemu_logcontext.c | 329 ------------------------------------- src/qemu/qemu_logcontext.h | 41 ----- 4 files changed, 372 deletions(-) delete mode 100644 src/qemu/qemu_logcontext.c delete mode 100644 src/qemu/qemu_logcontext.h diff --git a/po/POTFILES b/po/POTFILES index 1d3c3c0a81..43b4d005e3 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -181,7 +181,6 @@ src/qemu/qemu_hostdev.c src/qemu/qemu_hotplug.c src/qemu/qemu_interface.c src/qemu/qemu_interop_config.c -src/qemu/qemu_logcontext.c src/qemu/qemu_migration.c src/qemu/qemu_migration_cookie.c src/qemu/qemu_migration_params.c diff --git a/src/qemu/meson.build b/src/qemu/meson.build index 2a85e2e604..43a8ad7c3b 100644 --- a/src/qemu/meson.build +++ b/src/qemu/meson.build @@ -22,7 +22,6 @@ qemu_driver_sources = [ 'qemu_hotplug.c', 'qemu_interface.c', 'qemu_interop_config.c', - 'qemu_logcontext.c', 'qemu_migration.c', 'qemu_migration_cookie.c', 'qemu_migration_params.c', diff --git a/src/qemu/qemu_logcontext.c b/src/qemu/qemu_logcontext.c deleted file mode 100644 index 6e20f58bfa..0000000000 --- a/src/qemu/qemu_logcontext.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * qemu_logcontext.c: QEMU log context - * - * 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/>. - */ - -#include <config.h> - -#include "qemu_logcontext.h" -#include "viralloc.h" -#include "virlog.h" -#include "virstring.h" -#include "virutil.h" - -#include <fcntl.h> - -#define VIR_FROM_THIS VIR_FROM_QEMU - -VIR_LOG_INIT("qemu.qemu_logcontext"); - - -struct _qemuLogContext { - GObject parent; - - int writefd; - int readfd; /* Only used if manager == NULL */ - off_t pos; - ino_t inode; /* Only used if manager != NULL */ - char *path; - virLogManager *manager; -}; - -G_DEFINE_TYPE(qemuLogContext, qemu_log_context, G_TYPE_OBJECT); - -static void -qemuLogContextFinalize(GObject *obj); - - -static void -qemu_log_context_init(qemuLogContext *logctxt G_GNUC_UNUSED) -{ -} - - -static void -qemu_log_context_class_init(qemuLogContextClass *klass) -{ - GObjectClass *obj = G_OBJECT_CLASS(klass); - - obj->finalize = qemuLogContextFinalize; -} - - -static void -qemuLogContextFinalize(GObject *object) -{ - qemuLogContext *ctxt = QEMU_LOG_CONTEXT(object); - VIR_DEBUG("ctxt=%p", ctxt); - - virLogManagerFree(ctxt->manager); - VIR_FREE(ctxt->path); - VIR_FORCE_CLOSE(ctxt->writefd); - VIR_FORCE_CLOSE(ctxt->readfd); - G_OBJECT_CLASS(qemu_log_context_parent_class)->finalize(object); -} - - -qemuLogContext * -qemuLogContextNew(virQEMUDriver *driver, - virDomainObj *vm, - const char *basename) -{ - g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); - qemuLogContext *ctxt = QEMU_LOG_CONTEXT(g_object_new(QEMU_TYPE_LOG_CONTEXT, NULL)); - - VIR_DEBUG("Context new %p stdioLogD=%d", ctxt, cfg->stdioLogD); - ctxt->writefd = -1; - ctxt->readfd = -1; - - ctxt->path = g_strdup_printf("%s/%s.log", cfg->logDir, basename); - - if (cfg->stdioLogD) { - ctxt->manager = virLogManagerNew(driver->privileged); - if (!ctxt->manager) - goto error; - - ctxt->writefd = virLogManagerDomainOpenLogFile(ctxt->manager, - "qemu", - vm->def->uuid, - vm->def->name, - ctxt->path, - 0, - &ctxt->inode, - &ctxt->pos); - if (ctxt->writefd < 0) - goto error; - } else { - if ((ctxt->writefd = open(ctxt->path, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)) < 0) { - virReportSystemError(errno, _("failed to create logfile %1$s"), - ctxt->path); - goto error; - } - if (virSetCloseExec(ctxt->writefd) < 0) { - virReportSystemError(errno, _("failed to set close-on-exec flag on %1$s"), - ctxt->path); - goto error; - } - - /* For unprivileged startup we must truncate the file since - * we can't rely on logrotate. We don't use O_TRUNC since - * it is better for SELinux policy if we truncate afterwards */ - if (!driver->privileged && - ftruncate(ctxt->writefd, 0) < 0) { - virReportSystemError(errno, _("failed to truncate %1$s"), - ctxt->path); - goto error; - } - - if ((ctxt->readfd = open(ctxt->path, O_RDONLY)) < 0) { - virReportSystemError(errno, _("failed to open logfile %1$s"), - ctxt->path); - goto error; - } - if (virSetCloseExec(ctxt->readfd) < 0) { - virReportSystemError(errno, _("failed to set close-on-exec flag on %1$s"), - ctxt->path); - goto error; - } - - if ((ctxt->pos = lseek(ctxt->writefd, 0, SEEK_END)) < 0) { - virReportSystemError(errno, _("failed to seek in log file %1$s"), - ctxt->path); - goto error; - } - } - - return ctxt; - - error: - g_clear_object(&ctxt); - return NULL; -} - - -int -qemuLogContextWrite(qemuLogContext *ctxt, - const char *fmt, ...) -{ - va_list argptr; - g_autofree char *message = NULL; - int ret = -1; - - va_start(argptr, fmt); - - message = g_strdup_vprintf(fmt, argptr); - if (!ctxt->manager && - lseek(ctxt->writefd, 0, SEEK_END) < 0) { - virReportSystemError(errno, "%s", - _("Unable to seek to end of domain logfile")); - goto cleanup; - } - if (safewrite(ctxt->writefd, message, strlen(message)) < 0) { - virReportSystemError(errno, "%s", - _("Unable to write to domain logfile")); - goto cleanup; - } - - ret = 0; - - cleanup: - va_end(argptr); - return ret; -} - - -ssize_t -qemuLogContextRead(qemuLogContext *ctxt, - char **msg) -{ - char *buf; - size_t buflen; - - VIR_DEBUG("Context read %p manager=%p inode=%llu pos=%llu", - ctxt, ctxt->manager, - (unsigned long long)ctxt->inode, - (unsigned long long)ctxt->pos); - - if (ctxt->manager) { - buf = virLogManagerDomainReadLogFile(ctxt->manager, - ctxt->path, - ctxt->inode, - ctxt->pos, - 1024 * 128, - 0); - if (!buf) - return -1; - buflen = strlen(buf); - } else { - ssize_t got; - - buflen = 1024 * 128; - - /* Best effort jump to start of messages */ - ignore_value(lseek(ctxt->readfd, ctxt->pos, SEEK_SET)); - - buf = g_new0(char, buflen); - - got = saferead(ctxt->readfd, buf, buflen - 1); - if (got < 0) { - VIR_FREE(buf); - virReportSystemError(errno, "%s", - _("Unable to read from log file")); - return -1; - } - - buf[got] = '\0'; - - buf = g_renew(char, buf, got + 1); - buflen = got; - } - - *msg = buf; - - return buflen; -} - - -/** - * qemuLogContextFilter: Read and filter log for relevant messages - * @ctxt: the domain log context - * @msg: pointer to buffer to store the read messages in - * @max: maximum length of the message returned in @msg after filtering - * - * Reads log output from @ctxt and filters it. Skips messages not produced by - * the target executable or irrelevant messages. If @max is not zero, @buf will - * contain at most @max characters from the end of the log and @buf will start - * after a new line if possible. - */ -int -qemuLogContextReadFiltered(qemuLogContext *ctxt, - char **msg, - size_t max) -{ - char *buf; - char *eol; - char *filter_next; - size_t skip; - ssize_t got; - - if ((got = qemuLogContextRead(ctxt, &buf)) < 0) - return -1; - - /* Filter out debug messages from intermediate libvirt process */ - filter_next = buf; - while ((eol = strchr(filter_next, '\n'))) { - *eol = '\0'; - if (virLogProbablyLogMessage(filter_next) || - strstr(filter_next, "char device redirected to")) { - skip = (eol + 1) - filter_next; - memmove(filter_next, eol + 1, buf + got - eol); - got -= skip; - } else { - filter_next = eol + 1; - *eol = '\n'; - } - } - - if (got > 0 && - buf[got - 1] == '\n') { - buf[got - 1] = '\0'; - got--; - } - - if (max > 0 && got > max) { - skip = got - max; - - if (buf[skip - 1] != '\n' && - (eol = strchr(buf + skip, '\n')) && - !virStringIsEmpty(eol + 1)) - skip = eol + 1 - buf; - - memmove(buf, buf + skip, got - skip + 1); - got -= skip; - } - - buf = g_renew(char, buf, got + 1); - *msg = buf; - return 0; -} - - -int -qemuLogContextGetWriteFD(qemuLogContext *ctxt) -{ - return ctxt->writefd; -} - - -void -qemuLogContextMarkPosition(qemuLogContext *ctxt) -{ - if (ctxt->manager) - virLogManagerDomainGetLogFilePosition(ctxt->manager, - ctxt->path, - 0, - &ctxt->inode, - &ctxt->pos); - else - ctxt->pos = lseek(ctxt->writefd, 0, SEEK_END); -} - - -virLogManager * -qemuLogContextGetManager(qemuLogContext *ctxt) -{ - return ctxt->manager; -} diff --git a/src/qemu/qemu_logcontext.h b/src/qemu/qemu_logcontext.h deleted file mode 100644 index 738e908bc3..0000000000 --- a/src/qemu/qemu_logcontext.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * qemu_logcontext.h: QEMU log context - * - * 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/>. - */ - -#pragma once - -#include <glib-object.h> -#include "qemu_conf.h" -#include "logging/log_manager.h" - -#define QEMU_TYPE_LOG_CONTEXT qemu_log_context_get_type() -G_DECLARE_FINAL_TYPE(qemuLogContext, qemu_log_context, QEMU, LOG_CONTEXT, GObject); - -qemuLogContext *qemuLogContextNew(virQEMUDriver *driver, - virDomainObj *vm, - const char *basename); -int qemuLogContextWrite(qemuLogContext *ctxt, - const char *fmt, ...) G_GNUC_PRINTF(2, 3); -ssize_t qemuLogContextRead(qemuLogContext *ctxt, - char **msg); -int qemuLogContextReadFiltered(qemuLogContext *ctxt, - char **msg, - size_t max); -int qemuLogContextGetWriteFD(qemuLogContext *ctxt); -void qemuLogContextMarkPosition(qemuLogContext *ctxt); - -virLogManager *qemuLogContextGetManager(qemuLogContext *ctxt); -- 2.47.0

Use domainLogContext to enable logging for ch domain process during create and restore steps. Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/ch/ch_conf.h | 2 ++ src/ch/ch_monitor.c | 5 ++++- src/ch/ch_monitor.h | 3 ++- src/ch/ch_process.c | 34 ++++++++++++++++++++++++++++++---- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/ch/ch_conf.h b/src/ch/ch_conf.h index bac82a0170..b08573476e 100644 --- a/src/ch/ch_conf.h +++ b/src/ch/ch_conf.h @@ -45,6 +45,8 @@ struct _virCHDriverConfig { uid_t user; gid_t group; + + bool stdioLogD; }; G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCHDriverConfig, virObjectUnref); diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index 690aea37c8..c9b08b0f75 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -536,7 +536,7 @@ chMonitorCreateSocket(const char *socket_path) } virCHMonitor * -virCHMonitorNew(virDomainObj *vm, virCHDriverConfig *cfg) +virCHMonitorNew(virDomainObj *vm, virCHDriverConfig *cfg, int logfile) { g_autoptr(virCHMonitor) mon = NULL; g_autoptr(virCommand) cmd = NULL; @@ -572,6 +572,9 @@ virCHMonitorNew(virDomainObj *vm, virCHDriverConfig *cfg) } cmd = virCommandNew(vm->def->emulator); + virCommandSetOutputFD(cmd, &logfile); + virCommandSetErrorFD(cmd, &logfile); + virCommandNonblockingFDs(cmd); virCommandSetUmask(cmd, 0x002); socket_fd = chMonitorCreateSocket(mon->socketpath); if (socket_fd < 0) { diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h index 9ec58e5b20..5c02447116 100644 --- a/src/ch/ch_monitor.h +++ b/src/ch/ch_monitor.h @@ -103,7 +103,8 @@ struct _virCHMonitor { virCHMonitorThreadInfo *threads; }; -virCHMonitor *virCHMonitorNew(virDomainObj *vm, virCHDriverConfig *cfg); +virCHMonitor *virCHMonitorNew(virDomainObj *vm, virCHDriverConfig *cfg, + int logfile); void virCHMonitorClose(virCHMonitor *mon); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCHMonitor, virCHMonitorClose); diff --git a/src/ch/ch_process.c b/src/ch/ch_process.c index 61e263b62b..af44aa81a2 100644 --- a/src/ch/ch_process.c +++ b/src/ch/ch_process.c @@ -29,6 +29,7 @@ #include "ch_process.h" #include "domain_cgroup.h" #include "domain_interface.h" +#include "domain_logcontext.h" #include "viralloc.h" #include "virerror.h" #include "virfile.h" @@ -49,12 +50,13 @@ VIR_LOG_INIT("ch.ch_process"); static virCHMonitor * virCHProcessConnectMonitor(virCHDriver *driver, - virDomainObj *vm) + virDomainObj *vm, + int logfile) { virCHMonitor *monitor = NULL; virCHDriverConfig *cfg = virCHDriverGetConfig(driver); - monitor = virCHMonitorNew(vm, cfg); + monitor = virCHMonitorNew(vm, cfg, logfile); virObjectUnref(cfg); return monitor; @@ -890,6 +892,8 @@ virCHProcessStart(virCHDriver *driver, g_autoptr(virCHDriverConfig) cfg = virCHDriverGetConfig(priv->driver); g_autofree int *nicindexes = NULL; size_t nnicindexes = 0; + g_autoptr(domainLogContext) logCtxt = NULL; + int logfile = -1; if (virDomainObjIsActive(vm)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", @@ -901,6 +905,16 @@ virCHProcessStart(virCHDriver *driver, return -1; } + VIR_DEBUG("Creating domain log file for %s domain", vm->def->name); + if (!(logCtxt = domainLogContextNew(cfg->stdioLogD, cfg->logDir, + CH_DRIVER_NAME, + vm, driver->privileged, + vm->def->name))) { + virLastErrorPrefixMessage("%s", _("can't connect to virtlogd")); + return -1; + } + logfile = domainLogContextGetWriteFD(logCtxt); + if (virCHProcessPrepareDomain(vm) < 0) { return -1; } @@ -910,7 +924,7 @@ virCHProcessStart(virCHDriver *driver, if (!priv->monitor) { /* And we can get the first monitor connection now too */ - if (!(priv->monitor = virCHProcessConnectMonitor(driver, vm))) { + if (!(priv->monitor = virCHProcessConnectMonitor(driver, vm, logfile))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to create connection to CH socket")); goto cleanup; @@ -1047,10 +1061,22 @@ virCHProcessStartRestore(virCHDriver *driver, virDomainObj *vm, const char *from size_t ntapfds = 0; size_t nnicindexes = 0; int ret = -1; + g_autoptr(domainLogContext) logCtxt = NULL; + int logfile = -1; + + VIR_DEBUG("Creating domain log file for %s domain", vm->def->name); + if (!(logCtxt = domainLogContextNew(cfg->stdioLogD, cfg->logDir, + CH_DRIVER_NAME, + vm, driver->privileged, + vm->def->name))) { + virLastErrorPrefixMessage("%s", _("can't connect to virtlogd")); + return -1; + } + logfile = domainLogContextGetWriteFD(logCtxt); if (!priv->monitor) { /* Get the first monitor connection if not already */ - if (!(priv->monitor = virCHProcessConnectMonitor(driver, vm))) { + if (!(priv->monitor = virCHProcessConnectMonitor(driver, vm, logfile))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to create connection to CH socket")); goto cleanup; -- 2.47.0

Move the definitions of curl_data and curl_callback to be used within virCHMonitorPutNoContent. Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/ch/ch_monitor.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index c9b08b0f75..88df9d4a03 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -671,6 +671,28 @@ virCHMonitorCurlPerform(CURL *handle) return responseCode; } +struct curl_data { + char *content; + size_t size; +}; + +static size_t +curl_callback(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t content_size = size * nmemb; + struct curl_data *data = userp; + + if (content_size == 0) + return content_size; + + data->content = g_realloc(data->content, data->size + content_size); + + memcpy(&(data->content[data->size]), contents, content_size); + data->size += content_size; + + return content_size; +} + int virCHMonitorPutNoContent(virCHMonitor *mon, const char *endpoint) { @@ -698,28 +720,6 @@ virCHMonitorPutNoContent(virCHMonitor *mon, const char *endpoint) return ret; } -struct curl_data { - char *content; - size_t size; -}; - -static size_t -curl_callback(void *contents, size_t size, size_t nmemb, void *userp) -{ - size_t content_size = size * nmemb; - struct curl_data *data = userp; - - if (content_size == 0) - return content_size; - - data->content = g_realloc(data->content, data->size + content_size); - - memcpy(&(data->content[data->size]), contents, content_size); - data->size += content_size; - - return content_size; -} - static int virCHMonitorGet(virCHMonitor *mon, const char *endpoint, virJSONValue **response) { -- 2.47.0

Log curl responses from cloud-hypervisor process during Boot request, using domain's logContext. Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/ch/ch_monitor.c | 35 ++++++++++++++++++++++++++--------- src/ch/ch_monitor.h | 3 ++- src/ch/ch_process.c | 2 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index 88df9d4a03..d3f969e01a 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -56,7 +56,8 @@ static int virCHMonitorOnceInit(void) VIR_ONCE_GLOBAL_INIT(virCHMonitor); int virCHMonitorShutdownVMM(virCHMonitor *mon); -int virCHMonitorPutNoContent(virCHMonitor *mon, const char *endpoint); +int virCHMonitorPutNoContent(virCHMonitor *mon, const char *endpoint, + domainLogContext *logCtxt); static int virCHMonitorBuildCPUJson(virJSONValue *content, virDomainDef *vmdef) @@ -694,12 +695,15 @@ curl_callback(void *contents, size_t size, size_t nmemb, void *userp) } int -virCHMonitorPutNoContent(virCHMonitor *mon, const char *endpoint) +virCHMonitorPutNoContent(virCHMonitor *mon, const char *endpoint, + domainLogContext *logCtxt) { VIR_LOCK_GUARD lock = virObjectLockGuard(mon); g_autofree char *url = NULL; int responseCode = 0; int ret = -1; + struct curl_data data = {0}; + struct curl_slist *headers = NULL; url = g_strdup_printf("%s/%s", URL_ROOT, endpoint); @@ -712,8 +716,21 @@ virCHMonitorPutNoContent(virCHMonitor *mon, const char *endpoint) curl_easy_setopt(mon->handle, CURLOPT_HTTPHEADER, NULL); curl_easy_setopt(mon->handle, CURLOPT_INFILESIZE, 0L); + headers = curl_slist_append(headers, "Accept: application/json"); + curl_easy_setopt(mon->handle, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(mon->handle, CURLOPT_WRITEFUNCTION, curl_callback); + curl_easy_setopt(mon->handle, CURLOPT_WRITEDATA, (void *)&data); + responseCode = virCHMonitorCurlPerform(mon->handle); + if (logCtxt && data.size) { + /* Do this to append a NULL char at the end of data */ + data.content = g_realloc(data.content, data.size + 1); + data.content[data.size] = 0; + domainLogContextWrite(logCtxt, "HTTP response code from CH: %d\n", responseCode); + domainLogContextWrite(logCtxt, "Response = %s\n", data.content); + } + if (responseCode == 200 || responseCode == 204) ret = 0; @@ -863,7 +880,7 @@ virCHMonitorGetThreadInfo(virCHMonitor *mon, int virCHMonitorShutdownVMM(virCHMonitor *mon) { - return virCHMonitorPutNoContent(mon, URL_VMM_SHUTDOWN); + return virCHMonitorPutNoContent(mon, URL_VMM_SHUTDOWN, NULL); } int @@ -903,33 +920,33 @@ virCHMonitorCreateVM(virCHDriver *driver, virCHMonitor *mon) } int -virCHMonitorBootVM(virCHMonitor *mon) +virCHMonitorBootVM(virCHMonitor *mon, domainLogContext *logCtxt) { - return virCHMonitorPutNoContent(mon, URL_VM_BOOT); + return virCHMonitorPutNoContent(mon, URL_VM_BOOT, logCtxt); } int virCHMonitorShutdownVM(virCHMonitor *mon) { - return virCHMonitorPutNoContent(mon, URL_VM_SHUTDOWN); + return virCHMonitorPutNoContent(mon, URL_VM_SHUTDOWN, NULL); } int virCHMonitorRebootVM(virCHMonitor *mon) { - return virCHMonitorPutNoContent(mon, URL_VM_REBOOT); + return virCHMonitorPutNoContent(mon, URL_VM_REBOOT, NULL); } int virCHMonitorSuspendVM(virCHMonitor *mon) { - return virCHMonitorPutNoContent(mon, URL_VM_Suspend); + return virCHMonitorPutNoContent(mon, URL_VM_Suspend, NULL); } int virCHMonitorResumeVM(virCHMonitor *mon) { - return virCHMonitorPutNoContent(mon, URL_VM_RESUME); + return virCHMonitorPutNoContent(mon, URL_VM_RESUME, NULL); } int diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h index 5c02447116..ca23301723 100644 --- a/src/ch/ch_monitor.h +++ b/src/ch/ch_monitor.h @@ -25,6 +25,7 @@ #include "virobject.h" #include "virjson.h" #include "domain_conf.h" +#include "domain_logcontext.h" #include "ch_conf.h" #define URL_ROOT "http://localhost/api/v1" @@ -110,7 +111,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCHMonitor, virCHMonitorClose); int virCHMonitorCreateVM(virCHDriver *driver, virCHMonitor *mon); -int virCHMonitorBootVM(virCHMonitor *mon); +int virCHMonitorBootVM(virCHMonitor *mon, domainLogContext *logCtxt); int virCHMonitorShutdownVM(virCHMonitor *mon); int virCHMonitorRebootVM(virCHMonitor *mon); int virCHMonitorSuspendVM(virCHMonitor *mon); diff --git a/src/ch/ch_process.c b/src/ch/ch_process.c index af44aa81a2..9a85f7869e 100644 --- a/src/ch/ch_process.c +++ b/src/ch/ch_process.c @@ -964,7 +964,7 @@ virCHProcessStart(virCHDriver *driver, if (virDomainInterfaceStartDevices(vm->def) < 0) return -1; - if (virCHMonitorBootVM(priv->monitor) < 0) { + if (virCHMonitorBootVM(priv->monitor, logCtxt) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to boot guest VM")); goto cleanup; -- 2.47.0

On 12/19/24 15:45, Praveen K Paladugu wrote:
LogContext management is now moved from Qemu driver to hypervisor. After migrating Qemu to use domain_logcontext, I extended ch driver to use also use domain_logcontext to capture early boot failures within domain specific log files.
Changes in V2: * refactored the patches to ensure all of them build.
Praveen K Paladugu (10): hypervisor: copy qemu log context mgmt to hypervisor hypervisor: rename reference to qemu in domain_logcontext hypervisor: drop qemu specific args in domainLogContextNew hypervisor: Build domain_logcontext libvirt_private: export symbols from domain_logcontext qemu: Modify qemu driver to use domainLogContext qemu: delete qemu_logcontext files ch: Enable logging for ch domains ch: move curl_data and curl_callback definitions ch: Enable logging curl responses from ch
po/POTFILES | 2 +- src/ch/ch_conf.h | 2 + src/ch/ch_monitor.c | 84 ++++++++++++------- src/ch/ch_monitor.h | 6 +- src/ch/ch_process.c | 36 ++++++-- .../domain_logcontext.c} | 78 +++++++++-------- src/hypervisor/domain_logcontext.h | 45 ++++++++++ src/hypervisor/meson.build | 1 + src/libvirt_private.syms | 6 ++ src/qemu/meson.build | 1 - src/qemu/qemu_domain.c | 28 +++---- src/qemu/qemu_domain.h | 12 +-- src/qemu/qemu_logcontext.h | 41 --------- src/qemu/qemu_nbdkit.c | 12 ++- src/qemu/qemu_process.c | 45 +++++----- 15 files changed, 235 insertions(+), 164 deletions(-) rename src/{qemu/qemu_logcontext.c => hypervisor/domain_logcontext.c} (79%) create mode 100644 src/hypervisor/domain_logcontext.h delete mode 100644 src/qemu/qemu_logcontext.h
While this now compiles after each commit, it's also unnecessary verbose. I mean - I'm squashing commits 1-7 into one as it'll enable git see that qemu_logcontext.c was actually moved and renamed. It can save us in the future. Reviewed-by: Michal Privoznik <mprivozn@redhat.com> and merged. Michal

On 12/20/2024 9:54 AM, Michal Prívozník wrote:
On 12/19/24 15:45, Praveen K Paladugu wrote:
LogContext management is now moved from Qemu driver to hypervisor. After migrating Qemu to use domain_logcontext, I extended ch driver to use also use domain_logcontext to capture early boot failures within domain specific log files.
Changes in V2: * refactored the patches to ensure all of them build.
Praveen K Paladugu (10): hypervisor: copy qemu log context mgmt to hypervisor hypervisor: rename reference to qemu in domain_logcontext hypervisor: drop qemu specific args in domainLogContextNew hypervisor: Build domain_logcontext libvirt_private: export symbols from domain_logcontext qemu: Modify qemu driver to use domainLogContext qemu: delete qemu_logcontext files ch: Enable logging for ch domains ch: move curl_data and curl_callback definitions ch: Enable logging curl responses from ch
po/POTFILES | 2 +- src/ch/ch_conf.h | 2 + src/ch/ch_monitor.c | 84 ++++++++++++------- src/ch/ch_monitor.h | 6 +- src/ch/ch_process.c | 36 ++++++-- .../domain_logcontext.c} | 78 +++++++++-------- src/hypervisor/domain_logcontext.h | 45 ++++++++++ src/hypervisor/meson.build | 1 + src/libvirt_private.syms | 6 ++ src/qemu/meson.build | 1 - src/qemu/qemu_domain.c | 28 +++---- src/qemu/qemu_domain.h | 12 +-- src/qemu/qemu_logcontext.h | 41 --------- src/qemu/qemu_nbdkit.c | 12 ++- src/qemu/qemu_process.c | 45 +++++----- 15 files changed, 235 insertions(+), 164 deletions(-) rename src/{qemu/qemu_logcontext.c => hypervisor/domain_logcontext.c} (79%) create mode 100644 src/hypervisor/domain_logcontext.h delete mode 100644 src/qemu/qemu_logcontext.h
While this now compiles after each commit, it's also unnecessary verbose. I mean - I'm squashing commits 1-7 into one as it'll enable git see that qemu_logcontext.c was actually moved and renamed. It can save us in the future.
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
and merged.
Michal
Sounds good Michal. Thanks for merging them. -- Regards, Praveen K Paladugu
participants (2)
-
Michal Prívozník
-
Praveen K Paladugu