VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES = (1<<18),
VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM = (1<<19),
VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT = (1<<20),
+ VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST = (1<<21),
} virDomainXMLInternalFlags;
VIR_ENUM_IMPL(virDomainTaint, VIR_DOMAIN_TAINT_LAST,
if (virXPathLongLong("number(./clock/@adjustment)", ctxt,
&def->clock.data.variable.adjustment) < 0)
def->clock.data.variable.adjustment = 0;
+ if (virXPathLongLong("number(./clock/@adjustment0)", ctxt,
+ &def->clock.data.variable.adjustment0) < 0)
+ def->clock.data.variable.adjustment0 = 0;
tmp = virXPathString("string(./clock/@basis)", ctxt);
if (tmp) {
if ((def->clock.data.variable.basis = virDomainClockBasisTypeFromString(tmp)) < 0) {
verify(((VIR_DOMAIN_XML_INTERNAL_STATUS |
VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
- VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES)
+ VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
+ VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST)
& DUMPXML_FLAGS) == 0);
/* This internal version can accept VIR_DOMAIN_XML_INTERNAL_*,
virCheckFlags(DUMPXML_FLAGS |
VIR_DOMAIN_XML_INTERNAL_STATUS |
VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
- VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES,
+ VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
+ VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST,
-1);
if (!(type = virDomainVirtTypeToString(def->virtType))) {
virBufferAsprintf(buf, " adjustment='%lld' basis='%s'",
def->clock.data.variable.adjustment,
virDomainClockBasisTypeToString(def->clock.data.variable.basis));
+ if (flags & VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST) {
+ if (def->clock.data.variable.adjustment0)
+ virBufferAsprintf(buf, " adjustment0='%lld'",
+ def->clock.data.variable.adjustment0);
+ }
break;
case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
virBufferEscapeString(buf, " timezone='%s'", def->clock.data.timezone);
unsigned int flags = (VIR_DOMAIN_XML_SECURE |
VIR_DOMAIN_XML_INTERNAL_STATUS |
VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
- VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES);
+ VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
+ VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST);
int ret = -1;
char *xml;
if (!(obj = virDomainObjParseFile(statusFile, caps, xmlopt, expectedVirtTypes,
VIR_DOMAIN_XML_INTERNAL_STATUS |
VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
- VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES)))
+ VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
+ VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST)))
goto error;
virUUIDFormat(obj->def->uuid, uuidstr);
return 0;
}
-
static int
qemuProcessHandleRTCChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
virDomainObjPtr vm,
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
virObjectLock(vm);
- event = virDomainEventRTCChangeNewFromObj(vm, offset);
- 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);