From 896761e5c7b32741c609959450d1b9cb3ae1e4d4 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 30 Jan 2009 17:07:29 +0000 Subject: [PATCH] Fix numerous bugs in QEMU domain startup --- ChangeLog | 9 +++++ src/domain_conf.c | 1 + src/qemu_driver.c | 83 ++++++++++++++++++++++++++++++++++------------- 3 files changed, 70 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index a6deaf8712..c332e201d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Fri Jan 30 16:58:22 GMT 2009 Daniel P. Berrange + + Misc QEMU driver startup fixes + * src/domain_conf.c: Add initialization of monitor_watch + * src/qemud_driver.c: Fix infinite loop when QEMU quits on + startup. Fix watch removal if watch isn't added. Fix use + of VNC password from global driver config. Avoid zombies + from daemonizing QEMU. Fix memory leak in monitorpath + Fri Jan 30 16:51:22 GMT 2009 Daniel P. Berrange * src/lxc_driver.c: Avoid probing for LXC until we know we're diff --git a/src/domain_conf.c b/src/domain_conf.c index f696b6a9e1..adcd032221 100644 --- a/src/domain_conf.c +++ b/src/domain_conf.c @@ -497,6 +497,7 @@ virDomainObjPtr virDomainAssignDef(virConnectPtr conn, virDomainObjLock(domain); domain->state = VIR_DOMAIN_SHUTOFF; domain->def = def; + domain->monitor_watch = -1; if (VIR_REALLOC_N(doms->objs, doms->count + 1) < 0) { virReportOOMError(conn); diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 29592ab4cd..09f69bf1c2 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -355,10 +355,9 @@ qemudReconnectVMs(struct qemud_driver *driver) qemudLog(QEMUD_ERR, _("Failed to reconnect monitor for %s: %d\n"), vm->def->name, rc); goto next_error; - } else - vm->monitorpath = status->monitorpath; + } - if((vm->logfile = qemudLogFD(NULL, driver->logDir, vm->def->name)) < 0) + if ((vm->logfile = qemudLogFD(NULL, driver->logDir, vm->def->name)) < 0) return -1; if (vm->def->id >= driver->nextvmid) @@ -376,6 +375,8 @@ next_error: vm->newDef = NULL; next: virDomainObjUnlock(vm); + if (status) + VIR_FREE(status->monitorpath); VIR_FREE(status); VIR_FREE(config); } @@ -617,6 +618,9 @@ typedef int qemudHandlerMonitorOutput(virConnectPtr conn, const char *output, int fd); +/* + * Returns -1 for error, 0 on end-of-file, 1 for success + */ static int qemudReadMonitorOutput(virConnectPtr conn, virDomainObjPtr vm, @@ -630,7 +634,7 @@ qemudReadMonitorOutput(virConnectPtr conn, int got = 0; buf[0] = '\0'; - /* Consume & discard the initial greeting */ + /* Consume & discard the initial greeting */ while (got < (buflen-1)) { int ret; @@ -670,11 +674,17 @@ qemudReadMonitorOutput(virConnectPtr conn, _("Failure while reading %s startup output"), what); return -1; } + } else if (ret == 0) { + return 0; } else { got += ret; buf[got] = '\0'; - if ((ret = func(conn, vm, buf, fd)) != 1) - return ret; + ret = func(conn, vm, buf, fd); + if (ret == -1) + return -1; + if (ret == 1) + continue; + return 1; } } @@ -724,11 +734,14 @@ static int qemudOpenMonitor(virConnectPtr conn, } if (!reconnect) { - ret = qemudReadMonitorOutput(conn, - vm, monfd, - buf, sizeof(buf), - qemudCheckMonitorPrompt, - "monitor", 10000); + if (qemudReadMonitorOutput(conn, + vm, monfd, + buf, sizeof(buf), + qemudCheckMonitorPrompt, + "monitor", 10000) <= 0) + ret = -1; + else + ret = 0; } else { vm->monitor = monfd; ret = 0; @@ -858,7 +871,7 @@ static int qemudWaitForMonitor(virConnectPtr conn, if ((logfd = qemudLogReadFD(conn, driver->logDir, vm->def->name, pos)) < 0) - return logfd; + return -1; ret = qemudReadMonitorOutput(conn, vm, logfd, buf, sizeof(buf), qemudFindCharDevicePTYs, @@ -866,7 +879,17 @@ static int qemudWaitForMonitor(virConnectPtr conn, if (close(logfd) < 0) qemudLog(QEMUD_WARN, _("Unable to close logfile: %s\n"), strerror(errno)); - return ret; + + if (ret == 1) /* Success */ + return 0; + + if (ret == -1) + return -1; + + /* Unexpected end of file - inform user of QEMU log data */ + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("unable to start guest: %s"), buf); + return -1; } static int @@ -1033,7 +1056,7 @@ qemudInitPasswords(virConnectPtr conn, if (vm->def->graphics && vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && - vm->def->graphics->data.vnc.passwd) { + (vm->def->graphics->data.vnc.passwd || driver->vncPassword)) { if (qemudMonitorCommandExtra(vm, "change vnc password", vm->def->graphics->data.vnc.passwd ? @@ -1212,14 +1235,25 @@ static int qemudStartVMDaemon(virConnectPtr conn, /* wait for qemu process to to show up */ if (ret == 0) { int retries = 100; - while (retries) { - if ((ret = virFileReadPid(driver->stateDir, vm->def->name, &vm->pid)) == 0) - break; - usleep(100*1000); - retries--; + int childstat; + + while (waitpid(child, &childstat, 0) == -1 && + errno == EINTR); + + if (childstat == 0) { + while (retries) { + if ((ret = virFileReadPid(driver->stateDir, vm->def->name, &vm->pid)) == 0) + break; + usleep(100*1000); + retries--; + } + if (ret) + qemudLog(QEMUD_WARN, _("Domain %s didn't show up\n"), vm->def->name); + } else { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("Unable to daemonize QEMU process")); + ret = -1; } - if (ret) - qemudLog(QEMUD_WARN, _("Domain %s didn't show up\n"), vm->def->name); } if (ret == 0) { @@ -1262,14 +1296,17 @@ static void qemudShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED, if (!virDomainIsActive(vm)) return; - qemudLog(QEMUD_INFO, _("Shutting down VM '%s'\n"), vm->def->name); + qemudLog(QEMUD_DEBUG, _("Shutting down VM '%s'\n"), vm->def->name); if (virKillProcess(vm->pid, 0) == 0 && virKillProcess(vm->pid, SIGTERM) < 0) qemudLog(QEMUD_ERROR, _("Failed to send SIGTERM to %s (%d): %s\n"), vm->def->name, vm->pid, strerror(errno)); - virEventRemoveHandle(vm->monitor_watch); + if (vm->monitor_watch != -1) { + virEventRemoveHandle(vm->monitor_watch); + vm->monitor_watch = -1; + } if (close(vm->logfile) < 0) qemudLog(QEMUD_WARN, _("Unable to close logfile %d: %s\n"), -- GitLab