: This patch fixes the broken adjtime() emulation of PPSkit with nanokernel. Index: kernel/time.c =================================================================== RCS file: /root/LinuxCVS/Kernel/kernel/time.c,v retrieving revision 1.1.1.5.2.3 diff -u -r1.1.1.5.2.3 time.c --- kernel/time.c 8 Mar 2003 15:52:45 -0000 1.1.1.5.2.3 +++ kernel/time.c 21 Mar 2003 21:09:05 -0000 @@ -155,6 +155,11 @@ * 2003-02-04 Ulrich Windl * Added missing permission check for ``sys_clock_settime()''. Added * strategy routine to implement proper permission checks for sysctl. + * 2003-03-21 Ulrich Windl + * Fixed bug: adjtimex() was accepting microseconds as nanoseconds, + * returning nanoseconds as microseconds. Indicate broken adjtime() + * implementation with limited range. Changed ``tickadj'' back to + * microseconds (which is the granularity of adjtime() anyway). */ #include @@ -201,7 +206,8 @@ static long time_adjust = 0; /* remaining adjustment for adjtime() */ long time_tick; /* nanoseconds per tick (ns) */ -static long tickadj; /* number of nanoseconds to adjust time_tick */ +static long tickadj; /* number of microseconds to adjust time_tick */ + /* [extension by UW]: If ``rtc_update'' is positive then update the RTC as * before, but using the value as interval between updates. * ``rtc_update_slave'' will contain the value of ``rtc_update'' if the RTC @@ -371,7 +377,7 @@ static /* const */ int sysctl_no_max = 1 << 30; static /* const */ int sysctl_tick_min = 9 * (NANOSECOND/10/hz); static /* const */ int sysctl_tick_max = 11 * (NANOSECOND/10/hz); -static /* const */ int sysctl_tickadj_max = (NANOSECOND/hz) / 4; +static /* const */ int sysctl_tickadj_max = (NANOSECOND/1000/hz) / 4; static /* const */ int sysctl_hz = HZ; /* strategy routine for sysctl() */ @@ -624,6 +630,7 @@ /* Update remaining adjustment */ time_adjust -= time_update; + time_update *= 1000; /* convert to nanoseconds */ } #ifdef CONFIG_NTP /* @@ -1501,9 +1508,6 @@ result = 0; #endif - /* Save for later - semantics of adjtime is to return old value */ - save_adjust = time_adjust; - #if defined(CONFIG_NTP) && 0 /* STA_CLOCKERR is never set yet */ time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */ #endif @@ -1627,8 +1631,17 @@ } #endif /* CONFIG_NTP */ if (txc->modes == ADJ_ADJTIME) { - /* adjtime() is independent from ntp_adjtime() */ + /* + * The emulation of adjtime() is actually broken, + * because only one ``long'' is available to represent + * a ``struct timeval''. + */ + /* Save current adjustment to be retuned */ + save_adjust = time_adjust; time_adjust = txc->offset; + if (txc->offset < -30000000 || txc->offset > 30000000) + printk(KERN_WARNING + "adjtime() fails with large offsets\n"); } if (txc->modes & ADJ_TIMETICK) { #ifdef CONFIG_NTP @@ -1654,11 +1667,11 @@ Larger values might cause trouble! */ if (txc->tickadj <= 0 || - txc->tickadj > time_tick/4000) { + txc->tickadj > time_tick / 4) { result = -EINVAL; goto leave; } - tickadj = txc->tickadj * 1000; + tickadj = txc->tickadj; } } /* txc->modes */ leave: @@ -1703,7 +1716,7 @@ txc->errcnt = pps.errcnt; txc->stbcnt = pps.stbcnt; #endif - txc->tickadj = tickadj / 1000; /* extension by UW */ + txc->tickadj = tickadj; /* extension by UW */ #ifdef CONFIG_NTP if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0 @@ -1772,7 +1785,7 @@ */ time_tick = (NANOSECOND + hz/2) / hz; /* Speed of adjtime() is 50ms/s; may not be <= 0 */ - tickadj = 50000000/hz ? : 1; + tickadj = 50000/hz ? : 1; time_adjust = 0; rtc_update = 660; /* update every 11 minutes */