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

[Xen-devel] [PATCH] Have xen dom0 still handle time of 1970



It's come to our attention, that the time gets screwed up when set between EPOCH and EPOCH + uptime. This may not seem important (because we don't live in the 70s anymore) but it makes LTP fail. LTP has a date test that checks what happens when set to EPOCH + 100 secs + 100 nsecs, and makes sure that it gets a proper result.

The following patches helps xen handle the case where time is set back to Jan 1st 1970 (or anytime from EPOCH to EPOCH + uptime).

Here's what you get without the patch:

# date -u 010100011970
Thu Jan  1 00:01:00 UTC 1970
# date
Mon Feb 22 16:42:30 EST 2010

Here's what you get with the patch:

# date -u 010100011970
Thu Jan  1 00:01:00 UTC 1970
# date
Wed Dec 31 19:01:01 EST 1969

-- Steve

Signed-off-by: Steven Rostedt <srostedt@xxxxxxxxxx>
diff -r fd2667419c53 linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c
--- a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c  Tue Jan 16 14:04:12 
2007 -0500
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c  Wed Jan 17 10:34:06 
2007 -0500
@@ -260,7 +260,8 @@ static void __update_wallclock(time_t se
 {
        long wtm_nsec, xtime_nsec;
        time_t wtm_sec, xtime_sec;
-       u64 tmp, wc_nsec;
+       s64 tmp, wc_nsec;
+       int s;
 
        /* Adjust wall-clock time base based on wall_jiffies ticks. */
        wc_nsec = processed_system_time;
@@ -270,8 +271,17 @@ static void __update_wallclock(time_t se
 
        /* Split wallclock base into seconds and nanoseconds. */
        tmp = wc_nsec;
+       /*
+        * do_div does not like s64, and treats them as u64
+        * and we will not get the expected result.
+        * So for those with time machines, let 1970 work
+        * again!
+        */
+       s = tmp < 0 ? -1 : 1;
+       tmp *= s;
        xtime_nsec = do_div(tmp, 1000000000);
        xtime_sec  = (time_t)tmp;
+       xtime_sec *= s;
 
        wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - xtime_sec);
        wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - xtime_nsec);
@@ -289,7 +299,12 @@ static void update_wallclock(void)
        do {
                shadow_tv_version = s->wc_version;
                rmb();
-               shadow_tv.tv_sec  = s->wc_sec;
+               /*
+                * If someone decides to set the time to something
+                * before EPOCH + uptime, we can get a negative
+                * number here.
+                */
+               shadow_tv.tv_sec  = (s32)s->wc_sec;
                shadow_tv.tv_nsec = s->wc_nsec;
                rmb();
        } while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version));
diff -r fd2667419c53 xen/arch/x86/time.c
--- a/xen/arch/x86/time.c       Tue Jan 16 14:04:12 2007 -0500
+++ b/xen/arch/x86/time.c       Wed Jan 17 10:34:06 2007 -0500
@@ -708,12 +708,23 @@ void update_domain_wallclock_time(struct
 /* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */
 void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
 {
-    u64 x;
+    s64 x;
     u32 y, _wc_sec, _wc_nsec;
     struct domain *d;
+    int s;
 
     x = (secs * 1000000000ULL) + (u64)nsecs - system_time_base;
+    s = x < 0 ? -1 : 1;
+    /*
+     * do_div does not like negative s64 numbers and treats them
+     * as u64, thus the result is unexpected if the s64 is
+     * negative. For those that still live in the 70s, and
+     * want their Xen boxes to do the same, we must handle the
+     * negative case.
+     */
+    x *= s;
     y = do_div(x, 1000000000);
+    x *= s;
 
     spin_lock(&wc_lock);
     wc_sec  = _wc_sec  = (u32)x;
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.