[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH] Xen: Fix <clock> handling



For PV, Xen implements the <clock offset='utc'> and <clock
offset='localtime'> behaviour, while for HV it implements <clock
offset='variable'>.
This difference is important for domUs, which switch daylight saving on
there own, since the state is kept inside the VM and must be in sync
with the RTC provided by Xen.

For backward compatibility with previous versions of libvirt Xen-HV
still accepts 'utc' and 'localtime', but they are converted to
'variable' on the next read-back from Xend to libvirt, since this is
what Xen implements: The RTC is NOT reset back to the specified time on
next restart, but the previous offset is re-used.
Xen-HV also supports rtc_timeoffset relative to localtime=1, but
currently there is no mapping to libvirts <clock> syntax; such a
configuration will return an error.

Signed-off-by: Philipp Hahn <hahn univention de>
---
 src/xenxs/xen_sxpr.c |   85 ++++++++++++++++++++++++++++----------------------
 src/xenxs/xen_xm.c   |   70 +++++++++++++++++++++++++++--------------
 2 files changed, 94 insertions(+), 61 deletions(-)

diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c
index ac15853..19679fd 100644
--- a/src/xenxs/xen_sxpr.c
+++ b/src/xenxs/xen_sxpr.c
@@ -1247,7 +1247,6 @@ xenParseSxpr(const struct sexpr *root,
     } else
         def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;
 
-    def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
     if (hvm) {
         if (sexpr_int(root, "domain/image/hvm/acpi"))
             def->features |= (1 << VIR_DOMAIN_FEATURE_ACPI);
@@ -1260,9 +1259,13 @@ xenParseSxpr(const struct sexpr *root,
         if (sexpr_int(root, "domain/image/hvm/viridian"))
             def->features |= (1 << VIR_DOMAIN_FEATURE_VIRIDIAN);
 
-        /* Old XenD only allows localtime here for HVM */
-        if (sexpr_int(root, "domain/image/hvm/localtime"))
-            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
+        def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_VARIABLE;
+        def->clock.data.adjustment = sexpr_int(root, "domain/image/hvm/rtc_timeoffset");
+        if (def->clock.data.adjustment && sexpr_int(root, "domain/image/hvm/localtime")) {
+            XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
+                         "%s", _("domain information incompatible: localtime=1 while rtc_timeoffset!=0"));
+            goto error;
+        }
 
         if (sexpr_lookup(root, "domain/image/hvm/hpet")) {
             virDomainTimerDefPtr timer;
@@ -1280,10 +1283,12 @@ xenParseSxpr(const struct sexpr *root,
             def->clock.ntimers = 1;
             def->clock.timers[0] = timer;
         }
-    } else { /* !hvm */
+    } else {
         if (sexpr_int(root, "domain/image/linux/localtime"))
             def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
-    }
+        else
+            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
+    } /* !hvm */
 
     /* Current XenD allows localtime here, for PV and HVM */
     if (sexpr_int(root, "domain/localtime"))
@@ -2196,6 +2201,7 @@ xenFormatSxpr(virConnectPtr conn,
     const char *tmp;
     char *bufout;
     int hvm = 0, i;
+    int vmlocaltime = 0, rtc_timeoffset = 0;
 
     VIR_DEBUG("Formatting domain sexpr");
 
@@ -2255,31 +2261,15 @@ xenFormatSxpr(virConnectPtr conn,
     }
     virBufferAsprintf(&buf, "(on_crash '%s')", tmp);
 
-    /* Set localtime here for current XenD (both PV & HVM) */
-    if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME) {
-        if (def->clock.data.timezone) {
-            XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
-                         "%s", _("configurable timezones are not supported"));
-            goto error;
-        }
+    if (STREQ(def->os.type, "hvm"))
+        hvm = 1;
 
-        virBufferAddLit(&buf, "(localtime 1)");
-    } else if (def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_UTC) {
-        XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
-                     _("unsupported clock offset '%s'"),
-                     virDomainClockOffsetTypeToString(def->clock.offset));
-        goto error;
-    }
+    if (hvm)
+        virBufferAddLit(&buf, "(image (hvm ");
+    else
+        virBufferAddLit(&buf, "(image (linux ");
 
     if (!def->os.bootloader) {
-        if (STREQ(def->os.type, "hvm"))
-            hvm = 1;
-
-        if (hvm)
-            virBufferAddLit(&buf, "(image (hvm ");
-        else
-            virBufferAddLit(&buf, "(image (linux ");
-
         if (hvm &&
             def->os.loader == NULL) {
             XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
@@ -2424,17 +2414,13 @@ xenFormatSxpr(virConnectPtr conn,
                 virBufferAddLit(&buf, "(serial none)");
             }
 
-            /* Set localtime here to keep old XenD happy for HVM */
-            if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME)
-                virBufferAddLit(&buf, "(localtime 1)");
-
             if (def->sounds) {
                 virBufferAddLit(&buf, "(soundhw '");
                 if (xenFormatSxprSound(def, &buf) < 0)
                     goto error;
                 virBufferAddLit(&buf, "')");
             }
-        }
+        } /* hvm */
 
         /* get the device emulation model */
         if (def->emulator && (hvm || xendConfigVersion >= 3))
@@ -2458,15 +2444,40 @@ xenFormatSxpr(virConnectPtr conn,
                                          &buf, xendConfigVersion) < 0)
                 goto error;
         }
