mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-01 17:35:17 +00:00
qemu: Report the offset from host UTC for RTC_CHANGE event
https://bugzilla.redhat.com/show_bug.cgi?id=964177 Though both libvirt and QEMU's document say RTC_CHANGE returns the offset from the host UTC, qemu actually returns the offset from the specified date instead when specific date is provided (-rtc base=$date). It's not safe for qemu to fix it in code, it worked like that for 3 years, changing it now may break other QEMU use cases. What qemu tries to do is to fix the document: http://lists.gnu.org/archive/html/qemu-devel/2013-05/msg04782.html And in libvirt side, instead of replying on the value from qemu, this converts the offset returned from qemu to the offset from host UTC, by: /* * a: the offset from qemu RTC_CHANGE event * b: The specified date (-rtc base=$date) * c: the host date when libvirt gets the RTC_CHANGE event * offset: What libvirt will report */ offset = a + (b - c); The specified date (-rtc base=$date) is recorded in clock's def as an internal only member (may be useful to exposed outside?). Internal only XML tag "basetime" is introduced to not lose the guest's basetime after libvirt restarting/reloading: <clock offset='variable' adjustment='304' basis='utc' basetime='1370423588'/>
This commit is contained in:
parent
d60570b315
commit
e31b5cf393
@ -96,6 +96,7 @@ typedef enum {
|
||||
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_BASEDATE = (1 << 21),
|
||||
} virDomainXMLInternalFlags;
|
||||
|
||||
VIR_ENUM_IMPL(virDomainTaint, VIR_DOMAIN_TAINT_LAST,
|
||||
@ -11193,6 +11194,16 @@ virDomainDefParseXML(xmlDocPtr xml,
|
||||
break;
|
||||
}
|
||||
|
||||
if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE &&
|
||||
flags & VIR_DOMAIN_XML_INTERNAL_BASEDATE) {
|
||||
if (virXPathULongLong("number(./clock/@basedate)", ctxt,
|
||||
&def->clock.data.variable.basedate) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("invalid basedate"));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if ((n = virXPathNodeSet("./clock/timer", ctxt, &nodes)) < 0)
|
||||
goto error;
|
||||
|
||||
@ -15788,7 +15799,8 @@ virDomainResourceDefFormat(virBufferPtr buf,
|
||||
|
||||
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_BASEDATE)
|
||||
& DUMPXML_FLAGS) == 0);
|
||||
|
||||
/* This internal version can accept VIR_DOMAIN_XML_INTERNAL_*,
|
||||
@ -15810,7 +15822,8 @@ virDomainDefFormatInternal(virDomainDefPtr def,
|
||||
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_BASEDATE,
|
||||
-1);
|
||||
|
||||
if (!(type = virDomainVirtTypeToString(def->virtType))) {
|
||||
@ -16208,6 +16221,10 @@ virDomainDefFormatInternal(virDomainDefPtr def,
|
||||
virBufferAsprintf(buf, " adjustment='%lld' basis='%s'",
|
||||
def->clock.data.variable.adjustment,
|
||||
virDomainClockBasisTypeToString(def->clock.data.variable.basis));
|
||||
|
||||
if (flags & VIR_DOMAIN_XML_INTERNAL_BASEDATE)
|
||||
virBufferAsprintf(buf, " basedate='%llu'",
|
||||
def->clock.data.variable.basedate);
|
||||
break;
|
||||
case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
|
||||
virBufferEscapeString(buf, " timezone='%s'", def->clock.data.timezone);
|
||||
@ -16586,7 +16603,8 @@ virDomainSaveStatus(virDomainXMLOptionPtr xmlopt,
|
||||
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_BASEDATE);
|
||||
|
||||
int ret = -1;
|
||||
char *xml;
|
||||
@ -16674,7 +16692,8 @@ virDomainObjListLoadStatus(virDomainObjListPtr doms,
|
||||
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_BASEDATE)))
|
||||
goto error;
|
||||
|
||||
virUUIDFormat(obj->def->uuid, uuidstr);
|
||||
|
@ -1767,6 +1767,11 @@ struct _virDomainClockDef {
|
||||
struct {
|
||||
long long adjustment;
|
||||
int basis;
|
||||
|
||||
/* Store the base date (-rtc base=$date, in seconds
|
||||
* since the Epoch) of guest process, internal only
|
||||
*/
|
||||
unsigned long long basedate;
|
||||
} variable;
|
||||
|
||||
/* Timezone name, when
|
||||
|
@ -5519,6 +5519,9 @@ qemuBuildClockArgStr(virDomainClockDefPtr def)
|
||||
now += def->data.variable.adjustment;
|
||||
gmtime_r(&now, &nowbits);
|
||||
|
||||
/* Store the guest's basedate */
|
||||
def->data.variable.basedate = now;
|
||||
|
||||
virBufferAsprintf(&buf, "base=%d-%02d-%02dT%02d:%02d:%02d",
|
||||
nowbits.tm_year + 1900,
|
||||
nowbits.tm_mon + 1,
|
||||
|
@ -796,6 +796,19 @@ qemuProcessHandleRTCChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
||||
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
||||
|
||||
virObjectLock(vm);
|
||||
|
||||
/* QEMU's RTC_CHANGE event returns the offset from the specified
|
||||
* date instead of the host UTC if a specific date is provided
|
||||
* (-rtc base=$date). We need to convert it to be offset from
|
||||
* host UTC.
|
||||
*/
|
||||
if (vm->def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE) {
|
||||
time_t now = time(NULL);
|
||||
|
||||
offset += vm->def->clock.data.variable.basedate -
|
||||
(unsigned long long)now;
|
||||
}
|
||||
|
||||
event = virDomainEventRTCChangeNewFromObj(vm, offset);
|
||||
|
||||
if (vm->def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE)
|
||||
|
Loading…
x
Reference in New Issue
Block a user