Add new clock mode allowing variable adjustments

This introduces a third option for clock offset synchronization,
that allows an arbitrary / variable adjustment to be set. In
essence the XML contains the time delta in seconds, relative to
UTC.

  <clock offset='variable' adjustment='123465'/>

The difference from 'utc' mode, is that management apps should
track adjustments and preserve them at next reboot.

* docs/schemas/domain.rng: Schema for new clock mode
* src/conf/domain_conf.c, src/conf/domain_conf.h: Parse
  new clock time delta
* src/libvirt_private.syms, src/util/xml.c, src/util/xml.h: Add
  virXPathLongLong() method
This commit is contained in:
Daniel P. Berrange 2010-02-02 17:49:09 +00:00
parent eed2f8c3a9
commit b9e2967a5e
6 changed files with 101 additions and 7 deletions

View File

@ -297,12 +297,24 @@
<define name="clock">
<optional>
<element name="clock">
<attribute name="offset">
<choice>
<choice>
<attribute name="offset">
<value>localtime</value>
</attribute>
<attribute name="offset">
<value>utc</value>
</choice>
</attribute>
</attribute>
<group>
<attribute name="offset">
<value>variable</value>
</attribute>
<optional>
<attribute name="adjustment">
<ref name="timeDelta"/>
</attribute>
</optional>
</group>
</choice>
<empty/>
</element>
</optional>
@ -1616,4 +1628,9 @@
<param name='pattern'>[a-zA-Z0-9\-_]+</param>
</data>
</define>
<define name="timeDelta">
<data type="string">
<param name="pattern">(-|\+)?[0-9]+</param>
</data>
</define>
</grammar>

View File

@ -234,7 +234,8 @@ VIR_ENUM_IMPL(virDomainNetdevMacvtap, VIR_DOMAIN_NETDEV_MACVTAP_MODE_LAST,
VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
"utc",
"localtime");
"localtime",
"variable");
#define virDomainReportError(code, fmt...) \
virReportErrorHelper(NULL, VIR_FROM_DOMAIN, code, __FILE__, \
@ -3580,6 +3581,13 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
} else {
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
}
switch (def->clock.offset) {
case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
if (virXPathLongLong("number(./clock/@adjustment)", ctxt,
&def->clock.adjustment) < 0)
def->clock.adjustment = 0;
break;
}
def->os.bootloader = virXPathString("string(./bootloader)", ctxt);
def->os.bootloaderArgs = virXPathString("string(./bootloader_args)", ctxt);
@ -5535,8 +5543,14 @@ char *virDomainDefFormat(virDomainDefPtr def,
if (virCPUDefFormatBuf(&buf, def->cpu, " ", 0) < 0)
goto cleanup;
virBufferVSprintf(&buf, " <clock offset='%s'/>\n",
virBufferVSprintf(&buf, " <clock offset='%s'",
virDomainClockOffsetTypeToString(def->clock.offset));
switch (def->clock.offset) {
case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
virBufferVSprintf(&buf, " adjustment='%lld'", def->clock.adjustment);
break;
}
virBufferAddLit(&buf, "/>\n");
if (virDomainLifecycleDefFormat(&buf, def->onPoweroff,
"on_poweroff") < 0)

View File

@ -634,6 +634,7 @@ struct _virSecurityLabelDef {
enum virDomainClockOffsetType {
VIR_DOMAIN_CLOCK_OFFSET_UTC = 0,
VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME = 1,
VIR_DOMAIN_CLOCK_OFFSET_VARIABLE = 2,
VIR_DOMAIN_CLOCK_OFFSET_LAST,
};
@ -642,6 +643,10 @@ typedef struct _virDomainClockDef virDomainClockDef;
typedef virDomainClockDef *virDomainClockDefPtr;
struct _virDomainClockDef {
int offset;
/* Adjustment in seconds, relative to UTC, when
* offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE */
long long adjustment;
};
#define VIR_DOMAIN_CPUMASK_LEN 1024

View File

@ -629,6 +629,7 @@ virXPathStringLimit;
virXPathBoolean;
virXPathNumber;
virXPathULong;
virXPathLongLong;
virXPathULongLong;
virXPathLongHex;
virXPathULongHex;

View File

@ -364,6 +364,60 @@ virXPathULongLong(const char *xpath,
return (ret);
}
/**
* virXPathULongLong:
* @xpath: the XPath string to evaluate
* @ctxt: an XPath context
* @value: the returned long long value
*
* Convenience function to evaluate an XPath number
*
* Returns 0 in case of success in which case @value is set,
* or -1 if the XPath evaluation failed or -2 if the
* value doesn't have a long format.
*/
int
virXPathLongLong(const char *xpath,
xmlXPathContextPtr ctxt,
long long *value)
{
xmlXPathObjectPtr obj;
xmlNodePtr relnode;
int ret = 0;
if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
virXMLError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Invalid parameter to virXPathLongLong()"));
return (-1);
}
relnode = ctxt->node;
obj = xmlXPathEval(BAD_CAST xpath, ctxt);
ctxt->node = relnode;
if ((obj != NULL) && (obj->type == XPATH_STRING) &&
(obj->stringval != NULL) && (obj->stringval[0] != 0)) {
char *conv = NULL;
unsigned long long val;
val = strtoll((const char *) obj->stringval, &conv, 10);
if (conv == (const char *) obj->stringval) {
ret = -2;
} else {
*value = val;
}
} else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
(!(isnan(obj->floatval)))) {
*value = (long long) obj->floatval;
if (*value != obj->floatval) {
ret = -2;
}
} else {
ret = -1;
}
xmlXPathFreeObject(obj);
return (ret);
}
char *
virXMLPropString(xmlNodePtr node,
const char *name)

View File

@ -30,7 +30,10 @@ int virXPathULong(const char *xpath,
int virXPathULongLong(const char *xpath,
xmlXPathContextPtr ctxt,
unsigned long long *value);
int virXPathLongHex(const char *xpath,
int virXPathLongLong(const char *xpath,
xmlXPathContextPtr ctxt,
long long *value);
int virXPathLongHex (const char *xpath,
xmlXPathContextPtr ctxt,
long *value);
int virXPathULongHex(const char *xpath,