]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Support clock=variable relative to localtime
authorPhilipp Hahn <hahn@univention.de>
Mon, 6 Feb 2012 13:59:16 +0000 (14:59 +0100)
committerEric Blake <eblake@redhat.com>
Mon, 2 Apr 2012 15:08:31 +0000 (09:08 -0600)
Since Xen 3.1 the clock=variable semantic is supported. In addition to
qemu/kvm Xen also knows about a variant where the offset is relative to
'localtime' instead of 'utc'.

Extends the libvirt structure with a flag 'basis' to specify, if the
offset is relative to 'localtime' or 'utc'.

Extends the libvirt structure with a flag 'reset' to force the reset
behaviour of 'localtime' and 'utc'; this is needed for backward
compatibility with previous versions of libvirt, since they report
incorrect XML.

Adapt the only user 'qemu' to the new name.
Extend the RelaxNG schema accordingly.
Document the new 'basis' attribute in the HTML documentation.
Adapt test for the new attribute.

Signed-off-by: Philipp Hahn <hahn@univention.de>
docs/formatdomain.html.in
docs/schemas/domaincommon.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
src/libvirt_private.syms
src/qemu/qemu_command.c
src/qemu/qemu_process.c
tests/qemuxml2argvdata/qemuxml2argv-clock-variable.xml

index 863377ca857325b2ed72331cfdfbc65d82021d3b..a382d30098aad1318f2a57957a4e8fad2e49b8f2 100644 (file)
           <dt><code>utc</code></dt>
           <dd>
             The guest clock will always be synchronized to UTC when
-            booted</dd>
+            booted.
+            <span class="since">Since 0.9.11</span> 'utc' mode can be converted
+            to 'variable' mode, which can be controlled by using the
+            <code>adjustment</code> attribute. If the value is 'reset', the
+            conversion is never done (not all hypervisors can
+            synchronize to UTC on each boot; use of 'reset' will cause
+            an error on those hypervisors). A numeric value
+            forces the conversion to 'variable' mode using the value as the
+            initial adjustment. The default <code>adjustment</code> is
+            hypervisor specific.
+          </dd>
           <dt><code>localtime</code></dt>
           <dd>
             The guest clock will be synchronized to the host's configured
             timezone when booted, if any.
+            <span class="since">Since 0.9.11,</span> the <code>adjustment</code>
+            attribute behaves the same as in 'utc' mode.
           </dd>
           <dt><code>timezone</code></dt>
           <dd>
           <dt><code>variable</code></dt>
           <dd>
             The guest clock will have an arbitrary offset applied
-            relative to UTC. The delta relative to UTC is specified
+            relative to UTC or localtime, depending on the <code>basis</code>
+            attribute. The delta relative to UTC (or localtime) is specified
             in seconds, using the <code>adjustment</code> attribute.
             The guest is free to adjust the RTC over time and expect
-            that it will be honoured at next reboot. This is in
-            contrast to 'utc' mode, where the RTC adjustments are
+            that it will be honored at next reboot. This is in
+            contrast to 'utc' and 'localtime' mode (with the optional
+            attribute adjustment='reset'), where the RTC adjustments are
             lost at each reboot. <span class="since">Since 0.7.7</span>
+            <span class="since">Since 0.9.11</span> the <code>basis</code>
+            attribute can be either 'utc' (default) or 'localtime'.
           </dd>
         </dl>
         <p>
index 5ed47aca63524616321cd52370e1e1dd6a9b7f54..0cc04af5da894508a06d75a0787608a844d9e108 100644 (file)
     <optional>
       <element name="clock">
         <choice>
-          <attribute name="offset">
-            <value>localtime</value>
-          </attribute>
-          <attribute name="offset">
-            <value>utc</value>
-          </attribute>
+          <group>
+            <attribute name="offset">
+              <choice>
+                <value>localtime</value>
+                <value>utc</value>
+              </choice>
+            </attribute>
+            <optional>
+              <attribute name='adjustment'>
+                <choice>
+                  <ref name='timeDelta'/>
+                  <value>reset</value>
+                </choice>
+              </attribute>
+            </optional>
+          </group>
           <group>
             <attribute name="offset">
               <value>timezone</value>
                 <ref name="timeDelta"/>
               </attribute>
             </optional>
