summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAndrew Morton <akpm@digeo.com>2003-06-14 07:19:27 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2003-06-14 07:19:27 -0700
commitb9cebc5d5f51e520f9e1772976fff56244ded862 (patch)
tree5f922a7652de1f95b9554087ea1e8ca31d908407 /kernel
parent90ea34be80a2e3c0bf2970c8666180e50fc57d0a (diff)
[PATCH] Some clean up of the time code.
From: george anzinger <george@mvista.com> This patch does the following: Pushs down the change from timeval to timespec in the settime routines. Fixes two places where time was set without updating the monotonic clock offset. (Changes sys_stime() to call do_settimeofday() and changes clock_warp to do the update directly.) These were bugs! Changes the uptime code to use the posix_clock_monotonic notion of uptime instead of the jiffies. This time will track NTP changes and so should be better than your standard wristwatch (if your using ntp). Changes posix_clock_monotonic to start at 0 on boot (was set to start at initial jiffies). Fixes a bug (never experienced) in timer_create() in posix-timers.c where we "could" have released timer_id 0 if "id resources" were low. Adds a test in do_settimeofday() to error out (EINVAL) attempts to use unnormalized times. This is passed back up to both settimeofday and posix_setclock(). Warning: Requires changes in .../arch/???/kernel/time.c to change do_settimeofday() to return an error if time is not normalized and to use a timespec instead of timeval for its input.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/posix-timers.c5
-rw-r--r--kernel/time.c24
-rw-r--r--kernel/timer.c21
3 files changed, 29 insertions, 21 deletions
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index cbb920ab3102..fa82b964a9b1 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -409,7 +409,7 @@ sys_timer_create(clockid_t which_clock,
do {
if (unlikely(!idr_pre_get(&posix_timers_id))) {
error = -EAGAIN;
- new_timer_id = (timer_t)-1;
+ new_timer->it_id = (timer_t)-1;
goto out;
}
spin_lock_irq(&idr_lock);
@@ -1026,8 +1026,7 @@ sys_clock_settime(clockid_t which_clock, const struct timespec __user *tp)
if (posix_clocks[which_clock].clock_set)
return posix_clocks[which_clock].clock_set(&new_tp);
- new_tp.tv_nsec /= NSEC_PER_USEC;
- return do_sys_settimeofday((struct timeval *) &new_tp, NULL);
+ return do_sys_settimeofday(&new_tp, NULL);
}
asmlinkage long
diff --git a/kernel/time.c b/kernel/time.c
index 37b0415545ff..36febc007a93 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -68,22 +68,15 @@ asmlinkage long sys_time(int * tloc)
asmlinkage long sys_stime(int * tptr)
{
- int value;
+ struct timespec tv;
if (!capable(CAP_SYS_TIME))
return -EPERM;
- if (get_user(value, tptr))
+ if (get_user(tv.tv_sec, tptr))
return -EFAULT;
- write_seqlock_irq(&xtime_lock);
- time_interpolator_reset();
- xtime.tv_sec = value;
- xtime.tv_nsec = 0;
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
- write_sequnlock_irq(&xtime_lock);
+ tv.tv_nsec = 0;
+ do_settimeofday(&tv);
return 0;
}
@@ -123,9 +116,11 @@ asmlinkage long sys_gettimeofday(struct timeval __user *tv, struct timezone __us
inline static void warp_clock(void)
{
write_seqlock_irq(&xtime_lock);
+ wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
xtime.tv_sec += sys_tz.tz_minuteswest * 60;
time_interpolator_update(sys_tz.tz_minuteswest * 60 * NSEC_PER_SEC);
write_sequnlock_irq(&xtime_lock);
+ clock_was_set();
}
/*
@@ -139,7 +134,7 @@ inline static void warp_clock(void)
* various programs will get confused when the clock gets warped.
*/
-int do_sys_settimeofday(struct timeval *tv, struct timezone *tz)
+int do_sys_settimeofday(struct timespec *tv, struct timezone *tz)
{
static int firsttime = 1;
@@ -160,14 +155,14 @@ int do_sys_settimeofday(struct timeval *tv, struct timezone *tz)
/* SMP safe, again the code in arch/foo/time.c should
* globally block out interrupts when it runs.
*/
- do_settimeofday(tv);
+ return do_settimeofday(tv);
}
return 0;
}
asmlinkage long sys_settimeofday(struct timeval __user *tv, struct timezone __user *tz)
{
- struct timeval new_tv;
+ struct timespec new_tv;
struct timezone new_tz;
if (tv) {
@@ -177,6 +172,7 @@ asmlinkage long sys_settimeofday(struct timeval __user *tv, struct timezone __us
if (tz) {
if (copy_from_user(&new_tz, tz, sizeof(*tz)))
return -EFAULT;
+ new_tv.tv_nsec *= NSEC_PER_USEC;
}
return do_sys_settimeofday(tv ? &new_tv : NULL, tz ? &new_tz : NULL);
diff --git a/kernel/timer.c b/kernel/timer.c
index 06f87498c7c7..56dfe4fc6be4 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1109,7 +1109,6 @@ asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
asmlinkage long sys_sysinfo(struct sysinfo __user *info)
{
struct sysinfo val;
- u64 uptime;
unsigned long mem_total, sav_total;
unsigned int mem_unit, bitcount;
unsigned long seq;
@@ -1117,11 +1116,25 @@ asmlinkage long sys_sysinfo(struct sysinfo __user *info)
memset((char *)&val, 0, sizeof(struct sysinfo));
do {
+ struct timespec tp;
seq = read_seqbegin(&xtime_lock);
- uptime = jiffies_64 - INITIAL_JIFFIES;
- do_div(uptime, HZ);
- val.uptime = (unsigned long) uptime;
+ /*
+ * This is annoying. The below is the same thing
+ * posix_get_clock_monotonic() does, but it wants to
+ * take the lock which we want to cover the loads stuff
+ * too.
+ */
+
+ do_gettimeofday((struct timeval *)&tp);
+ tp.tv_nsec *= NSEC_PER_USEC;
+ tp.tv_sec += wall_to_monotonic.tv_sec;
+ tp.tv_nsec += wall_to_monotonic.tv_nsec;
+ if (tp.tv_nsec - NSEC_PER_SEC >= 0) {
+ tp.tv_nsec = tp.tv_nsec - NSEC_PER_SEC;
+ tp.tv_sec++;
+ }
+ val.uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0);
val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);