diff options
author | James Bottomley <jejb@parisc-linux.org> | 2006-06-24 16:05:18 +0000 |
---|---|---|
committer | Kyle McMartin <kyle@hera.kernel.org> | 2006-06-27 23:28:45 +0000 |
commit | 61c340166d8c62086b6de00afc7670eea27eb2ab (patch) | |
tree | 2f7b635d242d2a83e1d6c8d94199259dace30d55 /arch/parisc/kernel | |
parent | 6e1b9585aaae2fa4f9590f363b32c5d3b6339ba6 (diff) | |
download | op-kernel-dev-61c340166d8c62086b6de00afc7670eea27eb2ab.zip op-kernel-dev-61c340166d8c62086b6de00afc7670eea27eb2ab.tar.gz |
[PARISC] Fix do_gettimeofday() hang
Apparently gettimeoffset can return small negative values (usually in
the 100us range). If xtime.tv_nsec is accidentally less than this,
though (a fortunately unlikely event) it triggers the loop forever.
I've added a test and correct adjustment for this case. It has a
warning printk in there which I'd like to leave for the time being
just in case this problem implicates some other part of the kernel.
Signed-off-by: James Bottomley <jejb@parisc-linux.org>
Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
Diffstat (limited to 'arch/parisc/kernel')
-rw-r--r-- | arch/parisc/kernel/time.c | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 594930b..eb35e1c 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -157,8 +157,22 @@ do_gettimeofday (struct timeval *tv) usec += (xtime.tv_nsec / 1000); } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - while (usec >= 1000000) { - usec -= 1000000; + if (unlikely(usec > LONG_MAX)) { + /* This can happen if the gettimeoffset adjustment is + * negative and xtime.tv_nsec is smaller than the + * adjustment */ + printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec); + usec += USEC_PER_SEC; + --sec; + /* This should never happen, it means the negative + * time adjustment was more than a second, so there's + * something seriously wrong */ + BUG_ON(usec > LONG_MAX); + } + + + while (usec >= USEC_PER_SEC) { + usec -= USEC_PER_SEC; ++sec; } |