-
-        virBufferAddLit(&buf, "))");
     } else {
         /* PV domains accept kernel cmdline args */
         if (def->os.cmdline) {
-            virBufferEscapeSexpr(&buf, "(image (linux (args '%s')))",
-                                 def->os.cmdline);
+            virBufferEscapeSexpr(&buf, "(args '%s')", def->os.cmdline);
+        }
+    } /* os.bootloader */
+
+    /*
+     * PV: UTC and LOCALTIME.
+     * HV: VARIABLE + simulated UTC and LOCALTIME for backward compatibility.
+     */
+    switch (def->clock.offset) {
+    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
+        vmlocaltime = 1;
+        break;
+    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
+        break;
+    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
+        if (hvm) {
+            rtc_timeoffset = def->clock.data.adjustment;
+            break;
         }
+        /* fall through */
+    default:
+        XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
+                    _("unsupported clock offset '%s'"),
+                    virDomainClockOffsetTypeToString(def->clock.offset));
+        goto error;
     }
+    virBufferAsprintf(&buf, "(localtime %d)", vmlocaltime);
+    if (hvm)
+        virBufferAsprintf(&buf, "(rtc_timeoffset %d)", rtc_timeoffset);
+
+    virBufferAddLit(&buf, "))"); /* closes (image(hvm|linux */
 
     for (i = 0 ; i < def->ndisks ; i++)
         if (xenFormatSxprDisk(def->disks[i],
diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c
index 0aa04f3..022bcb8 100644
--- a/src/xenxs/xen_xm.c
+++ b/src/xenxs/xen_xm.c
@@ -414,9 +414,22 @@ xenParseXM(virConfPtr conf, int xendConfigVersion,
     if (xenXMConfigGetBool(conf, "localtime", &vmlocaltime, 0) < 0)
         goto cleanup;
 
-    def->clock.offset = vmlocaltime ?
-        VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME :
-        VIR_DOMAIN_CLOCK_OFFSET_UTC;
+    if (hvm) {
+        unsigned long rtc_timeoffset;
+        if (xenXMConfigGetULong(conf, "rtc_timeoffset", &rtc_timeoffset, 0) < 0)
+            goto cleanup;
+        def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_VARIABLE;
+        def->clock.data.adjustment = (int)rtc_timeoffset;
+        if (vmlocaltime) {
+            XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
+                        "%s", _("domain information incompatible: localtime=1 while rtc_timeoffset!=0"));
+            goto cleanup;
+        }
+    } else {
+        def->clock.offset = vmlocaltime ?
+            VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME :
+            VIR_DOMAIN_CLOCK_OFFSET_UTC;
+    } /* !hvm */
 
     if (xenXMConfigCopyStringOpt(conf, "device_model", &def->emulator) < 0)
         goto cleanup;
@@ -1456,6 +1469,7 @@ virConfPtr xenFormatXM(virConnectPtr conn,
     char uuid[VIR_UUID_STRING_BUFLEN];
     virConfValuePtr diskVal = NULL;
     virConfValuePtr netVal = NULL;
+    int vmlocaltime = 0, rtc_timeoffset = 0;
 
     if (!(conf = virConfNew()))
         goto cleanup;
@@ -1557,26 +1571,6 @@ virConfPtr xenFormatXM(virConnectPtr conn,
                 goto no_memory;
         }
 
-        if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME) {
-            if (def->clock.data.timezone) {
-                XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
-                           "%s", _("configurable timezones are not supported"));
-                goto cleanup;
-            }
-
-            if (xenXMConfigSetInt(conf, "localtime", 1) < 0)
-                goto no_memory;
-        } else if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_UTC) {
-            if (xenXMConfigSetInt(conf, "localtime", 0) < 0)
-                goto no_memory;
-        } else {
-            /* XXX We could support Xen's rtc clock offset */
-            XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("unsupported clock offset '%s'"),
-                       virDomainClockOffsetTypeToString(def->clock.offset));
-            goto cleanup;
-        }
-
         for (i = 0; i < def->clock.ntimers; i++) {
             if (def->clock.timers[i]->name == VIR_DOMAIN_TIMER_NAME_HPET &&
                 def->clock.timers[i]->present != -1 &&
@@ -1615,7 +1609,35 @@ virConfPtr xenFormatXM(virConnectPtr conn,
         if (def->os.cmdline &&
             xenXMConfigSetString(conf, "extra", def->os.cmdline) < 0)
             goto no_memory;
-
+    } /* !hvm */
+
+    /*
+     * PV: UTC and LOCALTIME.
+     * HV: VARIABLE + simulated UTC and LOCALTIME for backward compatibility.
+     */
+    switch (def->clock.offset) {
+    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
+        vmlocaltime = 1;
+        break;
+    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
+        break;
+    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
+        if (hvm) {
+            rtc_timeoffset = def->clock.data.adjustment;
+            break;
+        }
+        /* fall through */
+    default:
+        XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
+                    _("unsupported clock offset '%s'"),
+                    virDomainClockOffsetTypeToString(def->clock.offset));
+        goto cleanup;
+    }
+    if (xenXMConfigSetInt(conf, "localtime", vmlocaltime) < 0)
+        goto no_memory;
+    if (hvm) {
+        if (xenXMConfigSetInt(conf, "rtc_timeoffset", rtc_timeoffset) < 0)
+            goto no_memory;
     }
 
     if (!(lifecycle = virDomainLifecycleTypeToString(def->onPoweroff))) {
-- 
1.7.1


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]