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(a)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