[Adding qemu]
On 05/22/2014 05:07 AM, Laine Stump wrote:
commit e31b5cf393857 attempted to fix libvirt's
VIR_DOMAIN_EVENT_ID_RTC_CHANGE, which is documentated to always
s/documentated/documented/
provide the new offset of the domain's real time clock from UTC.
The
problem was that, in the case that qemu is provided with an "-rtc
base=x" where x is an absolute time (rather than "utc" or
"localtime"), the offset sent by qemu's RTC_CHANGE event is *not* the
new offset from UTC, but rather is the sum of all changes to the
domain's RTC since it was started with base=x.
So, despite what was said in commit e31b5cf393857, if we assume that
the original value stored in "adjustment" was the offset from UTC at
the time the domain was started, we can always determine the current
offset from UTC by simply adding the most recent (i.e. current) offset
from qemu to that original adjustment.
Is this true even if we miss an RTC update event from qemu? I'm worried
about the following situation:
user prepares to do a libvirtd upgrade, so libvirtd is shut down. Then
the guest triggers an RTC update, so qemu sends an event, but the event
is lost. Then libvirtd starts again, and doesn't realize the event is lost.
Do we need more help from qemu, such as a new field to an existing QMP
command (or a new QMP command) that lists the cumulative offset that
qemu is using, where we call that query command any time after an RTC
update event or after a libvirtd restart? I'm wondering if this is more
a bug in qemu for not providing the right information rather than
libvirt's responsibility to work around it. If the only way to keep
accurate information is to sum the values we get from events, we are at
risk of a lost event getting us messed up.
This patch accomplishes that by storing the initial adjustment in the
domain's status as "adjustment0". Each time a new RTC_CHANGE event is
received from qemu, we simply add adjustment0 to the value sent by
qemu, store that as the new adjustment, and forward that value on to
any event handler.
This patch (*not* e31b5cf393857, which should be reverted prior to
applying this patch) fixes:
https://bugzilla.redhat.com/show_bug.cgi?id=964177
(for the case where basis='utc'. It does not fix basis='localtime')
---
Changes from V1: remove all attempts to fix basis='localtime' in favor
of fixing it in a simpler and better manner in a separate patch.
I'd also appreciate it if the qemu developers can chime in on what is
supposed to happen for localtime guests.
There are at least four combinations:
host running on UTC bios time, guest running on UTC time (in my opinion,
the only sane setting, but we're talking about reality not sanity)
host running on UTC, guest running on localtime (perhaps the guest is
windows, and we know that windows prefers to run on localtime)
host running on localtime bios (perhaps because it is dual-boot with
windows, and windows prefers bios in localtime), guest running on UTC time
host running on localtime, guest running on localtime
But it gets even more complicated. The host localtime need not be
consistent with the guest localtime. That is, I could be a cloud
provider with servers on the east coast, and renting out processor time
to a client on the west coast that wants their guest tied to west coast
localtime. And that's assuming that both host and guest switch in and
out of daylight savings at the same time, which falls apart when you
cross political boundaries. Then there's the fun of migration (what if
my server farm is spread across multiple timezones - does migration take
into account the difference in localtime between source and destination
servers).
I can _totally_ understand the desire to run a GUEST in such a way that
the guest thinks it has a bios stored in localtime (and when the guest
updates the RTC twice a year to account for daylight savings, it changes
what offset we track about the guest). But I think it is INSANITY to
ever try and run a host on a localtime system (daylight savings changes
in the host are just asking for problems to the guests) - so even if the
host is tied to localtime bios, it is still probably wiser for qemu to
base its offsets to UTC no matter what. If the commandline allows a
specification of a localtime offset, I think it should be used ONLY for
a one-time up-front conversion into a corresponding UTC offset, and then
execute qemu in relation to utc thereafter (therefore, migration is
always done in terms of utc, without regards for whether source and
destination have a different localtime).
src/conf/domain_conf.c | 21 +++++++++++++++++----
src/conf/domain_conf.h | 7 +++++++
src/qemu/qemu_command.c | 9 +++++++++
src/qemu/qemu_process.c | 27 ++++++++++++++++++++++-----
4 files changed, 55 insertions(+), 9 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
- if (vm->def->clock.offset ==
VIR_DOMAIN_CLOCK_OFFSET_VARIABLE)
+ if (vm->def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE) {
+ /* when a basedate is manually given on the qemu commandline
+ * rather than simply "-rtc base=utc", the offset sent by qemu
+ * in this event is *not* the new offset from UTC, but is
+ * instead the new offset from the *original basedate* +
+ * uptime. For example, if the original offset was 3600 and
+ * the guest clock has been advanced by 10 seconds, qemu will
+ * send "10" in the event - this means that the new offset
+ * from UTC is 3610, *not* 10. If the guest clock is advanced
+ * by another 10 seconds, qemu will now send "20" - i.e. each
+ * event is the sum of the most recent change and all previous
+ * changes since the domain was started. Fortunately, we have
+ * saved the initial offset in "adjustment0", so to arrive at
+ * the proper new "adjustment", we just add the most recent
+ * offset to adjustment0.
+ */
+ offset += vm->def->clock.data.variable.adjustment0;
vm->def->clock.data.variable.adjustment = offset;
- if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
- VIR_WARN("unable to save domain status with RTC change");
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
+ VIR_WARN("unable to save domain status with RTC change");
+ }
+
+ event = virDomainEventRTCChangeNewFromObj(vm, offset);
virObjectUnlock(vm);
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library
http://libvirt.org