diff options
| author | Andrew Morton <akpm@digeo.com> | 2003-06-14 07:19:27 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-06-14 07:19:27 -0700 |
| commit | b9cebc5d5f51e520f9e1772976fff56244ded862 (patch) | |
| tree | 5f922a7652de1f95b9554087ea1e8ca31d908407 /kernel | |
| parent | 90ea34be80a2e3c0bf2970c8666180e50fc57d0a (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.c | 5 | ||||
| -rw-r--r-- | kernel/time.c | 24 | ||||
| -rw-r--r-- | kernel/timer.c | 21 |
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); |
