* non-scalar ktime addition and subtraction broken
@ 2006-06-02 3:08 Jeff Dike
2006-06-02 6:54 ` Thomas Gleixner
0 siblings, 1 reply; 6+ messages in thread
From: Jeff Dike @ 2006-06-02 3:08 UTC (permalink / raw)
To: Thomas Gleixner, linux-kernel; +Cc: Christopher S. Aker, user-mode-linux-devel
The use of 64-bit additions and subtractions on something which is
nominally a struct containing 32-bit second and nanosecond field is
broken when a negative time is involved. When the structure is
treated as a 64-bit integer, the increment of the upper 32 bits that's
part of two's-complement subtraction is lost. This leaves the end
result off by one second.
This manifested itself with sleeps inside UML lasting about 1 second
shorter than expected.
The patch below is more a problem statement than a real fix. People
thought about performance, and I don't know what this does to that
work.
I'm not sure why the hrtimer.c part is needed - I had done that before
tracking down the ktime_add problem. I see short sleeps without it,
so it is needed somehow.
The ktime_sub piece was done for completeness - UML compiles and boots
with no apparent ill effects, but it's otherwise untested.
As an aside, I fail to see how it can be correct for ktime_sub to add
NSEC_PER_SEC to something without compensating somewhere else for it.
Andrew - please don't drop this into -mm without an OK from Thomas or
someone else who's familiar with this code :-)
Jeff
Index: linux-2.6.17-mm/include/linux/ktime.h
===================================================================
--- linux-2.6.17-mm.orig/include/linux/ktime.h 2006-06-01 22:15:44.000000000 -0400
+++ linux-2.6.17-mm/include/linux/ktime.h 2006-06-01 23:00:32.000000000 -0400
@@ -148,7 +148,8 @@ static inline ktime_t ktime_sub(const kt
{
ktime_t res;
- res.tv64 = lhs.tv64 - rhs.tv64;
+ res.tv.sec = lhs.tv.sec - rhs.tv.sec;
+ res.tv.nsec = lhs.tv.nsec - rhs.tv.nsec;
if (res.tv.nsec < 0)
res.tv.nsec += NSEC_PER_SEC;
@@ -167,7 +168,8 @@ static inline ktime_t ktime_add(const kt
{
ktime_t res;
- res.tv64 = add1.tv64 + add2.tv64;
+ res.tv.sec = add1.tv.sec + add2.tv.sec;
+ res.tv.nsec = add1.tv.nsec + add2.tv.nsec;
/*
* performance trick: the (u32) -NSEC gives 0x00000000Fxxxxxxx
* so we subtract NSEC_PER_SEC and add 1 to the upper 32 bit.
Index: linux-2.6.17-mm/kernel/hrtimer.c
===================================================================
--- linux-2.6.17-mm.orig/kernel/hrtimer.c 2006-06-01 22:15:44.000000000 -0400
+++ linux-2.6.17-mm/kernel/hrtimer.c 2006-06-01 22:57:24.000000000 -0400
@@ -627,7 +627,8 @@ static inline void run_hrtimer_queue(str
int restart;
timer = rb_entry(node, struct hrtimer, node);
- if (base->softirq_time.tv64 <= timer->expires.tv64)
+ if(ktime_to_ns(base->softirq_time) <=
+ ktime_to_ns(timer->expires))
break;
fn = timer->function;
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: non-scalar ktime addition and subtraction broken
2006-06-02 3:08 non-scalar ktime addition and subtraction broken Jeff Dike
@ 2006-06-02 6:54 ` Thomas Gleixner
2006-06-02 15:19 ` [uml-devel] " Jeff Dike
0 siblings, 1 reply; 6+ messages in thread
From: Thomas Gleixner @ 2006-06-02 6:54 UTC (permalink / raw)
To: Jeff Dike; +Cc: linux-kernel, Christopher S. Aker, user-mode-linux-devel
On Thu, 2006-06-01 at 23:08 -0400, Jeff Dike wrote:
> The use of 64-bit additions and subtractions on something which is
> nominally a struct containing 32-bit second and nanosecond field is
> broken when a negative time is involved. When the structure is
> treated as a 64-bit integer, the increment of the upper 32 bits that's
> part of two's-complement subtraction is lost. This leaves the end
> result off by one second.
>
> This manifested itself with sleeps inside UML lasting about 1 second
> shorter than expected.
>
> The patch below is more a problem statement than a real fix. People
> thought about performance, and I don't know what this does to that
> work.
>
> I'm not sure why the hrtimer.c part is needed - I had done that before
> tracking down the ktime_add problem. I see short sleeps without it,
> so it is needed somehow.
>
> The ktime_sub piece was done for completeness - UML compiles and boots
> with no apparent ill effects, but it's otherwise untested.
>
> As an aside, I fail to see how it can be correct for ktime_sub to add
> NSEC_PER_SEC to something without compensating somewhere else for it.
>
> Andrew - please don't drop this into -mm without an OK from Thomas or
> someone else who's familiar with this code :-)
NAK. ktime_t is defined that ist must be normalized the same way as
timespecs. The nsec part must be >= 0 and < NSEC_PER_SEC. Fix the part
which is feeding non normalized values.
tglx
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [uml-devel] Re: non-scalar ktime addition and subtraction broken
2006-06-02 6:54 ` Thomas Gleixner
@ 2006-06-02 15:19 ` Jeff Dike
2006-06-02 18:28 ` [uml-devel] " Blaisorblade
0 siblings, 1 reply; 6+ messages in thread
From: Jeff Dike @ 2006-06-02 15:19 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: linux-kernel, Christopher S. Aker, user-mode-linux-devel
On Fri, Jun 02, 2006 at 08:54:22AM +0200, Thomas Gleixner wrote:
> NAK. ktime_t is defined that ist must be normalized the same way as
> timespecs. The nsec part must be >= 0 and < NSEC_PER_SEC. Fix the part
> which is feeding non normalized values.
Aha, that would be me, initializing wall_to_monotonic incorrectly. Thanks
for the clue.
Jeff
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [uml-devel] non-scalar ktime addition and subtraction broken
2006-06-02 15:19 ` [uml-devel] " Jeff Dike
@ 2006-06-02 18:28 ` Blaisorblade
2006-06-02 21:34 ` Jeff Dike
0 siblings, 1 reply; 6+ messages in thread
From: Blaisorblade @ 2006-06-02 18:28 UTC (permalink / raw)
To: user-mode-linux-devel
Cc: Jeff Dike, Thomas Gleixner, linux-kernel, Christopher S. Aker
[-- Attachment #1: Type: text/plain, Size: 1239 bytes --]
On Friday 02 June 2006 17:19, Jeff Dike wrote:
> On Fri, Jun 02, 2006 at 08:54:22AM +0200, Thomas Gleixner wrote:
> > NAK. ktime_t is defined that ist must be normalized the same way as
> > timespecs. The nsec part must be >= 0 and < NSEC_PER_SEC. Fix the part
> > which is feeding non normalized values.
>
> Aha, that would be me, initializing wall_to_monotonic incorrectly. Thanks
> for the clue.
Ok, since I now I'll never finish it:
$ ll old-patch-scripts/patches/uml-fix-timers.patch
-rw-r--r-- 1 paolo paolo 6763 2005-07-24 06:41
old-patch-scripts/patches/uml-fix-timers.patch
I'm attaching this incomplete patch. It won't apply (it was written likely
before 2.6.13 but surely after git was born), it likely introduces bugs and I
don't remember which ones, but it does point out some theoretical issues
about timekeeping (including this one):
+ set_normalized_timespec(&wall_to_monotonic, -now.tv_sec,
-now.tv_nsec);
(I likely was fighting against the loadavg >= 1.0 bug but I went looking for
every kind of things).
--
Inform me of my mistakes, so I can keep imitating Homer Simpson's "Doh!".
Paolo Giarrusso, aka Blaisorblade (Skype ID "PaoloGiarrusso", ICQ 215621894)
http://www.user-mode-linux.org/~blaisorblade
[-- Attachment #2: uml-fix-timers.patch --]
[-- Type: text/x-diff, Size: 6763 bytes --]
*) Rename timer() since it's a global and such a name is a "shooting offense".
Also, it's difficult to find the def with ctags currently, because people miss
fantasy.
*) do_timer must be called with xtime_lock held. I'm not sure
boot_timer_handler needs this, however I don't think it hurts: it simply
disables irq and takes a spinlock.
*) wall_to_monotonic must be normalized and have a posititive ts_nsec part,
see wall_to_monotonic definition and i386 usage in arch/i386/kernel/time.c.
Otherwise you can get negative tv_nsec results with
do_posix_clock_monotonic_gettime and its callers, including sys_timer_gettime.
*) Remove um_time() and um_stime() syscalls since they are identical to
system-wide ones.
*) Move clock_was_set() from do_gettimeofday to do_settimeofday. Not only from
the name you guess this is needed, but I indeed verified that for i386 it's in
arch/i386/kernel/time.c:do_settimeofday().
*) XXX: Probably do_settimeofday should be copied from i386 to replace the
current version.
*) XXX: do_[gs]ettimeofday() should use seqlocks like in i386, instead of
timer_lock() like they do. They also don't synchronize with the rest, beyond
the performance problems!
Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
---
linux-2.6.git-paolo/arch/um/include/time_user.h | 2
linux-2.6.git-paolo/arch/um/kernel/time.c | 13 ++---
linux-2.6.git-paolo/arch/um/kernel/time_kern.c | 42 ++++++-----------
linux-2.6.git-paolo/arch/um/sys-i386/sys_call_table.S | 2
linux-2.6.git-paolo/arch/um/sys-x86_64/syscall_table.c | 7 --
5 files changed, 23 insertions(+), 43 deletions(-)
diff -puN arch/um/kernel/time.c~uml-fix-timers arch/um/kernel/time.c
--- linux-2.6.git/arch/um/kernel/time.c~uml-fix-timers 2005-05-21 18:38:18.000000000 +0200
+++ linux-2.6.git-paolo/arch/um/kernel/time.c 2005-05-21 18:38:18.000000000 +0200
@@ -27,7 +27,7 @@ extern struct timeval xtime;
struct timeval local_offset = { 0, 0 };
-void timer(void)
+void userspace_timer(void)
{
gettimeofday(&xtime, NULL);
timeradd(&xtime, &local_offset, &xtime);
@@ -97,19 +97,16 @@ void uml_idle_timer(void)
set_interval(ITIMER_REAL);
}
-extern int do_posix_clock_monotonic_gettime(struct timespec *tp);
+extern void time_init_kern(void);
+/* This is called by init/main.c during early boot. */
void time_init(void)
{
- struct timespec now;
-
if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
panic("Couldn't set SIGVTALRM handler");
set_interval(ITIMER_VIRTUAL);
- do_posix_clock_monotonic_gettime(&now);
- wall_to_monotonic.tv_sec = -now.tv_sec;
- wall_to_monotonic.tv_nsec = -now.tv_nsec;
+ time_init_kern();
}
/* Declared in linux/time.h, which can't be included here */
@@ -123,7 +120,6 @@ void do_gettimeofday(struct timeval *tv)
gettimeofday(tv, NULL);
timeradd(tv, &local_offset, tv);
time_unlock(flags);
- clock_was_set();
}
int do_settimeofday(struct timespec *tv)
@@ -142,6 +138,7 @@ int do_settimeofday(struct timespec *tv)
gettimeofday(&now, NULL);
timersub(&tv_in, &now, &local_offset);
time_unlock(flags);
+ clock_was_set();
return(0);
}
diff -puN arch/um/kernel/time_kern.c~uml-fix-timers arch/um/kernel/time_kern.c
--- linux-2.6.git/arch/um/kernel/time_kern.c~uml-fix-timers 2005-05-21 18:38:18.000000000 +0200
+++ linux-2.6.git-paolo/arch/um/kernel/time_kern.c 2005-05-21 18:38:18.000000000 +0200
@@ -88,52 +88,40 @@ void timer_irq(union uml_pt_regs *regs)
}
}
+void time_init_kern(void)
+{
+ struct timespec now;
+
+ do_posix_clock_monotonic_gettime(&now);
+ set_normalized_timespec(&wall_to_monotonic, -now.tv_sec, -now.tv_nsec);
+}
+
+/* This is used during boot only, later it's replaced by
+ * user_time_init_{tt,skas} with alarm_handler, during timer_init() */
void boot_timer_handler(int sig)
{
+ unsigned long flags;
struct pt_regs regs;
CHOOSE_MODE((void)
(UPT_SC(®s.regs) = (struct sigcontext *) (&sig + 1)),
(void) (regs.regs.skas.is_user = 0));
+ write_seqlock_irqsave(&xtime_lock, flags);
do_timer(®s);
+ write_sequnlock_irqrestore(&xtime_lock, flags);
}
irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
{
unsigned long flags;
- do_timer(regs);
write_seqlock_irqsave(&xtime_lock, flags);
- timer();
+ do_timer(regs);
+ userspace_timer();
write_sequnlock_irqrestore(&xtime_lock, flags);
return(IRQ_HANDLED);
}
-long um_time(int __user *tloc)
-{
- struct timeval now;
-
- do_gettimeofday(&now);
- if (tloc) {
- if (put_user(now.tv_sec, tloc))
- now.tv_sec = -EFAULT;
- }
- return now.tv_sec;
-}
-
-long um_stime(int __user *tptr)
-{
- int value;
- struct timespec new;
-
- if (get_user(value, tptr))
- return -EFAULT;
- new.tv_sec = value;
- new.tv_nsec = 0;
- do_settimeofday(&new);
- return 0;
-}
-
void timer_handler(int sig, union uml_pt_regs *regs)
{
local_irq_disable();
diff -puN arch/um/include/time_user.h~uml-fix-timers arch/um/include/time_user.h
--- linux-2.6.git/arch/um/include/time_user.h~uml-fix-timers 2005-05-21 18:38:18.000000000 +0200
+++ linux-2.6.git-paolo/arch/um/include/time_user.h 2005-05-21 18:38:18.000000000 +0200
@@ -6,7 +6,7 @@
#ifndef __TIME_USER_H__
#define __TIME_USER_H__
-extern void timer(void);
+extern void userspace_timer(void);
extern void switch_timers(int to_real);
extern void set_interval(int timer_type);
extern void idle_sleep(int secs);
diff -puN arch/um/sys-i386/sys_call_table.S~uml-fix-timers arch/um/sys-i386/sys_call_table.S
--- linux-2.6.git/arch/um/sys-i386/sys_call_table.S~uml-fix-timers 2005-05-21 18:38:18.000000000 +0200
+++ linux-2.6.git-paolo/arch/um/sys-i386/sys_call_table.S 2005-05-21 18:38:18.000000000 +0200
@@ -7,8 +7,6 @@
#define sys_vm86old sys_ni_syscall
#define sys_vm86 sys_ni_syscall
-#define sys_stime um_stime
-#define sys_time um_time
#define old_mmap old_mmap_i386
#include "../../i386/kernel/syscall_table.S"
diff -puN arch/um/sys-x86_64/syscall_table.c~uml-fix-timers arch/um/sys-x86_64/syscall_table.c
--- linux-2.6.git/arch/um/sys-x86_64/syscall_table.c~uml-fix-timers 2005-05-21 18:38:18.000000000 +0200
+++ linux-2.6.git-paolo/arch/um/sys-x86_64/syscall_table.c 2005-05-21 18:38:18.000000000 +0200
@@ -20,11 +20,8 @@
/*#define sys_set_thread_area sys_ni_syscall
#define sys_get_thread_area sys_ni_syscall*/
-/* For __NR_time. The x86-64 name hopefully will change from sys_time64 to
- * sys_time (since the current situation is bogus). I've sent a patch to cleanup
- * this. Remove below the obsoleted line. */
-#define sys_time64 um_time
-#define sys_time um_time
+/*To remove when x86_64 fixes the syscall name.*/
+#define sys_time64 sys_time
/* On UML we call it this way ("old" means it's not mmap2) */
#define sys_mmap old_mmap
_
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [uml-devel] non-scalar ktime addition and subtraction broken
2006-06-02 18:28 ` [uml-devel] " Blaisorblade
@ 2006-06-02 21:34 ` Jeff Dike
2006-06-04 15:04 ` Blaisorblade
0 siblings, 1 reply; 6+ messages in thread
From: Jeff Dike @ 2006-06-02 21:34 UTC (permalink / raw)
To: Blaisorblade
Cc: user-mode-linux-devel, Thomas Gleixner, linux-kernel,
Christopher S. Aker
On Fri, Jun 02, 2006 at 08:28:37PM +0200, Blaisorblade wrote:
> Ok, since I now I'll never finish it:
> $ ll old-patch-scripts/patches/uml-fix-timers.patch
> -rw-r--r-- 1 paolo paolo 6763 2005-07-24 06:41
> old-patch-scripts/patches/uml-fix-timers.patch
>
> I'm attaching this incomplete patch. It won't apply (it was written likely
> before 2.6.13 but surely after git was born), it likely introduces bugs and I
> *) Rename timer() since it's a global and such a name is a "shooting
> offense". Also, it's difficult to find the def with ctags
> currently, because people miss fantasy.
This is now gone, replaced by get_time. I can rename that if you feel
it's objectionable.
> *) do_timer must be called with xtime_lock held. I'm not sure
> boot_timer_handler needs this, however I don't think it hurts: it simply
> disables irq and takes a spinlock.
Fixed.
> *) wall_to_monotonic must be normalized and have a posititive ts_nsec part,
> see wall_to_monotonic definition and i386 usage in arch/i386/kernel/time.c.
> Otherwise you can get negative tv_nsec results with
> do_posix_clock_monotonic_gettime and its callers, including
> sys_timer_gettime.
Bah, you almost completely diagnosed the bug. Fixed now.
> *) Remove um_time() and um_stime() syscalls since they are identical to
> system-wide ones.
Fixed. sys_time64 seems to be gone on x86_64, so I deleted it from
here as well.
> *) Move clock_was_set() from do_gettimeofday to do_settimeofday. Not
> only from the name you guess this is needed, but I indeed verified
> that for i386 it's in arch/i386/kernel/time.c:do_settimeofday().
I had already fixed this.
> *) XXX: Probably do_settimeofday should be copied from i386 to
> replace the current version.
>
> *) XXX: do_[gs]ettimeofday() should use seqlocks like in i386,
> instead of timer_lock() like they do. They also don't synchronize
> with the rest, beyond the performance problems!
You're probably right. These two are related, and I'm not sure what
to do with them offhand.
Jeff
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [uml-devel] non-scalar ktime addition and subtraction broken
2006-06-02 21:34 ` Jeff Dike
@ 2006-06-04 15:04 ` Blaisorblade
0 siblings, 0 replies; 6+ messages in thread
From: Blaisorblade @ 2006-06-04 15:04 UTC (permalink / raw)
To: user-mode-linux-devel
Cc: Jeff Dike, Thomas Gleixner, linux-kernel, Christopher S. Aker
On Friday 02 June 2006 23:34, Jeff Dike wrote:
> On Fri, Jun 02, 2006 at 08:28:37PM +0200, Blaisorblade wrote:
> > Ok, since I now I'll never finish it:
> > $ ll old-patch-scripts/patches/uml-fix-timers.patch
> > -rw-r--r-- 1 paolo paolo 6763 2005-07-24 06:41
> > old-patch-scripts/patches/uml-fix-timers.patch
> >
> > I'm attaching this incomplete patch. It won't apply (it was written
> > likely before 2.6.13 but surely after git was born), it likely introduces
> > bugs and I
> >
> > *) Rename timer() since it's a global and such a name is a "shooting
> > offense". Also, it's difficult to find the def with ctags
> > currently, because people miss fantasy.
>
> This is now gone, replaced by get_time. I can rename that if you feel
> it's objectionable.
I still see (around 2.6.17-rc3) timer() existing in the same place and with
the same definition - even if it now seems unused:
void timer(void)
{
gettimeofday(&xtime, NULL);
timeradd(&xtime, &local_offset, &xtime);
}
> > *) do_timer must be called with xtime_lock held. I'm not sure
> > boot_timer_handler needs this, however I don't think it hurts: it simply
> > disables irq and takes a spinlock.
>
> Fixed.
>
> > *) wall_to_monotonic must be normalized and have a posititive ts_nsec
> > part, see wall_to_monotonic definition and i386 usage in
> > arch/i386/kernel/time.c. Otherwise you can get negative tv_nsec results
> > with
> > do_posix_clock_monotonic_gettime and its callers, including
> > sys_timer_gettime.
>
> Bah, you almost completely diagnosed the bug. Fixed now.
Yep, however I didn't reproduce any misbehaviour at that time.
> > *) Remove um_time() and um_stime() syscalls since they are identical to
> > system-wide ones.
> Fixed. sys_time64 seems to be gone on x86_64, so I deleted it from
> here as well.
Yes, I deleted sys_time64 time ago, forgot to update
arch/um/sys-x86_64/syscall_table.c.
> > *) Move clock_was_set() from do_gettimeofday to do_settimeofday. Not
> > only from the name you guess this is needed, but I indeed verified
> > that for i386 it's in arch/i386/kernel/time.c:do_settimeofday().
> > *) XXX: Probably do_settimeofday should be copied from i386 to
> > replace the current version.
> >
> > *) XXX: do_[gs]ettimeofday() should use seqlocks like in i386,
> > instead of timer_lock() like they do. They also don't synchronize
> > with the rest, beyond the performance problems!
>
> You're probably right. These two are related, and I'm not sure what
> to do with them offhand.
And that's why I didn't send the patches then in first place - I wanted to
complete them (I have too many incomplete patches, and too little time to
finish them :-( ).
--
Inform me of my mistakes, so I can keep imitating Homer Simpson's "Doh!".
Paolo Giarrusso, aka Blaisorblade (Skype ID "PaoloGiarrusso", ICQ 215621894)
http://www.user-mode-linux.org/~blaisorblade
Chiacchiera con i tuoi amici in tempo reale!
http://it.yahoo.com/mail_it/foot/*http://it.messenger.yahoo.com
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2006-06-04 15:15 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-06-02 3:08 non-scalar ktime addition and subtraction broken Jeff Dike
2006-06-02 6:54 ` Thomas Gleixner
2006-06-02 15:19 ` [uml-devel] " Jeff Dike
2006-06-02 18:28 ` [uml-devel] " Blaisorblade
2006-06-02 21:34 ` Jeff Dike
2006-06-04 15:04 ` Blaisorblade
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox