[libvirt] [PATCH v2 12/13] qemu: convert monitor to use qemuDomainLogContextPtr indirectly

John Ferlan jferlan at redhat.com
Thu Nov 19 00:53:16 UTC 2015



On 11/12/2015 12:19 PM, Daniel P. Berrange wrote:
> Currently the QEMU monitor is given an FD to the logfile. This
> won't work in the future with virtlogd, so it needs to use the
> qemuDomainLogContextPtr instead, but it shouldn't directly
> access that object either. So define a callback that the
> monitor can use for reporting errors from the log file.
> 
> Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
> ---
>  src/qemu/qemu_domain.c    | 12 ------
>  src/qemu/qemu_domain.h    |  2 -
>  src/qemu/qemu_migration.c |  2 +-
>  src/qemu/qemu_monitor.c   | 51 ++++++++++++++------------
>  src/qemu/qemu_monitor.h   |  8 +++-
>  src/qemu/qemu_process.c   | 93 ++++++++++++++++++++++++-----------------------
>  src/qemu/qemu_process.h   |  4 --
>  7 files changed, 84 insertions(+), 88 deletions(-)
> 

[...]

> index d3f0c09..bd5d9ca 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -94,9 +94,10 @@ struct _qemuMonitor {
>      char *balloonpath;
>      bool ballooninit;
>  
> -    /* Log file fd of the qemu process to dig for usable info */
> -    int logfd;
> -    off_t logpos;
> +    /* Log file context of the qemu process to dig for usable info */
> +    qemuMonitorReportDomainLogError logFunc;
> +    void *logOpaque;
> +    virFreeCallback logDestroy;
>  };
>  
>  /**
> @@ -315,7 +316,6 @@ qemuMonitorDispose(void *obj)
>      VIR_FREE(mon->buffer);
>      virJSONValueFree(mon->options);
>      VIR_FREE(mon->balloonpath);
> -    VIR_FORCE_CLOSE(mon->logfd);
>  }
>  
>  
> @@ -706,18 +706,17 @@ qemuMonitorIO(int watch, int fd, int events, void *opaque)
>      }
>  
>      if (error || eof) {
> -        if (hangup && mon->logfd != -1) {
> +        if (hangup && mon->logFunc != NULL) {
>              /* Check if an error message from qemu is available and if so, use
>               * it to overwrite the actual message. It's done only in early
>               * startup phases or during incoming migration when the message
>               * from qemu is certainly more interesting than a
>               * "connection reset by peer" message.
>               */
> -            qemuProcessReportLogError(mon->logfd,
> -                                      mon->logpos,
> -                                      _("early end of file from monitor, "
> -                                        "possible problem"));
> -            VIR_FORCE_CLOSE(mon->logfd);
> +            mon->logFunc(mon,
> +                         _("early end of file from monitor, "
> +                           "possible problem"),
> +                         mon->logOpaque);

Mostly a consistency thing and not that it should happen since
qemuConnectMonitor checks for logCtxt before calling
qemuMonitorSetDomainLog; however, qemuMonitorClose and
qemuMonitorSetDomainLog check for mon->logOpaque before calling
logDestroy. Likewise, if logFunc is called with NULL (logOpaque) life
won't be good.

I don't think there's anything wrong with the current code - just caused
me to double check things.

