diff options
author | Paul Mackerras <paulus@samba.org> | 2005-10-30 06:55:52 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2005-10-30 06:55:52 -0500 |
commit | 5f6b5b973a125de0dbe236ce659a495787c81ff0 (patch) | |
tree | 49286d23fff0b829e2c93831925eadceeeb6cd7a /arch/powerpc/kernel/time.c | |
parent | eb66ce6333742e32825f0294310ff53e284fa828 (diff) |
powerpc: Fix time setting bug on 32-bit
This fixes a bug where settimeofday would set the wrong parameters
in do_gtod, resulting in gettimeofday returning a value about 4
hours after the correct time. The bug was that we divided a
negative 64-bit value with do_div, which treated it as unsigned
and gave us a result that was approximately 1.8e10 too large
(since the divisor was 1e9).
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/time.c')
-rw-r--r-- | arch/powerpc/kernel/time.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 9f264c2f02c3..ed5c38fb146c 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -518,7 +518,7 @@ int do_settimeofday(struct timespec *tv) | |||
518 | long wtm_nsec, new_nsec = tv->tv_nsec; | 518 | long wtm_nsec, new_nsec = tv->tv_nsec; |
519 | unsigned long flags; | 519 | unsigned long flags; |
520 | long int tb_delta; | 520 | long int tb_delta; |
521 | u64 new_xsec; | 521 | u64 new_xsec, tb_delta_xs; |
522 | 522 | ||
523 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | 523 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) |
524 | return -EINVAL; | 524 | return -EINVAL; |
@@ -541,8 +541,7 @@ int do_settimeofday(struct timespec *tv) | |||
541 | #endif | 541 | #endif |
542 | tb_delta = tb_ticks_since(tb_last_stamp); | 542 | tb_delta = tb_ticks_since(tb_last_stamp); |
543 | tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; | 543 | tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; |
544 | 544 | tb_delta_xs = mulhdu(tb_delta, do_gtod.varp->tb_to_xs); | |
545 | new_nsec -= 1000 * mulhwu(tb_to_us, tb_delta); | ||
546 | 545 | ||
547 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec); | 546 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec); |
548 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec); | 547 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec); |
@@ -557,9 +556,12 @@ int do_settimeofday(struct timespec *tv) | |||
557 | 556 | ||
558 | ntp_clear(); | 557 | ntp_clear(); |
559 | 558 | ||
560 | new_xsec = (u64)new_nsec * XSEC_PER_SEC; | 559 | new_xsec = 0; |
561 | do_div(new_xsec, NSEC_PER_SEC); | 560 | if (new_nsec != 0) { |
562 | new_xsec += (u64)new_sec * XSEC_PER_SEC; | 561 | new_xsec = (u64)new_nsec * XSEC_PER_SEC; |
562 | do_div(new_xsec, NSEC_PER_SEC); | ||
563 | } | ||
564 | new_xsec += (u64)new_sec * XSEC_PER_SEC - tb_delta_xs; | ||
563 | update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs); | 565 | update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs); |
564 | 566 | ||
565 | #ifdef CONFIG_PPC64 | 567 | #ifdef CONFIG_PPC64 |