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 to specify, if the offset is
relative to 'localtime' or 'utc'.
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(a)univention.de>
---
docs/formatdomain.html.in | 7 ++++-
docs/schemas/domaincommon.rng | 8 ++++++
src/conf/domain_conf.c | 24 ++++++++++++++++---
src/conf/domain_conf.h | 15 ++++++++++-
src/libvirt_private.syms | 1 +
src/qemu/qemu_command.c | 8 +++++-
src/qemu/qemu_process.c | 2 +-
.../qemuxml2argv-clock-variable.xml | 2 +-
8 files changed, 56 insertions(+), 11 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 29497a0..a849774 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -935,12 +935,15 @@
<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
+ contrast to 'utc' and 'localtime' mode, where the RTC
adjustments are
lost at each reboot. <span class="since">Since
0.7.7</span>
+ The <code>basis</code> attribute can be either 'utc'
(default) or
+ 'localtime'. <span class="since">Since
0.9.10</span>
</dd>
</dl>
<p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 8111045..9735e7c 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -576,6 +576,14 @@
<ref name="timeDelta"/>
</attribute>
</optional>
+ <optional>
+ <attribute name="basis">
+ <choice>
+ <value>utc</value>
+ <value>localtime</value>
+ </choice>
+ </attribute>
+ </optional>
</group>
</choice>
<zeroOrMore>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index aa4b32d..38e3f36 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -575,6 +575,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",
@@ -7469,8 +7473,19 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
switch (def->clock.offset) {
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:
@@ -11831,8 +11846,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
virDomainClockOffsetTypeToString(def->clock.offset));
switch (def->clock.offset) {
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);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 0a2795d..54eb732 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1366,15 +1366,25 @@ 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
+ /* 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 */
@@ -2069,6 +2079,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)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d6ad36c..f850742 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -258,6 +258,7 @@ virDomainChrTcpProtocolTypeFromString;
virDomainChrTcpProtocolTypeToString;
virDomainChrTypeFromString;
virDomainChrTypeToString;
+virDomainClockBasisTypeToString;
virDomainClockOffsetTypeFromString;
virDomainClockOffsetTypeToString;
virDomainConfigFile;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 0e26df1..3f0c3c1 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3430,7 +3430,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",
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 2d92d66..2f6f068 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -734,7 +734,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");
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-clock-variable.xml
b/tests/qemuxml2argvdata/qemuxml2argv-clock-variable.xml
index 9f52cca..eadefac 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-clock-variable.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-clock-variable.xml
@@ -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>
--
1.7.1