From: george anzinger <george@mvista.com>

This is an update of a patch I sent some time ago.  You could not apply it
then because of some other stuff...  Let me know if I need to use a
different base system...

I will send Eric's patch soon...

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.



 arch/i386/kernel/time.c |   23 +++++++++++++----------
 fs/proc/proc_misc.c     |   37 ++++++++++---------------------------
 include/linux/time.h    |    5 +++--
 kernel/posix-timers.c   |    5 ++---
 kernel/time.c           |   24 ++++++++++--------------
 kernel/timer.c          |   21 +++++++++++++++++----
 6 files changed, 55 insertions(+), 60 deletions(-)

diff -puN arch/i386/kernel/time.c~time-fixes-cleanup-1 arch/i386/kernel/time.c
--- 25/arch/i386/kernel/time.c~time-fixes-cleanup-1	2003-06-10 22:06:31.000000000 -0700
+++ 25-akpm/arch/i386/kernel/time.c	2003-06-10 22:06:38.000000000 -0700
@@ -114,8 +114,11 @@ void do_gettimeofday(struct timeval *tv)
 	tv->tv_usec = usec;
 }
 
-void do_settimeofday(struct timeval *tv)
+int do_settimeofday(struct timespec *tv)
 {
+	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+		return -EINVAL;
+
 	write_seqlock_irq(&xtime_lock);
 	/*
 	 * This is revolting. We need to set "xtime" correctly. However, the
@@ -123,17 +126,16 @@ void do_settimeofday(struct timeval *tv)
 	 * wall time.  Discover what correction gettimeofday() would have
 	 * made, and then undo it!
 	 */
-	tv->tv_usec -= timer->get_offset();
-	tv->tv_usec -= (jiffies - wall_jiffies) * (USEC_PER_SEC / HZ);
+	tv->tv_nsec -= timer->get_offset() * NSEC_PER_USEC;
+	tv->tv_nsec -= (jiffies - wall_jiffies) * TICK_NSEC(TICK_USEC);
 
-	while (tv->tv_usec < 0) {
-		tv->tv_usec += USEC_PER_SEC;
+	while (tv->tv_nsec < 0) {
+		tv->tv_nsec += NSEC_PER_SEC;
 		tv->tv_sec--;
 	}
-	tv->tv_usec *= NSEC_PER_USEC;
 
 	wall_to_monotonic.tv_sec += xtime.tv_sec - tv->tv_sec;
-	wall_to_monotonic.tv_nsec += xtime.tv_nsec - tv->tv_usec;
+	wall_to_monotonic.tv_nsec += xtime.tv_nsec - tv->tv_nsec;
 
 	if (wall_to_monotonic.tv_nsec > NSEC_PER_SEC) {
 		wall_to_monotonic.tv_nsec -= NSEC_PER_SEC;
@@ -145,13 +147,14 @@ void do_settimeofday(struct timeval *tv)
 	}
 
 	xtime.tv_sec = tv->tv_sec;
-	xtime.tv_nsec = tv->tv_usec;
+	xtime.tv_nsec = tv->tv_nsec;
 	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);
 	clock_was_set();
+	return 0;
 }
 
 static int set_rtc_mmss(unsigned long nowtime)
@@ -303,9 +306,9 @@ void __init time_init(void)
 {
 	
 	xtime.tv_sec = get_cmos_time();
-	wall_to_monotonic.tv_sec = -xtime.tv_sec + INITIAL_JIFFIES / HZ;
+	wall_to_monotonic.tv_sec = -xtime.tv_sec;
 	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-	wall_to_monotonic.tv_nsec = 0;
+	wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
 
 
 	timer = select_timer();
diff -puN fs/proc/proc_misc.c~time-fixes-cleanup-1 fs/proc/proc_misc.c
--- 25/fs/proc/proc_misc.c~time-fixes-cleanup-1	2003-06-10 22:06:31.000000000 -0700
+++ 25-akpm/fs/proc/proc_misc.c	2003-06-10 22:06:31.000000000 -0700
@@ -137,36 +137,19 @@ static struct vmalloc_info get_vmalloc_i
 static int uptime_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
 {
-	u64 uptime;
-	unsigned long uptime_remainder;
+	struct timespec uptime;
+	struct timespec idle;
 	int len;
+	u64 idle_jiffies = init_task.utime + init_task.stime;
 
-	uptime = get_jiffies_64() - INITIAL_JIFFIES;
-	uptime_remainder = (unsigned long) do_div(uptime, HZ);
+	do_posix_clock_monotonic_gettime(&uptime);
+	jiffies_to_timespec(idle_jiffies, &idle);
+	len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
+			(unsigned long) uptime.tv_sec,
+			(uptime.tv_nsec / (NSEC_PER_SEC / 100)),
+			(unsigned long) idle.tv_sec,
+			(idle.tv_nsec / (NSEC_PER_SEC / 100)));
 
-#if HZ!=100
-	{
-		u64 idle = init_task.utime + init_task.stime;
-		unsigned long idle_remainder;
-
-		idle_remainder = (unsigned long) do_div(idle, HZ);
-		len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
-			(unsigned long) uptime,
-			(uptime_remainder * 100) / HZ,
-			(unsigned long) idle,
-			(idle_remainder * 100) / HZ);
-	}
-#else
-	{
-		unsigned long idle = init_task.utime + init_task.stime;
-
-		len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
-			(unsigned long) uptime,
-			uptime_remainder,
-			idle / HZ,
-			idle % HZ);
-	}
-#endif
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
diff -puN include/linux/time.h~time-fixes-cleanup-1 include/linux/time.h
--- 25/include/linux/time.h~time-fixes-cleanup-1	2003-06-10 22:06:31.000000000 -0700
+++ 25-akpm/include/linux/time.h	2003-06-10 22:06:38.000000000 -0700
@@ -200,9 +200,10 @@ struct timespec current_kernel_time(void
 
 #ifdef __KERNEL__
 extern void do_gettimeofday(struct timeval *tv);
-extern void do_settimeofday(struct timeval *tv);
-extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+extern int do_settimeofday(struct timespec *tv);
+extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz);
 extern void clock_was_set(void); // call when ever the clock is set
+extern int do_posix_clock_monotonic_gettime(struct timespec *tp);
 extern long do_nanosleep(struct timespec *t);
 extern long do_utimes(char __user * filename, struct timeval * times);
 #endif
diff -puN kernel/posix-timers.c~time-fixes-cleanup-1 kernel/posix-timers.c
--- 25/kernel/posix-timers.c~time-fixes-cleanup-1	2003-06-10 22:06:31.000000000 -0700
+++ 25-akpm/kernel/posix-timers.c	2003-06-10 22:06:38.000000000 -0700
@@ -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,
 	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 -puN kernel/time.c~time-fixes-cleanup-1 kernel/time.c
--- 25/kernel/time.c~time-fixes-cleanup-1	2003-06-10 22:06:31.000000000 -0700
+++ 25-akpm/kernel/time.c	2003-06-10 22:06:38.000000000 -0700
@@ -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 
 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 *
 		/* 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 
 	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 -puN kernel/timer.c~time-fixes-cleanup-1 kernel/timer.c
--- 25/kernel/timer.c~time-fixes-cleanup-1	2003-06-10 22:06:31.000000000 -0700
+++ 25-akpm/kernel/timer.c	2003-06-10 22:06:38.000000000 -0700
@@ -1109,7 +1109,6 @@ asmlinkage long sys_nanosleep(struct tim
 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 sysin
 	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);

_