From 6ee78d334a9e8e841880d6931892a8ebaa73faeb Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Fri, 29 Apr 2016 18:01:39 +0200 Subject: [PATCH] qemu: Refresh RTC adjustment on qemuProcessReconnect https://bugzilla.redhat.com/show_bug.cgi?id=1139766 Thing is, for some reasons you can have your domain's RTC to be in something different than UTC. More weirdly, it's not only time zone what you can shift it of, but an arbitrary value. So, if domain is configured that way, libvirt will correctly put it onto qemu cmd line and moreover track it as this offset changes during domain's life time (e.g. because guest OS decides the best thing to do is set new time to RTC). Anyway, they way in which this tracking is implemented is events. But we've got a problem if change in guest's RTC occurs and the daemon is not running. The event is lost and we end up reporting invalid value in domain XML. Therefore, when the daemon is starting up again and it is reconnecting to all running domains, re-fetch their RTC so the correct offset value can be computed. Signed-off-by: Michal Privoznik --- src/qemu/qemu_process.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 527300aad0..348b3920df 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1992,6 +1992,42 @@ qemuRefreshVirtioChannelState(virQEMUDriverPtr driver, return ret; } +static void +qemuRefreshRTC(virQEMUDriverPtr driver, + virDomainObjPtr vm) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + time_t now, then; + struct tm thenbits; + long localOffset; + int rv; + + if (vm->def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_VARIABLE) + return; + + memset(&thenbits, 0, sizeof(thenbits)); + qemuDomainObjEnterMonitor(driver, vm); + now = time(NULL); + rv = qemuMonitorGetRTCTime(priv->mon, &thenbits); + if (qemuDomainObjExitMonitor(driver, vm) < 0) + rv = -1; + + if (rv < 0) + return; + + thenbits.tm_isdst = -1; + if ((then = mktime(&thenbits)) == (time_t) -1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to convert time")); + return; + } + + /* Thing is, @now is in local TZ but @then in UTC. */ + if (virTimeLocalOffsetFromUTC(&localOffset) < 0) + return; + + vm->def->clock.data.variable.adjustment = then - now + localOffset; +} int qemuProcessRefreshBalloonState(virQEMUDriverPtr driver, @@ -3673,6 +3709,9 @@ qemuProcessReconnect(void *opaque) if (qemuRefreshVirtioChannelState(driver, obj) < 0) goto error; + /* If querying of guest's RTC failed, report error, but do not kill the domain. */ + qemuRefreshRTC(driver, obj); + if (qemuProcessRefreshBalloonState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0) goto error;