[libvirt] [PATCH v2 06/13] qemu: unify code for reporting errors from QEMU log files
John Ferlan
jferlan at redhat.com
Wed Nov 18 23:05:07 UTC 2015
On 11/12/2015 12:19 PM, Daniel P. Berrange wrote:
> There are two pretty similar functions qemuProcessReadLog and
> qemuProcessReadChildErrors. Both read from the QEMU log file
> and try to strip out libvirt messages. The latter than reports
s/than/then
> an error, while the former lets the callers report an error.
>
> Re-write qemuProcessReadLog so that it uses a single read
> into a dynamically allocated buffer. Then introduce a new
> qemuProcessReportLogError that calls qemuProcessReadLog
> and reports an error.
>
> Convert all callers to use qemuProcessReportLogError.
>
> Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
> ---
> src/qemu/qemu_domain.c | 24 +-----
> src/qemu/qemu_domain.h | 2 +-
> src/qemu/qemu_migration.c | 2 +-
> src/qemu/qemu_monitor.c | 58 +++-----------
> src/qemu/qemu_monitor.h | 2 +-
> src/qemu/qemu_process.c | 200 ++++++++++++++++++----------------------------
> src/qemu/qemu_process.h | 4 +-
> 7 files changed, 95 insertions(+), 197 deletions(-)
>
[...]
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 69a0f97..c09e9dc 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -1549,7 +1549,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
>
> static int
> qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob,
> - int logfd)
> + int logfd, off_t pos)
> {
> qemuDomainObjPrivatePtr priv = vm->privateData;
> int ret = -1;
> @@ -1575,8 +1575,8 @@ qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob,
> &monitorCallbacks,
> driver);
>
> - if (mon)
> - ignore_value(qemuMonitorSetDomainLog(mon, logfd));
> + if (mon && logfd != -1 && pos != -1)
> + ignore_value(qemuMonitorSetDomainLog(mon, logfd, pos));
>
> virObjectLock(vm);
> virObjectUnref(vm);
> @@ -1630,111 +1630,76 @@ qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob,
> /**
> * qemuProcessReadLog: Read log file of a qemu VM
> * @fd: File descriptor of the log file
> - * @buf: buffer to store the read messages
> - * @buflen: allocated space available in @buf
> + * @msg: pointer to buffer to store the read messages in
msg after off? (not that it matters that much)
> * @off: Offset to start reading from
> - * @skipchar: Skip messages about created character devices
> *
> * Reads log of a qemu VM. Skips messages not produced by qemu or irrelevant
> - * messages. Returns length of the message stored in @buf, or -1 on error.
> + * messages. Returns returns 0 on success or -1 on error
> */
> -int
> -qemuProcessReadLog(int fd, char *buf, int buflen, int off, bool skipchar)
> +static int
> +qemuProcessReadLog(int fd, off_t offset, char **msg)
> {
> - char *filter_next = buf;
> - ssize_t bytes;
> + char *buf;
> + size_t buflen = 1024 * 128;
> + ssize_t got;
> char *eol;
> + char *filter_next;
>
> - while (off < buflen - 1) {
> - bytes = saferead(fd, buf + off, buflen - off - 1);
> - if (bytes < 0)
> - return -1;
> -
> - off += bytes;
> - buf[off] = '\0';
> + /* Best effort jump to start of messages */
> + ignore_value(lseek(fd, offset, SEEK_SET));
>
> - if (bytes == 0)
> - break;
> + if (VIR_ALLOC_N(buf, buflen) < 0)
> + return -1;
>
> - /* Filter out debug messages from intermediate libvirt process */
> - while ((eol = strchr(filter_next, '\n'))) {
> - *eol = '\0';
> - if (virLogProbablyLogMessage(filter_next) ||
> - (skipchar &&
> - STRPREFIX(filter_next, "char device redirected to"))) {
> - memmove(filter_next, eol + 1, off - (eol - buf));
> - off -= eol + 1 - filter_next;
> - } else {
> - filter_next = eol + 1;
> - *eol = '\n';
> - }
> - }
> + got = saferead(fd, buf, buflen - 1);
> + if (got < 0) {
> + virReportSystemError(errno, "%s",
> + _("Unable to read from log file"));
I know (because I ran Coverity on all the patches) that a future patch
changes this, but buf is leaked here - at least for a few patches.
> + return -1;
> }
Additionally, theoretically 'got' could be 0 here
>
> - return off;
> -}
> -
> -/*
> - * Read domain log and probably overwrite error if there's one in
> - * the domain log file. This function exists to cover the small
> - * window between fork() and exec() during which child may fail
> - * by libvirt's hand, e.g. placing onto a NUMA node failed.
> - */
> -static int
> -qemuProcessReadChildErrors(virQEMUDriverPtr driver,
> - virDomainObjPtr vm,
> - off_t originalOff)
> -{
> - int ret = -1;
> - int logfd;
> - off_t off = 0;
> - ssize_t bytes;
> - char buf[1024] = {0};
> - char *eol, *filter_next = buf;
> -
> - if ((logfd = qemuDomainOpenLog(driver, vm, originalOff)) < 0)
> - goto cleanup;
> -
> - while (off < sizeof(buf) - 1) {
> - bytes = saferead(logfd, buf + off, sizeof(buf) - off - 1);
> - if (bytes < 0) {
> - VIR_WARN("unable to read from log file: %s",
> - virStrerror(errno, buf, sizeof(buf)));
> - goto cleanup;
> - }
> + buf[got] = '\0';
>
> - off += bytes;
> - buf[off] = '\0';
> -
> - if (bytes == 0)
> - break;
> -
> - while ((eol = strchr(filter_next, '\n'))) {
> - *eol = '\0';
> - if (STRPREFIX(filter_next, "libvirt: ")) {
> - filter_next = eol + 1;
> - *eol = '\n';
> - break;
> - } else {
> - memmove(filter_next, eol + 1, off - (eol - buf));
> - off -= eol + 1 - filter_next;
> - }
> + /* Filter out debug messages from intermediate libvirt process */
> + filter_next = buf;
> + while ((eol = strchr(filter_next, '\n'))) {
> + *eol = '\0';
> + if (virLogProbablyLogMessage(filter_next) ||
> + STRPREFIX(filter_next, "char device redirected to")) {
> + size_t skip = (eol + 1) - filter_next;
> + memmove(filter_next, eol + 1, (got - skip) + 1);
> + got -= skip;
> + } else {
> + filter_next = eol + 1;
> + *eol = '\n';
> }
> }
Coverity also has a false positive here w/r/t filter_next - it claims
filter_next (because it pointed to buf) is leaked when the code returns.
Seems it could have something to do with when got == 1, although I don't
see it. FWIW: the Coverity notes:
(9) Event cond_false: Condition "eol = strchr(filter_next, 10)",
taking false branch
then
(11) Event cond_true: Condition "buf[got - 1] == 10", taking true branch
So that says, 'buf' (filter_next) didn't find '\n' in the strchr() call
(e.g. taking false branch), then somehow buf[got - 1] == '\n';
If I set filter_next to NULL right after the while loop there's no error
(hence my feeling on a false positive).
An ACK mainly because I think what's being done is fine...
John
>
> - if (off > 0) {
> - /* Found an error in the log. Report it */
> - virResetLastError();
> - virReportError(VIR_ERR_INTERNAL_ERROR,
> - _("Process exited prior to exec: %s"),
> - buf);
> + if (buf[got - 1] == '\n') {
> + buf[got - 1] = '\0';
> + got--;
> }
> + VIR_SHRINK_N(buf, buflen, buflen - got - 1);
> + *msg = buf;
> + return 0;
> +}
>
> - ret = 0;
>
> - cleanup:
> - VIR_FORCE_CLOSE(logfd);
> - return ret;
[...]
More information about the libvir-list
mailing list