+            <optional>
+              <attribute name="basis">
+                <choice>
+                  <value>utc</value>
+                  <value>localtime</value>
+                </choice>
+              </attribute>
+            </optional>
           </group>
         </choice>
         <zeroOrMore>
index c800160441cbda608f14b5a4fd3489e73c60b5be..cca757d6078a38e4a46a5d295f71e135e3dc2acd 100644 (file)
@@ -590,6 +590,10 @@ VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
               "variable",
               "timezone");
 
+VIR_ENUM_IMPL(virDomainClockBasis, VIR_DOMAIN_CLOCK_BASIS_LAST,
+              "utc",
+              "localtime");
+
 VIR_ENUM_IMPL(virDomainTimerName, VIR_DOMAIN_TIMER_NAME_LAST,
               "platform",
               "pit",
@@ -8069,10 +8073,53 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
         def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
     }
     switch (def->clock.offset) {
+    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
+    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
+        tmp = virXPathString("string(./clock/@adjustment)", ctxt);
+        if (tmp) {
+            if (STREQ(tmp, "reset")) {
+                def->clock.data.utc_reset = true;
+            } else {
+                char *conv = NULL;
+                unsigned long long val;
+                val = strtoll(tmp, &conv, 10);
+                if (conv == tmp || *conv != '\0') {
+                    virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                         _("unknown clock adjustment '%s'"), tmp);
+                    goto error;
+                }
+                switch (def->clock.offset) {
+                case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
+                    def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_LOCALTIME;
+                    break;
+                case VIR_DOMAIN_CLOCK_OFFSET_UTC:
+                    def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
+                    break;
+                }
+                def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_VARIABLE;
+                def->clock.data.variable.adjustment = val;
+            }
+            VIR_FREE(tmp);
+        } else {
+            def->clock.data.utc_reset = false;
+        }
+        break;
+
     case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
         if (virXPathLongLong("number(./clock/@adjustment)", ctxt,
-                             &def->clock.data.adjustment) < 0)
-            def->clock.data.adjustment = 0;
+                             &def->clock.data.variable.adjustment) < 0)
+            def->clock.data.variable.adjustment = 0;
+        tmp = virXPathString("string(./clock/@basis)", ctxt);
+        if (tmp) {
+            if ((def->clock.data.variable.basis = virDomainClockBasisTypeFromString(tmp)) < 0) {
+                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                     _("unknown clock basis '%s'"), tmp);
+                goto error;
+            }
+            VIR_FREE(tmp);
+        } else {
+            def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
+        }
         break;
 
     case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