>              virCopyLastError(&mon->lastError);
>              virResetLastError();
>          }
> @@ -802,7 +801,6 @@ qemuMonitorOpenInternal(virDomainObjPtr vm,
>      if (!(mon = virObjectLockableNew(qemuMonitorClass)))
>          return NULL;
>  
> -    mon->logfd = -1;
>      if (virCondInit(&mon->notify) < 0) {
>          virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>                         _("cannot initialize monitor condition"));
> @@ -932,6 +930,13 @@ qemuMonitorClose(qemuMonitorPtr mon)
>          VIR_FORCE_CLOSE(mon->fd);
>      }
>  
> +    if (mon->logDestroy && mon->logOpaque) {
> +        mon->logDestroy(mon->logOpaque);
> +        mon->logOpaque = NULL;
> +        mon->logDestroy = NULL;
> +        mon->logFunc = NULL;
> +    }
> +
>      /* In case another thread is waiting for its monitor command to be
>       * processed, we need to wake it up with appropriate error set.
>       */
> @@ -3646,21 +3651,21 @@ qemuMonitorGetDeviceAliases(qemuMonitorPtr mon,
>   * early startup errors of qemu.
>   *
>   * @mon: Monitor object to set the log file reading on
> - * @logfd: File descriptor of the already open log file
> - * @pos: position to read errors from
> + * @func: the callback to report errors
> + * @opaque: data to pass to @func

Missing @destroy

>   */
> -int
> -qemuMonitorSetDomainLog(qemuMonitorPtr mon, int logfd, off_t pos)
> +void
> +qemuMonitorSetDomainLog(qemuMonitorPtr mon,
> +                        qemuMonitorReportDomainLogError func,
> +                        void *opaque,
> +                        virFreeCallback destroy)

[...]

> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 132b3eb..4a2e2c1 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -1544,9 +1544,22 @@ static qemuMonitorCallbacks monitorCallbacks = {
>      .domainMigrationStatus = qemuProcessHandleMigrationStatus,
>  };
>  
> +static void
> +qemuProcessMonitorReportLogError(qemuMonitorPtr mon,
> +                                 const char *msg,
> +                                 void *opaque);
> +
> +
> +static void
> +qemuProcessMonitorLogFree(void *opaque)
> +{
> +    qemuDomainLogContextPtr logCtxt = opaque;

This could check opaque != NULL and avoid the other checks for
logDestroy && logOpaque - your call.

> +    qemuDomainLogContextFree(logCtxt);
> +}
> +
>  static int
>  qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob,
> -                   int logfd, off_t pos)
> +                   qemuDomainLogContextPtr logCtxt)
>  {
>      qemuDomainObjPrivatePtr priv = vm->privateData;
>      int ret = -1;
> @@ -1572,8 +1585,13 @@ qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob,
>                            &monitorCallbacks,
>                            driver);
>  
> -    if (mon && logfd != -1 && pos != -1)
> -        ignore_value(qemuMonitorSetDomainLog(mon, logfd, pos));
> +    if (mon && logCtxt) {
> +        qemuDomainLogContextRef(logCtxt);
> +        qemuMonitorSetDomainLog(mon,
> +                                qemuProcessMonitorReportLogError,
> +                                logCtxt,
> +                                qemuProcessMonitorLogFree);
> +    }
>  
>      virObjectLock(vm);
>      virObjectUnref(vm);
> @@ -1626,36 +1644,22 @@ qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob,
>  
>  /**
>   * qemuProcessReadLog: Read log file of a qemu VM
> - * @fd: File descriptor of the log file
> + * @logCtxt: the domain log context
>   * @msg: pointer to buffer to store the read messages in
> - * @off: Offset to start reading from
>   *
>   * Reads log of a qemu VM. Skips messages not produced by qemu or irrelevant
>   * messages. Returns returns 0 on success or -1 on error
>   */
>  static int
> -qemuProcessReadLog(int fd, off_t offset, char **msg)
> +qemuProcessReadLog(qemuDomainLogContextPtr logCtxt, char **msg)
>  {
>      char *buf;
> -    size_t buflen = 1024 * 128;
>      ssize_t got;
>      char *eol;
>      char *filter_next;
>  
> -    /* Best effort jump to start of messages */
> -    ignore_value(lseek(fd, offset, SEEK_SET));
> -
> -    if (VIR_ALLOC_N(buf, buflen) < 0)
> -        return -1;
> -
> -    got = saferead(fd, buf, buflen - 1);
> -    if (got < 0) {
> -        virReportSystemError(errno, "%s",
> -                             _("Unable to read from log file"));
> +    if ((got = qemuDomainLogContextRead(logCtxt, &buf)) < 0)
>          return -1;
> -    }
> -
> -    buf[got] = '\0';
>  
>      /* Filter out debug messages from intermediate libvirt process */
>      filter_next = buf;
> @@ -1672,24 +1676,24 @@ qemuProcessReadLog(int fd, off_t offset, char **msg)
>          }
>      }
>  
> -    if (buf[got - 1] == '\n') {
> +    if (got > 0 &&
> +        buf[got - 1] == '\n') {
>          buf[got - 1] = '\0';
>          got--;
>      }
> -    VIR_SHRINK_N(buf, buflen, buflen - got - 1);
> +    ignore_value(VIR_REALLOC_N_QUIET(buf, got + 1));
>      *msg = buf;

This is where I first saw Coverity erroneously complaining filter_next
is leaked... If I set filter_buf = NULL after the while loop there's no
complaint. Very strange.

>      return 0;
>  }
>  
>  


ACK - as long as @destroy is noted and your call on other comments.

John




More information about the libvir-list mailing list