]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: Report the offset from host UTC for RTC_CHANGE event
authorOsier Yang <jyang@redhat.com>
Wed, 5 Jun 2013 10:32:59 +0000 (18:32 +0800)
committerCole Robinson <crobinso@redhat.com>
Thu, 11 Jul 2013 21:46:45 +0000 (17:46 -0400)
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'/>

(cherry picked from commit e31b5cf393857a6ca78d148c19393e28dfb39de1)

src/conf/domain_conf.c
src/conf/domain_conf.h
src/qemu/qemu_command.c
src/qemu/qemu_process.c

index 4dc7d254232e8e1136bced50c22233ec201d89c1..3c54f72e3a8611dda8a8c1bea840ce72ea2ef4a5 100644 (file)
@@ -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,
@@ -10768,6 +10769,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;
 
@@ -15330,7 +15341,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_*,
@@ -15352,7 +15364,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))) {
@@ -15746,6 +15759,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);
@@ -16124,7 +16141,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;
@@ -16212,7 +16230,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);
index 3a0f23ae7eaa634cb5d16bd616ae5ec4def9c8a9..a2a9ff507a5873610eef72d9ab36360dbd89f36a 100644 (file)
@@ -1734,6 +1734,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
index c81579998a1e862fa5efd465e8873895eca774bb..6699e6e72f850ebc21a4c6006068989351a92e7a 100644 (file)
@@ -5338,6 +5338,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,
index 0be43b46ef721d9b30231ec0fcd914ba613bb995..e169f4d002b9077d45e0a0f368bad0263bffadee 100644 (file)
@@ -789,6 +789,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)