@@ -12521,9 +12568,15 @@ virDomainDefFormatInternal(virDomainDefPtr def,
     virBufferAsprintf(buf, "  <clock offset='%s'",
                       virDomainClockOffsetTypeToString(def->clock.offset));
     switch (def->clock.offset) {
+    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
+    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
+        if (def->clock.data.utc_reset)
+            virBufferAddLit(buf, " adjustment='reset'");
+        break;
     case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
-        virBufferAsprintf(buf, " adjustment='%lld'",
-                          def->clock.data.adjustment);
+        virBufferAsprintf(buf, " adjustment='%lld' basis='%s'",
+                          def->clock.data.variable.adjustment,
+                          virDomainClockBasisTypeToString(def->clock.data.variable.basis));
         break;
     case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
         virBufferEscapeString(buf, " timezone='%s'", def->clock.data.timezone);
index 3fcb02644c8e581677f02542d776dfb64c6a88a4..0eed60e02a93fce961e587ae4acc0af5a1538e06 100644 (file)
@@ -1446,15 +1446,27 @@ enum virDomainClockOffsetType {
     VIR_DOMAIN_CLOCK_OFFSET_LAST,
 };
 
+enum virDomainClockBasis {
+    VIR_DOMAIN_CLOCK_BASIS_UTC = 0,
+    VIR_DOMAIN_CLOCK_BASIS_LOCALTIME = 1,
+
+    VIR_DOMAIN_CLOCK_BASIS_LAST,
+};
+
 typedef struct _virDomainClockDef virDomainClockDef;
 typedef virDomainClockDef *virDomainClockDefPtr;
 struct _virDomainClockDef {
     int offset;
 
     union {
-        /* Adjustment in seconds, relative to UTC, when
+        /* Bug-compatibility-mode for Xen utc|localtime */
+        int utc_reset;
+        /* Adjustment in seconds, relative to UTC or LOCALTIME, when
          * offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE */
-        long long adjustment;
+        struct {
+            long long adjustment;
+            int basis;
+        } variable;
 
         /* Timezone name, when
          * offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME */
@@ -2176,6 +2188,7 @@ int virDomainStateReasonFromString(virDomainState state, const char *reason);
 
 VIR_ENUM_DECL(virDomainSeclabel)
 VIR_ENUM_DECL(virDomainClockOffset)
+VIR_ENUM_DECL(virDomainClockBasis)
 
 VIR_ENUM_DECL(virDomainTimerName)
 VIR_ENUM_DECL(virDomainTimerTrack)
index 97fec2fcf463cc01b1ee50da7a1122a101e5b1f4..a90f8a0fa22126e6bb6334d15b22e4d8e1fd2a29 100644 (file)
@@ -255,6 +255,7 @@ virDomainChrTcpProtocolTypeFromString;
 virDomainChrTcpProtocolTypeToString;
 virDomainChrTypeFromString;
 virDomainChrTypeToString;
+virDomainClockBasisTypeToString;
 virDomainClockOffsetTypeFromString;
 virDomainClockOffsetTypeToString;
 virDomainConfigFile;
index cfd5d756cb7b9419b6e1eb86543b6b06347265ff..ea9431fa311cc59d9249eef94eacc9ad7ba9c89a 100644 (file)
@@ -3563,7 +3563,13 @@ qemuBuildClockArgStr(virDomainClockDefPtr def)
         time_t now = time(NULL);
         struct tm nowbits;
 
-        now += def->data.adjustment;
+        if (def->data.variable.basis != VIR_DOMAIN_CLOCK_BASIS_UTC) {
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                            _("unsupported clock basis '%s'"),
+                            virDomainClockBasisTypeToString(def->data.variable.basis));
+            goto error;
+        }
+        now += def->data.variable.adjustment;
         gmtime_r(&now, &nowbits);
 
         virBufferAsprintf(&buf, "base=%d-%02d-%02dT%02d:%02d:%02d",
index 0667a03924951083152823dbbb46c5f540c3c18e..91f1c5b095db6d06b76cad678d0eb5973d2cb42e 100644 (file)
@@ -738,7 +738,7 @@ qemuProcessHandleRTCChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     event = virDomainEventRTCChangeNewFromObj(vm, offset);
 
     if (vm->def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE)
-        vm->def->clock.data.adjustment = offset;
+        vm->def->clock.data.variable.adjustment = offset;
 
     if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
         VIR_WARN("unable to save domain status with RTC change");
index 97c0aedb4505cc13d96c7744a9efef04d62d51ce..73103bbb3a0e41f3173196ad1528b6d0180c6aa4 100644 (file)
@@ -8,7 +8,7 @@
     <type arch='i686' machine='pc'>hvm</type>
     <boot dev='hd'/>
   </os>
-  <clock offset='variable' adjustment='123456'/>
+  <clock offset='variable' adjustment='123456' basis='utc'/>
   <on_poweroff>destroy</on_poweroff>
   <on_reboot>restart</on_reboot>
   <on_crash>destroy</on_crash>