<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>
<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>
"variable",
"timezone");
+VIR_ENUM_IMPL(virDomainClockBasis, VIR_DOMAIN_CLOCK_BASIS_LAST,
+ "utc",
+ "localtime");
+
VIR_ENUM_IMPL(virDomainTimerName, VIR_DOMAIN_TIMER_NAME_LAST,
"platform",
"pit",
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:
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);
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 */
VIR_ENUM_DECL(virDomainSeclabel)
VIR_ENUM_DECL(virDomainClockOffset)
+VIR_ENUM_DECL(virDomainClockBasis)
VIR_ENUM_DECL(virDomainTimerName)
VIR_ENUM_DECL(virDomainTimerTrack)
virDomainChrTcpProtocolTypeToString;
virDomainChrTypeFromString;
virDomainChrTypeToString;
+virDomainClockBasisTypeToString;
virDomainClockOffsetTypeFromString;
virDomainClockOffsetTypeToString;
virDomainConfigFile;
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",
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");
<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>