mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-08 04:31:33 +00:00
Support clock=variable relative to localtime
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>
This commit is contained in:
parent
867ed7bb9e
commit
b8bf79aad7
@ -985,11 +985,23 @@
|
||||
<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>
|
||||
@ -1000,12 +1012,16 @@
|
||||
<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>
|
||||
|
@ -582,12 +582,22 @@
|
||||
<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>
|
||||
@ -607,6 +617,14 @@
|
||||
<ref name="timeDelta"/>
|
||||
</attribute>
|
||||
</optional>
|
||||
<optional>
|
||||
<attribute name="basis">
|
||||
<choice>
|
||||
<value>utc</value>
|
||||
<value>localtime</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</group>
|
||||
</choice>
|
||||
<zeroOrMore>
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -255,6 +255,7 @@ virDomainChrTcpProtocolTypeFromString;
|
||||
virDomainChrTcpProtocolTypeToString;
|
||||
virDomainChrTypeFromString;
|
||||
virDomainChrTypeToString;
|
||||
virDomainClockBasisTypeToString;
|
||||
virDomainClockOffsetTypeFromString;
|
||||
virDomainClockOffsetTypeToString;
|
||||
virDomainConfigFile;
|
||||
|
@ -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",
|
||||
|
@ -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");
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user