Dear Linus,
the appended patch enables 32 bit linux boxes to display more than
497.1 days of uptime. No user land application changes are needed.
This is the solution that came out of the "[Patch] Re: Nasty suprise with
uptime" thread a week ago.
As no objections have been raised since then, and as I was able to cure
the observed lockups after jiffies wraparound by the "[Patch] fix
incorrect jiffies compares" just posted to lkml, I believe this to be
ready for inclusion into the main tree.
The patch introduces a get_jiffies64() function that internally counts the
jiffies wrap. This way there is no overhead neither in the timer interrupt
nor in functions not interested in a 64bit jiffies value. IMHO this patch
does not interfere with the possible introduction of a "real" 64 bit
jiffies counter at later times, as the get_jiffies64() can still be
retained then to provide the necessary locking.
I also extended the start_time field of struct task_struct to 64 bits so
that ps output will still be ok after the 32 bit wraparound while keeping
sub-second resolution of runtimes.
Idle time overflow is dealt with in the same way as the jiffies
wraparound. The CPU time of the idle task will still overflow as it will
for every other process getting more than 497.1 days of CPU time, but I
don't want to blow up every time variable. I believe this to be acceptable
behavior.
The downshot of counting jiffies wraps in get_jiffies64() is that
overflows get undetected if for more than 497 days
- /proc/uptime is not read,
- sysinfo() is not called,
- and no new processes are started,
which altogether is rather unlikely.
Correct uptime display after jiffies wrap is of course only useful if
there are no stability problems after the wrap. To aid in finding out this
I added a config time option to initialize the jiffies counter to a value
5 minutes before wrap. I kindly ask people to turn this on and watch out.
It did not affect stability for me anymore after the jiffies comparison
fixed were applied.
Tim
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/Documentation/Configure.help linux-2.4.15-pre2-jiffies64/Documentation/Configure.help
--- linux-2.4.15-pre2/Documentation/Configure.help Sun Nov 11 10:23:36 2001
+++ linux-2.4.15-pre2-jiffies64/Documentation/Configure.help Sun Nov 11 10:40:13 2001
@@ -23550,6 +23550,14 @@
of the BUG call as well as the EIP and oops trace. This aids
debugging but costs about 70-100K of memory.
+Debug jiffies counter wraparound (DANGEROUS)
+CONFIG_DEBUG_JIFFIESWRAP
+ Say Y here to initialize the jiffies counter to a value 5 minutes
+ before wraparound. This may make your system UNSTABLE and its
+ only use is to hunt down the causes of this instability.
+ If you don't know what the jiffies counter is or if you want
+ a stable system, say N.
+
Include kgdb kernel debugger
CONFIG_KGDB
Include in-kernel hooks for kgdb, the Linux kernel source level
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/arm/config.in linux-2.4.15-pre2-jiffies64/arch/arm/config.in
--- linux-2.4.15-pre2/arch/arm/config.in Sun Nov 11 10:23:36 2001
+++ linux-2.4.15-pre2-jiffies64/arch/arm/config.in Sun Nov 11 10:40:13 2001
@@ -601,6 +601,7 @@
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool 'Spinlock debugging' CONFIG_DEBUG_SPINLOCK
dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
# These options are only for real kernel hackers who want to get their hands dirty.
dep_bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_EXPERIMENTAL
dep_bool ' Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/cris/config.in linux-2.4.15-pre2-jiffies64/arch/cris/config.in
--- linux-2.4.15-pre2/arch/cris/config.in Mon Oct 15 22:42:14 2001
+++ linux-2.4.15-pre2-jiffies64/arch/cris/config.in Sun Nov 11 10:40:13 2001
@@ -250,4 +250,5 @@
if [ "$CONFIG_PROFILE" = "y" ]; then
int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
fi
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/i386/config.in linux-2.4.15-pre2-jiffies64/arch/i386/config.in
--- linux-2.4.15-pre2/arch/i386/config.in Sat Nov 3 02:46:47 2001
+++ linux-2.4.15-pre2-jiffies64/arch/i386/config.in Sun Nov 11 10:40:13 2001
@@ -405,6 +405,7 @@
bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
+ bool ' Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
fi
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/m68k/config.in linux-2.4.15-pre2-jiffies64/arch/m68k/config.in
--- linux-2.4.15-pre2/arch/m68k/config.in Tue Jun 12 04:15:27 2001
+++ linux-2.4.15-pre2-jiffies64/arch/m68k/config.in Sun Nov 11 10:40:13 2001
@@ -545,4 +545,5 @@
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/mips/config.in linux-2.4.15-pre2-jiffies64/arch/mips/config.in
--- linux-2.4.15-pre2/arch/mips/config.in Mon Oct 15 22:41:34 2001
+++ linux-2.4.15-pre2-jiffies64/arch/mips/config.in Sun Nov 11 10:40:13 2001
@@ -519,4 +519,5 @@
if [ "$CONFIG_SMP" != "y" ]; then
bool 'Run uncached' CONFIG_MIPS_UNCACHED
fi
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/parisc/config.in linux-2.4.15-pre2-jiffies64/arch/parisc/config.in
--- linux-2.4.15-pre2/arch/parisc/config.in Wed Apr 18 02:19:25 2001
+++ linux-2.4.15-pre2-jiffies64/arch/parisc/config.in Sun Nov 11 10:40:13 2001
@@ -206,5 +206,6 @@
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/ppc/config.in linux-2.4.15-pre2-jiffies64/arch/ppc/config.in
--- linux-2.4.15-pre2/arch/ppc/config.in Sat Nov 3 02:43:54 2001
+++ linux-2.4.15-pre2-jiffies64/arch/ppc/config.in Sun Nov 11 10:40:13 2001
@@ -391,4 +391,5 @@
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool 'Include kgdb kernel debugger' CONFIG_KGDB
bool 'Include xmon kernel debugger' CONFIG_XMON
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/sh/config.in linux-2.4.15-pre2-jiffies64/arch/sh/config.in
--- linux-2.4.15-pre2/arch/sh/config.in Mon Oct 15 22:36:48 2001
+++ linux-2.4.15-pre2-jiffies64/arch/sh/config.in Sun Nov 11 10:40:13 2001
@@ -385,4 +385,5 @@
if [ "$CONFIG_SH_STANDARD_BIOS" = "y" ]; then
bool 'Early printk support' CONFIG_SH_EARLY_PRINTK
fi
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/sparc/config.in linux-2.4.15-pre2-jiffies64/arch/sparc/config.in
--- linux-2.4.15-pre2/arch/sparc/config.in Tue Jun 12 04:15:27 2001
+++ linux-2.4.15-pre2-jiffies64/arch/sparc/config.in Sun Nov 11 10:40:13 2001
@@ -265,4 +265,5 @@
comment 'Kernel hacking'
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/fs/proc/array.c linux-2.4.15-pre2-jiffies64/fs/proc/array.c
--- linux-2.4.15-pre2/fs/proc/array.c Thu Oct 11 18:00:01 2001
+++ linux-2.4.15-pre2-jiffies64/fs/proc/array.c Sun Nov 11 10:40:13 2001
@@ -343,7 +343,7 @@
ppid = task->pid ? task->p_opptr->pid : 0;
read_unlock(&tasklist_lock);
res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
-%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
+%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
task->pid,
task->comm,
@@ -366,7 +366,7 @@
nice,
0UL /* removed */,
task->it_real_value,
- task->start_time,
+ (unsigned long long)(task->start_time) - INITIAL_JIFFIES,
vsize,
mm ? mm->rss : 0, /* you might want to shift this left 3 */
task->rlim[RLIMIT_RSS].rlim_cur,
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/fs/proc/proc_misc.c linux-2.4.15-pre2-jiffies64/fs/proc/proc_misc.c
--- linux-2.4.15-pre2/fs/proc/proc_misc.c Thu Oct 11 19:46:57 2001
+++ linux-2.4.15-pre2-jiffies64/fs/proc/proc_misc.c Sun Nov 11 10:40:14 2001
@@ -39,6 +39,7 @@
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
+#include <asm/div64.h>
#define LOAD_INT(x) ((x) >> FSHIFT)
@@ -100,37 +101,59 @@
return proc_calc_metrics(page, start, off, count, eof, len);
}
+#if BITS_PER_LONG < 48
+
+u64 get_idle64(void)
+{
+ static unsigned long idle_hi, idle_last;
+ static spinlock_t idle64_lock = SPIN_LOCK_UNLOCKED;
+ unsigned long idle;
+
+ spin_lock(&idle64_lock);
+ idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
+ if (idle < idle_last) /* We have a wrap */
+ idle_hi++;
+ idle_last = idle;
+ spin_unlock(&idle64_lock);
+
+ return (idle | ((u64)idle_hi) << BITS_PER_LONG);
+}
+
+#else
+ /* Idle time won't overflow for 8716 years at HZ==1024 */
+
+static inline u64 get_idle64(void)
+{
+ return (u64)(init_tasks[0]->times.tms_utime
+ + init_tasks[0]->times.tms_stime);
+}
+
+#endif /* BITS_PER_LONG < 48 */
+
static int uptime_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- unsigned long uptime;
- unsigned long idle;
+ u64 uptime, idle;
+ unsigned long uptime_remainder, idle_remainder;
int len;
- uptime = jiffies;
- idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
+ uptime = get_jiffies64() - INITIAL_JIFFIES;
+ uptime_remainder = (unsigned long) do_div(uptime, HZ);
+ idle = get_idle64();
+ idle_remainder = (unsigned long) do_div(idle, HZ);
- /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
- that would overflow about every five days at HZ == 100.
- Therefore the identity a = (a / b) * b + a % b is used so that it is
- calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
- The part in front of the '+' always evaluates as 0 (mod 100). All divisions
- in the above formulas are truncating. For HZ being a power of 10, the
- calculations simplify to the version in the #else part (if the printf
- format is adapted to the same number of digits as zeroes in HZ.
- */
#if HZ!=100
len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- (((uptime % HZ) * 100) / HZ) % 100,
- idle / HZ,
- (((idle % HZ) * 100) / HZ) % 100);
+ (unsigned long) uptime,
+ (uptime_remainder * 100) / HZ,
+ (unsigned long) idle,
+ (idle_remainder * 100) / HZ);
#else
len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- uptime % HZ,
- idle / HZ,
- idle % HZ);
+ (unsigned long) uptime,
+ uptime_remainder,
+ (unsigned long) idle,
+ idle_remainder);
#endif
return proc_calc_metrics(page, start, off, count, eof, len);
}
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/include/linux/sched.h linux-2.4.15-pre2-jiffies64/include/linux/sched.h
--- linux-2.4.15-pre2/include/linux/sched.h Sun Nov 11 10:28:23 2001
+++ linux-2.4.15-pre2-jiffies64/include/linux/sched.h Sun Nov 11 12:59:22 2001
@@ -352,7 +352,7 @@
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
struct tms times;
- unsigned long start_time;
+ u64 start_time;
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
@@ -549,6 +549,8 @@
#include <asm/current.h>
extern unsigned long volatile jiffies;
+extern u64 get_jiffies64(void);
+
extern unsigned long itimer_ticks;
extern unsigned long itimer_next;
extern struct timeval xtime;
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/include/linux/timex.h linux-2.4.15-pre2-jiffies64/include/linux/timex.h
--- linux-2.4.15-pre2/include/linux/timex.h Mon Nov 5 21:42:13 2001
+++ linux-2.4.15-pre2-jiffies64/include/linux/timex.h Sun Nov 11 12:54:00 2001
@@ -53,6 +53,13 @@
#include <asm/param.h>
+#ifdef CONFIG_DEBUG_JIFFIESWRAP
+ /* Make the jiffies counter wrap around sooner. */
+# define INITIAL_JIFFIES ((unsigned long)(-300*HZ))
+#else
+# define INITIAL_JIFFIES 0
+#endif
+
/*
* The following defines establish the engineering parameters of the PLL
* model. The HZ variable establishes the timer interrupt frequency, 100 Hz
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/kernel/acct.c linux-2.4.15-pre2-jiffies64/kernel/acct.c
--- linux-2.4.15-pre2/kernel/acct.c Mon Mar 19 21:35:08 2001
+++ linux-2.4.15-pre2-jiffies64/kernel/acct.c Sun Nov 11 10:40:14 2001
@@ -56,6 +56,7 @@
#include <linux/tty.h>
#include <asm/uaccess.h>
+#include <asm/div64.h>
/*
* These constants control the amount of freespace that suspend and
@@ -227,20 +228,24 @@
* This routine has been adopted from the encode_comp_t() function in
* the kern_acct.c file of the FreeBSD operating system. The encoding
* is a 13-bit fraction with a 3-bit (base 8) exponent.
+ *
+ * Bumped up to encode 64 bit values. Unfortunately the result may
+ * overflow now.
*/
#define MANTSIZE 13 /* 13 bit mantissa. */
-#define EXPSIZE 3 /* Base 8 (3 bit) exponent. */
+#define EXPSIZE 3 /* 3 bit exponent. */
+#define EXPBASE 3 /* Base 8 (3 bit) exponent. */
#define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */
-static comp_t encode_comp_t(unsigned long value)
+static comp_t encode_comp_t(u64 value)
{
int exp, rnd;
exp = rnd = 0;
while (value > MAXFRACT) {
- rnd = value & (1 << (EXPSIZE - 1)); /* Round up? */
- value >>= EXPSIZE; /* Base 8 exponent == 3 bit shift. */
+ rnd = value & (1 << (EXPBASE - 1)); /* Round up? */
+ value >>= EXPBASE; /* Base 8 exponent == 3 bit shift. */
exp++;
}
@@ -248,16 +253,21 @@
* If we need to round up, do it (and handle overflow correctly).
*/
if (rnd && (++value > MAXFRACT)) {
- value >>= EXPSIZE;
+ value >>= EXPBASE;
exp++;
}
/*
* Clean it up and polish it off.
*/
- exp <<= MANTSIZE; /* Shift the exponent into place */
- exp += value; /* and add on the mantissa. */
- return exp;
+ if (exp >= (1 << EXPSIZE)) {
+ /* Overflow. Return largest representable number instead. */
+ return (1ul << (MANTSIZE + EXPSIZE)) - 1;
+ } else {
+ exp <<= MANTSIZE; /* Shift the exponent into place */
+ exp += value; /* and add on the mantissa. */
+ return exp;
+ }
}
/*
@@ -277,6 +287,7 @@
struct acct ac;
mm_segment_t fs;
unsigned long vsize;
+ u64 elapsed;
/*
* First check to see if there is enough free_space to continue
@@ -294,8 +305,10 @@
strncpy(ac.ac_comm, current->comm, ACCT_COMM);
ac.ac_comm[ACCT_COMM - 1] = '\0';
- ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
- ac.ac_etime = encode_comp_t(jiffies - current->start_time);
+ elapsed = get_jiffies64() - current->start_time;
+ ac.ac_etime = encode_comp_t(elapsed);
+ do_div(elapsed, HZ);
+ ac.ac_btime = xtime.tv_sec - elapsed;
ac.ac_utime = encode_comp_t(current->times.tms_utime);
ac.ac_stime = encode_comp_t(current->times.tms_stime);
ac.ac_uid = current->uid;
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/kernel/fork.c linux-2.4.15-pre2-jiffies64/kernel/fork.c
--- linux-2.4.15-pre2/kernel/fork.c Wed Oct 24 02:44:15 2001
+++ linux-2.4.15-pre2-jiffies64/kernel/fork.c Sun Nov 11 10:40:14 2001
@@ -647,7 +647,7 @@
}
#endif
p->lock_depth = -1; /* -1 = no lock */
- p->start_time = jiffies;
+ p->start_time = get_jiffies64();
INIT_LIST_HEAD(&p->local_pages);
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/kernel/info.c linux-2.4.15-pre2-jiffies64/kernel/info.c
--- linux-2.4.15-pre2/kernel/info.c Sat Apr 21 01:15:40 2001
+++ linux-2.4.15-pre2-jiffies64/kernel/info.c Sun Nov 11 10:40:14 2001
@@ -12,15 +12,19 @@
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
+#include <asm/div64.h>
asmlinkage long sys_sysinfo(struct sysinfo *info)
{
struct sysinfo val;
+ u64 uptime;
memset((char *)&val, 0, sizeof(struct sysinfo));
cli();
- val.uptime = jiffies / HZ;
+ uptime = get_jiffies64() - INITIAL_JIFFIES;
+ do_div(uptime, HZ);
+ val.uptime = (unsigned long) uptime;
val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/kernel/timer.c linux-2.4.15-pre2-jiffies64/kernel/timer.c
--- linux-2.4.15-pre2/kernel/timer.c Mon Oct 8 19:41:41 2001
+++ linux-2.4.15-pre2-jiffies64/kernel/timer.c Sun Nov 11 13:05:25 2001
@@ -65,7 +65,7 @@
extern int do_setitimer(int, struct itimerval *, struct itimerval *);
-unsigned long volatile jiffies;
+unsigned long volatile jiffies = INITIAL_JIFFIES;
unsigned int * prof_buffer;
unsigned long prof_len;
@@ -115,9 +115,17 @@
}
for (i = 0; i < TVR_SIZE; i++)
INIT_LIST_HEAD(tv1.vec + i);
+
+#if CONFIG_DEBUG_JIFFIESWRAP
+ tv1.index = INITIAL_JIFFIES & TVR_MASK;
+ tv2.index = (INITIAL_JIFFIES >> TVR_BITS) & TVN_MASK;
+ tv3.index = (INITIAL_JIFFIES >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
+ tv4.index = (INITIAL_JIFFIES >> (TVR_BITS + 2*TVN_BITS)) & TVN_MASK;
+ tv5.index = (INITIAL_JIFFIES >> (TVR_BITS + 3*TVN_BITS)) & TVN_MASK;
+#endif
}
-static unsigned long timer_jiffies;
+static unsigned long timer_jiffies = INITIAL_JIFFIES;
static inline void internal_add_timer(struct timer_list *timer)
{
@@ -638,7 +646,7 @@
}
/* jiffies at the most recent update of wall time */
-unsigned long wall_jiffies;
+unsigned long wall_jiffies = INITIAL_JIFFIES;
/*
* This spinlock protect us from races in SMP while playing with xtime. -arca
@@ -683,6 +691,37 @@
if (TQ_ACTIVE(tq_timer))
mark_bh(TQUEUE_BH);
}
+
+
+#if BITS_PER_LONG < 48
+
+u64 get_jiffies64(void)
+{
+ static unsigned long jiffies_hi = 0;
+ static unsigned long jiffies_last = INITIAL_JIFFIES;
+ static spinlock_t jiffies64_lock = SPIN_LOCK_UNLOCKED;
+ unsigned long jiffies_tmp;
+
+ spin_lock(&jiffies64_lock);
+ jiffies_tmp = jiffies; /* avoid races */
+ if (jiffies_tmp < jiffies_last) /* We have a wrap */
+ jiffies_hi++;
+ jiffies_last = jiffies_tmp;
+ spin_unlock(&jiffies64_lock);
+
+ return (jiffies_tmp | ((u64)jiffies_hi) << BITS_PER_LONG);
+}
+
+#else
+ /* jiffies is wide enough to not wrap for 8716 years at HZ==1024 */
+
+static inline u64 get_jiffies64(void)
+{
+ return (u64)jiffies;
+}
+
+#endif /* BITS_PER_LONG < 48 */
+
#if !defined(__alpha__) && !defined(__ia64__)
diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/mm/oom_kill.c linux-2.4.15-pre2-jiffies64/mm/oom_kill.c
--- linux-2.4.15-pre2/mm/oom_kill.c Sun Nov 4 02:05:25 2001
+++ linux-2.4.15-pre2-jiffies64/mm/oom_kill.c Sun Nov 11 10:42:26 2001
@@ -69,11 +69,10 @@
/*
* CPU time is in seconds and run time is in minutes. There is no
* particular reason for this other than that it turned out to work
- * very well in practice. This is not safe against jiffie wraps
- * but we don't care _that_ much...
+ * very well in practice.
*/
cpu_time = (p->times.tms_utime + p->times.tms_stime) >> (SHIFT_HZ + 3);
- run_time = (jiffies - p->start_time) >> (SHIFT_HZ + 10);
+ run_time = (get_jiffies64() - p->start_time) >> (SHIFT_HZ + 10);
points /= int_sqrt(cpu_time);
points /= int_sqrt(int_sqrt(run_time));
Thank you for doing this labor of love -
I will let you know how it goes sometime
after March 23, 2003 -
cu
jjs
Tim Schmielau wrote:
> Dear Linus,
>
> the appended patch enables 32 bit linux boxes to display more than
> 497.1 days of uptime. No user land application changes are needed.
> This is the solution that came out of the "[Patch] Re: Nasty suprise with
> uptime" thread a week ago.
>
> As no objections have been raised since then, and as I was able to cure
> the observed lockups after jiffies wraparound by the "[Patch] fix
> incorrect jiffies compares" just posted to lkml, I believe this to be
> ready for inclusion into the main tree.
>
> The patch introduces a get_jiffies64() function that internally counts the
> jiffies wrap. This way there is no overhead neither in the timer interrupt
> nor in functions not interested in a 64bit jiffies value. IMHO this patch
> does not interfere with the possible introduction of a "real" 64 bit
> jiffies counter at later times, as the get_jiffies64() can still be
> retained then to provide the necessary locking.
>
> I also extended the start_time field of struct task_struct to 64 bits so
> that ps output will still be ok after the 32 bit wraparound while keeping
> sub-second resolution of runtimes.
>
> Idle time overflow is dealt with in the same way as the jiffies
> wraparound. The CPU time of the idle task will still overflow as it will
> for every other process getting more than 497.1 days of CPU time, but I
> don't want to blow up every time variable. I believe this to be acceptable
> behavior.
>
> The downshot of counting jiffies wraps in get_jiffies64() is that
> overflows get undetected if for more than 497 days
> - /proc/uptime is not read,
> - sysinfo() is not called,
> - and no new processes are started,
> which altogether is rather unlikely.
>
> Correct uptime display after jiffies wrap is of course only useful if
> there are no stability problems after the wrap. To aid in finding out this
> I added a config time option to initialize the jiffies counter to a value
> 5 minutes before wrap. I kindly ask people to turn this on and watch out.
> It did not affect stability for me anymore after the jiffies comparison
> fixed were applied.
>
> Tim
>
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/Documentation/Configure.help linux-2.4.15-pre2-jiffies64/Documentation/Configure.help
> --- linux-2.4.15-pre2/Documentation/Configure.help Sun Nov 11 10:23:36 2001
> +++ linux-2.4.15-pre2-jiffies64/Documentation/Configure.help Sun Nov 11 10:40:13 2001
> @@ -23550,6 +23550,14 @@
> of the BUG call as well as the EIP and oops trace. This aids
> debugging but costs about 70-100K of memory.
>
> +Debug jiffies counter wraparound (DANGEROUS)
> +CONFIG_DEBUG_JIFFIESWRAP
> + Say Y here to initialize the jiffies counter to a value 5 minutes
> + before wraparound. This may make your system UNSTABLE and its
> + only use is to hunt down the causes of this instability.
> + If you don't know what the jiffies counter is or if you want
> + a stable system, say N.
> +
> Include kgdb kernel debugger
> CONFIG_KGDB
> Include in-kernel hooks for kgdb, the Linux kernel source level
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/arm/config.in linux-2.4.15-pre2-jiffies64/arch/arm/config.in
> --- linux-2.4.15-pre2/arch/arm/config.in Sun Nov 11 10:23:36 2001
> +++ linux-2.4.15-pre2-jiffies64/arch/arm/config.in Sun Nov 11 10:40:13 2001
> @@ -601,6 +601,7 @@
> bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
> bool 'Spinlock debugging' CONFIG_DEBUG_SPINLOCK
> dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26
> +bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
> # These options are only for real kernel hackers who want to get their hands dirty.
> dep_bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_EXPERIMENTAL
> dep_bool ' Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/cris/config.in linux-2.4.15-pre2-jiffies64/arch/cris/config.in
> --- linux-2.4.15-pre2/arch/cris/config.in Mon Oct 15 22:42:14 2001
> +++ linux-2.4.15-pre2-jiffies64/arch/cris/config.in Sun Nov 11 10:40:13 2001
> @@ -250,4 +250,5 @@
> if [ "$CONFIG_PROFILE" = "y" ]; then
> int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
> fi
> +bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
> endmenu
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/i386/config.in linux-2.4.15-pre2-jiffies64/arch/i386/config.in
> --- linux-2.4.15-pre2/arch/i386/config.in Sat Nov 3 02:46:47 2001
> +++ linux-2.4.15-pre2-jiffies64/arch/i386/config.in Sun Nov 11 10:40:13 2001
> @@ -405,6 +405,7 @@
> bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
> bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
> bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
> + bool ' Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
> fi
>
> endmenu
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/m68k/config.in linux-2.4.15-pre2-jiffies64/arch/m68k/config.in
> --- linux-2.4.15-pre2/arch/m68k/config.in Tue Jun 12 04:15:27 2001
> +++ linux-2.4.15-pre2-jiffies64/arch/m68k/config.in Sun Nov 11 10:40:13 2001
> @@ -545,4 +545,5 @@
>
> #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
> bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
> +bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
> endmenu
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/mips/config.in linux-2.4.15-pre2-jiffies64/arch/mips/config.in
> --- linux-2.4.15-pre2/arch/mips/config.in Mon Oct 15 22:41:34 2001
> +++ linux-2.4.15-pre2-jiffies64/arch/mips/config.in Sun Nov 11 10:40:13 2001
> @@ -519,4 +519,5 @@
> if [ "$CONFIG_SMP" != "y" ]; then
> bool 'Run uncached' CONFIG_MIPS_UNCACHED
> fi
> +bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
> endmenu
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/parisc/config.in linux-2.4.15-pre2-jiffies64/arch/parisc/config.in
> --- linux-2.4.15-pre2/arch/parisc/config.in Wed Apr 18 02:19:25 2001
> +++ linux-2.4.15-pre2-jiffies64/arch/parisc/config.in Sun Nov 11 10:40:13 2001
> @@ -206,5 +206,6 @@
>
> #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
> bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
> +bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
> endmenu
>
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/ppc/config.in linux-2.4.15-pre2-jiffies64/arch/ppc/config.in
> --- linux-2.4.15-pre2/arch/ppc/config.in Sat Nov 3 02:43:54 2001
> +++ linux-2.4.15-pre2-jiffies64/arch/ppc/config.in Sun Nov 11 10:40:13 2001
> @@ -391,4 +391,5 @@
> bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
> bool 'Include kgdb kernel debugger' CONFIG_KGDB
> bool 'Include xmon kernel debugger' CONFIG_XMON
> +bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
> endmenu
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/sh/config.in linux-2.4.15-pre2-jiffies64/arch/sh/config.in
> --- linux-2.4.15-pre2/arch/sh/config.in Mon Oct 15 22:36:48 2001
> +++ linux-2.4.15-pre2-jiffies64/arch/sh/config.in Sun Nov 11 10:40:13 2001
> @@ -385,4 +385,5 @@
> if [ "$CONFIG_SH_STANDARD_BIOS" = "y" ]; then
> bool 'Early printk support' CONFIG_SH_EARLY_PRINTK
> fi
> +bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
> endmenu
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/arch/sparc/config.in linux-2.4.15-pre2-jiffies64/arch/sparc/config.in
> --- linux-2.4.15-pre2/arch/sparc/config.in Tue Jun 12 04:15:27 2001
> +++ linux-2.4.15-pre2-jiffies64/arch/sparc/config.in Sun Nov 11 10:40:13 2001
> @@ -265,4 +265,5 @@
> comment 'Kernel hacking'
>
> bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
> +bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
> endmenu
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/fs/proc/array.c linux-2.4.15-pre2-jiffies64/fs/proc/array.c
> --- linux-2.4.15-pre2/fs/proc/array.c Thu Oct 11 18:00:01 2001
> +++ linux-2.4.15-pre2-jiffies64/fs/proc/array.c Sun Nov 11 10:40:13 2001
> @@ -343,7 +343,7 @@
> ppid = task->pid ? task->p_opptr->pid : 0;
> read_unlock(&tasklist_lock);
> res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
> -%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
> +%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu \
> %lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
> task->pid,
> task->comm,
> @@ -366,7 +366,7 @@
> nice,
> 0UL /* removed */,
> task->it_real_value,
> - task->start_time,
> + (unsigned long long)(task->start_time) - INITIAL_JIFFIES,
> vsize,
> mm ? mm->rss : 0, /* you might want to shift this left 3 */
> task->rlim[RLIMIT_RSS].rlim_cur,
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/fs/proc/proc_misc.c linux-2.4.15-pre2-jiffies64/fs/proc/proc_misc.c
> --- linux-2.4.15-pre2/fs/proc/proc_misc.c Thu Oct 11 19:46:57 2001
> +++ linux-2.4.15-pre2-jiffies64/fs/proc/proc_misc.c Sun Nov 11 10:40:14 2001
> @@ -39,6 +39,7 @@
> #include <asm/uaccess.h>
> #include <asm/pgtable.h>
> #include <asm/io.h>
> +#include <asm/div64.h>
>
> #define LOAD_INT(x) ((x) >> FSHIFT)
> @@ -100,37 +101,59 @@
> return proc_calc_metrics(page, start, off, count, eof, len);
> }
>
> +#if BITS_PER_LONG < 48
> +
> +u64 get_idle64(void)
> +{
> + static unsigned long idle_hi, idle_last;
> + static spinlock_t idle64_lock = SPIN_LOCK_UNLOCKED;
> + unsigned long idle;
> +
> + spin_lock(&idle64_lock);
> + idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
> + if (idle < idle_last) /* We have a wrap */
> + idle_hi++;
> + idle_last = idle;
> + spin_unlock(&idle64_lock);
> +
> + return (idle | ((u64)idle_hi) << BITS_PER_LONG);
> +}
> +
> +#else
> + /* Idle time won't overflow for 8716 years at HZ==1024 */
> +
> +static inline u64 get_idle64(void)
> +{
> + return (u64)(init_tasks[0]->times.tms_utime
> + + init_tasks[0]->times.tms_stime);
> +}
> +
> +#endif /* BITS_PER_LONG < 48 */
> +
> static int uptime_read_proc(char *page, char **start, off_t off,
> int count, int *eof, void *data)
> {
> - unsigned long uptime;
> - unsigned long idle;
> + u64 uptime, idle;
> + unsigned long uptime_remainder, idle_remainder;
> int len;
>
> - uptime = jiffies;
> - idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
> + uptime = get_jiffies64() - INITIAL_JIFFIES;
> + uptime_remainder = (unsigned long) do_div(uptime, HZ);
> + idle = get_idle64();
> + idle_remainder = (unsigned long) do_div(idle, HZ);
>
> - /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
> - that would overflow about every five days at HZ == 100.
> - Therefore the identity a = (a / b) * b + a % b is used so that it is
> - calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
> - The part in front of the '+' always evaluates as 0 (mod 100). All divisions
> - in the above formulas are truncating. For HZ being a power of 10, the
> - calculations simplify to the version in the #else part (if the printf
> - format is adapted to the same number of digits as zeroes in HZ.
> - */
> #if HZ!=100
> len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
> - uptime / HZ,
> - (((uptime % HZ) * 100) / HZ) % 100,
> - idle / HZ,
> - (((idle % HZ) * 100) / HZ) % 100);
> + (unsigned long) uptime,
> + (uptime_remainder * 100) / HZ,
> + (unsigned long) idle,
> + (idle_remainder * 100) / HZ);
> #else
> len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
> - uptime / HZ,
> - uptime % HZ,
> - idle / HZ,
> - idle % HZ);
> + (unsigned long) uptime,
> + uptime_remainder,
> + (unsigned long) idle,
> + idle_remainder);
> #endif
> return proc_calc_metrics(page, start, off, count, eof, len);
> }
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/include/linux/sched.h linux-2.4.15-pre2-jiffies64/include/linux/sched.h
> --- linux-2.4.15-pre2/include/linux/sched.h Sun Nov 11 10:28:23 2001
> +++ linux-2.4.15-pre2-jiffies64/include/linux/sched.h Sun Nov 11 12:59:22 2001
> @@ -352,7 +352,7 @@
> unsigned long it_real_incr, it_prof_incr, it_virt_incr;
> struct timer_list real_timer;
> struct tms times;
> - unsigned long start_time;
> + u64 start_time;
> long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
> /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
> unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
> @@ -549,6 +549,8 @@
> #include <asm/current.h>
>
> extern unsigned long volatile jiffies;
> +extern u64 get_jiffies64(void);
> +
> extern unsigned long itimer_ticks;
> extern unsigned long itimer_next;
> extern struct timeval xtime;
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/include/linux/timex.h linux-2.4.15-pre2-jiffies64/include/linux/timex.h
> --- linux-2.4.15-pre2/include/linux/timex.h Mon Nov 5 21:42:13 2001
> +++ linux-2.4.15-pre2-jiffies64/include/linux/timex.h Sun Nov 11 12:54:00 2001
> @@ -53,6 +53,13 @@
>
> #include <asm/param.h>
>
> +#ifdef CONFIG_DEBUG_JIFFIESWRAP
> + /* Make the jiffies counter wrap around sooner. */
> +# define INITIAL_JIFFIES ((unsigned long)(-300*HZ))
> +#else
> +# define INITIAL_JIFFIES 0
> +#endif
> +
> /*
> * The following defines establish the engineering parameters of the PLL
> * model. The HZ variable establishes the timer interrupt frequency, 100 Hz
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/kernel/acct.c linux-2.4.15-pre2-jiffies64/kernel/acct.c
> --- linux-2.4.15-pre2/kernel/acct.c Mon Mar 19 21:35:08 2001
> +++ linux-2.4.15-pre2-jiffies64/kernel/acct.c Sun Nov 11 10:40:14 2001
> @@ -56,6 +56,7 @@
> #include <linux/tty.h>
>
> #include <asm/uaccess.h>
> +#include <asm/div64.h>
>
> /*
> * These constants control the amount of freespace that suspend and
> @@ -227,20 +228,24 @@
> * This routine has been adopted from the encode_comp_t() function in
> * the kern_acct.c file of the FreeBSD operating system. The encoding
> * is a 13-bit fraction with a 3-bit (base 8) exponent.
> + *
> + * Bumped up to encode 64 bit values. Unfortunately the result may
> + * overflow now.
> */
>
> #define MANTSIZE 13 /* 13 bit mantissa. */
> -#define EXPSIZE 3 /* Base 8 (3 bit) exponent. */
> +#define EXPSIZE 3 /* 3 bit exponent. */
> +#define EXPBASE 3 /* Base 8 (3 bit) exponent. */
> #define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */
>
> -static comp_t encode_comp_t(unsigned long value)
> +static comp_t encode_comp_t(u64 value)
> {
> int exp, rnd;
>
> exp = rnd = 0;
> while (value > MAXFRACT) {
> - rnd = value & (1 << (EXPSIZE - 1)); /* Round up? */
> - value >>= EXPSIZE; /* Base 8 exponent == 3 bit shift. */
> + rnd = value & (1 << (EXPBASE - 1)); /* Round up? */
> + value >>= EXPBASE; /* Base 8 exponent == 3 bit shift. */
> exp++;
> }
>
> @@ -248,16 +253,21 @@
> * If we need to round up, do it (and handle overflow correctly).
> */
> if (rnd && (++value > MAXFRACT)) {
> - value >>= EXPSIZE;
> + value >>= EXPBASE;
> exp++;
> }
>
> /*
> * Clean it up and polish it off.
> */
> - exp <<= MANTSIZE; /* Shift the exponent into place */
> - exp += value; /* and add on the mantissa. */
> - return exp;
> + if (exp >= (1 << EXPSIZE)) {
> + /* Overflow. Return largest representable number instead. */
> + return (1ul << (MANTSIZE + EXPSIZE)) - 1;
> + } else {
> + exp <<= MANTSIZE; /* Shift the exponent into place */
> + exp += value; /* and add on the mantissa. */
> + return exp;
> + }
> }
>
> /*
> @@ -277,6 +287,7 @@
> struct acct ac;
> mm_segment_t fs;
> unsigned long vsize;
> + u64 elapsed;
>
> /*
> * First check to see if there is enough free_space to continue
> @@ -294,8 +305,10 @@
> strncpy(ac.ac_comm, current->comm, ACCT_COMM);
> ac.ac_comm[ACCT_COMM - 1] = '\0';
>
> - ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
> - ac.ac_etime = encode_comp_t(jiffies - current->start_time);
> + elapsed = get_jiffies64() - current->start_time;
> + ac.ac_etime = encode_comp_t(elapsed);
> + do_div(elapsed, HZ);
> + ac.ac_btime = xtime.tv_sec - elapsed;
> ac.ac_utime = encode_comp_t(current->times.tms_utime);
> ac.ac_stime = encode_comp_t(current->times.tms_stime);
> ac.ac_uid = current->uid;
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/kernel/fork.c linux-2.4.15-pre2-jiffies64/kernel/fork.c
> --- linux-2.4.15-pre2/kernel/fork.c Wed Oct 24 02:44:15 2001
> +++ linux-2.4.15-pre2-jiffies64/kernel/fork.c Sun Nov 11 10:40:14 2001
> @@ -647,7 +647,7 @@
> }
> #endif
> p->lock_depth = -1; /* -1 = no lock */
> - p->start_time = jiffies;
> + p->start_time = get_jiffies64();
>
> INIT_LIST_HEAD(&p->local_pages);
>
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/kernel/info.c linux-2.4.15-pre2-jiffies64/kernel/info.c
> --- linux-2.4.15-pre2/kernel/info.c Sat Apr 21 01:15:40 2001
> +++ linux-2.4.15-pre2-jiffies64/kernel/info.c Sun Nov 11 10:40:14 2001
> @@ -12,15 +12,19 @@
> #include <linux/smp_lock.h>
>
> #include <asm/uaccess.h>
> +#include <asm/div64.h>
>
> asmlinkage long sys_sysinfo(struct sysinfo *info)
> {
> struct sysinfo val;
> + u64 uptime;
>
> memset((char *)&val, 0, sizeof(struct sysinfo));
>
> cli();
> - val.uptime = jiffies / HZ;
> + uptime = get_jiffies64() - INITIAL_JIFFIES;
> + do_div(uptime, HZ);
> + val.uptime = (unsigned long) uptime;
>
> val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
> val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/kernel/timer.c linux-2.4.15-pre2-jiffies64/kernel/timer.c
> --- linux-2.4.15-pre2/kernel/timer.c Mon Oct 8 19:41:41 2001
> +++ linux-2.4.15-pre2-jiffies64/kernel/timer.c Sun Nov 11 13:05:25 2001
> @@ -65,7 +65,7 @@
>
> extern int do_setitimer(int, struct itimerval *, struct itimerval *);
>
> -unsigned long volatile jiffies;
> +unsigned long volatile jiffies = INITIAL_JIFFIES;
>
> unsigned int * prof_buffer;
> unsigned long prof_len;
> @@ -115,9 +115,17 @@
> }
> for (i = 0; i < TVR_SIZE; i++)
> INIT_LIST_HEAD(tv1.vec + i);
> +
> +#if CONFIG_DEBUG_JIFFIESWRAP
> + tv1.index = INITIAL_JIFFIES & TVR_MASK;
> + tv2.index = (INITIAL_JIFFIES >> TVR_BITS) & TVN_MASK;
> + tv3.index = (INITIAL_JIFFIES >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
> + tv4.index = (INITIAL_JIFFIES >> (TVR_BITS + 2*TVN_BITS)) & TVN_MASK;
> + tv5.index = (INITIAL_JIFFIES >> (TVR_BITS + 3*TVN_BITS)) & TVN_MASK;
> +#endif
> }
>
> -static unsigned long timer_jiffies;
> +static unsigned long timer_jiffies = INITIAL_JIFFIES;
>
> static inline void internal_add_timer(struct timer_list *timer)
> {
> @@ -638,7 +646,7 @@
> }
>
> /* jiffies at the most recent update of wall time */
> -unsigned long wall_jiffies;
> +unsigned long wall_jiffies = INITIAL_JIFFIES;
>
> /*
> * This spinlock protect us from races in SMP while playing with xtime. -arca
> @@ -683,6 +691,37 @@
> if (TQ_ACTIVE(tq_timer))
> mark_bh(TQUEUE_BH);
> }
> +
> +
> +#if BITS_PER_LONG < 48
> +
> +u64 get_jiffies64(void)
> +{
> + static unsigned long jiffies_hi = 0;
> + static unsigned long jiffies_last = INITIAL_JIFFIES;
> + static spinlock_t jiffies64_lock = SPIN_LOCK_UNLOCKED;
> + unsigned long jiffies_tmp;
> +
> + spin_lock(&jiffies64_lock);
> + jiffies_tmp = jiffies; /* avoid races */
> + if (jiffies_tmp < jiffies_last) /* We have a wrap */
> + jiffies_hi++;
> + jiffies_last = jiffies_tmp;
> + spin_unlock(&jiffies64_lock);
> +
> + return (jiffies_tmp | ((u64)jiffies_hi) << BITS_PER_LONG);
> +}
> +
> +#else
> + /* jiffies is wide enough to not wrap for 8716 years at HZ==1024 */
> +
> +static inline u64 get_jiffies64(void)
> +{
> + return (u64)jiffies;
> +}
> +
> +#endif /* BITS_PER_LONG < 48 */
> +
>
> #if !defined(__alpha__) && !defined(__ia64__)
>
> diff -u -r --exclude-from dontdiff linux-2.4.15-pre2/mm/oom_kill.c linux-2.4.15-pre2-jiffies64/mm/oom_kill.c
> --- linux-2.4.15-pre2/mm/oom_kill.c Sun Nov 4 02:05:25 2001
> +++ linux-2.4.15-pre2-jiffies64/mm/oom_kill.c Sun Nov 11 10:42:26 2001
> @@ -69,11 +69,10 @@
> /*
> * CPU time is in seconds and run time is in minutes. There is no
> * particular reason for this other than that it turned out to work
> - * very well in practice. This is not safe against jiffie wraps
> - * but we don't care _that_ much...
> + * very well in practice.
> */
> cpu_time = (p->times.tms_utime + p->times.tms_stime) >> (SHIFT_HZ + 3);
> - run_time = (jiffies - p->start_time) >> (SHIFT_HZ + 10);
> + run_time = (get_jiffies64() - p->start_time) >> (SHIFT_HZ + 10);
>
> points /= int_sqrt(cpu_time);
> points /= int_sqrt(int_sqrt(run_time));
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
[new patch further down]
> the appended patch enables 32 bit linux boxes to display more than
> 497.1 days of uptime. No user land application changes are needed.
> This is the solution that came out of the "[Patch] Re: Nasty suprise with
> uptime" thread a week ago.
>
[...]
> The patch introduces a get_jiffies64() function that internally counts the
> jiffies wrap. This way there is no overhead neither in the timer interrupt
> nor in functions not interested in a 64bit jiffies value. IMHO this patch
> does not interfere with the possible introduction of a "real" 64 bit
> jiffies counter at later times, as the get_jiffies64() can still be
> retained then to provide the necessary locking.
>
> I also extended the start_time field of struct task_struct to 64 bits so
> that ps output will still be ok after the 32 bit wraparound while keeping
> sub-second resolution of runtimes.
>
> Idle time overflow is dealt with in the same way as the jiffies
> wraparound. The CPU time of the idle task will still overflow as it will
> for every other process getting more than 497.1 days of CPU time, but I
> don't want to blow up every time variable. I believe this to be acceptable
> behavior.
>
> The downshot of counting jiffies wraps in get_jiffies64() is that
> overflows go undetected if for more than 497 days
> - /proc/uptime is not read,
> - sysinfo() is not called,
> - and no new processes are started,
> which altogether is rather unlikely.
I extended the patch to use a counter for periodically checking for
jiffies overflows, so none can go undetected anymore. Still the CPU time
overhead is minimal as timer are implemented rather efficiently
> Correct uptime display after jiffies wrap is of course only useful if
> there are no stability problems after the wrap. To aid in finding out this
> I added a config time option to initialize the jiffies counter to a value
> 5 minutes before wrap. I kindly ask people to turn this on and watch out.
> It did not affect stability for me anymore after the jiffies comparison
> fixes were applied.
Tim
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/Documentation/Configure.help linux-2.4.15-pre6-jiffies64/Documentation/Configure.help
--- linux-2.4.15-pre6/Documentation/Configure.help Sun Nov 18 10:41:30 2001
+++ linux-2.4.15-pre6-jiffies64/Documentation/Configure.help Sun Nov 18 10:42:12 2001
@@ -23579,6 +23579,14 @@
of the BUG call as well as the EIP and oops trace. This aids
debugging but costs about 70-100K of memory.
+Debug jiffies counter wraparound (DANGEROUS)
+CONFIG_DEBUG_JIFFIESWRAP
+ Say Y here to initialize the jiffies counter to a value 5 minutes
+ before wraparound. This may make your system UNSTABLE and its
+ only use is to hunt down the causes of this instability.
+ If you don't know what the jiffies counter is or if you want
+ a stable system, say N.
+
Include kgdb kernel debugger
CONFIG_KGDB
Include in-kernel hooks for kgdb, the Linux kernel source level
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/arm/config.in linux-2.4.15-pre6-jiffies64/arch/arm/config.in
--- linux-2.4.15-pre6/arch/arm/config.in Sun Nov 18 10:41:30 2001
+++ linux-2.4.15-pre6-jiffies64/arch/arm/config.in Sun Nov 18 10:42:12 2001
@@ -601,6 +601,7 @@
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool 'Spinlock debugging' CONFIG_DEBUG_SPINLOCK
dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
# These options are only for real kernel hackers who want to get their hands dirty.
dep_bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_EXPERIMENTAL
dep_bool ' Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/cris/config.in linux-2.4.15-pre6-jiffies64/arch/cris/config.in
--- linux-2.4.15-pre6/arch/cris/config.in Mon Oct 15 22:42:14 2001
+++ linux-2.4.15-pre6-jiffies64/arch/cris/config.in Sun Nov 18 10:42:12 2001
@@ -250,4 +250,5 @@
if [ "$CONFIG_PROFILE" = "y" ]; then
int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
fi
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/i386/config.in linux-2.4.15-pre6-jiffies64/arch/i386/config.in
--- linux-2.4.15-pre6/arch/i386/config.in Sun Nov 18 10:41:30 2001
+++ linux-2.4.15-pre6-jiffies64/arch/i386/config.in Sun Nov 18 10:42:12 2001
@@ -407,6 +407,7 @@
bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
+ bool ' Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
fi
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/m68k/config.in linux-2.4.15-pre6-jiffies64/arch/m68k/config.in
--- linux-2.4.15-pre6/arch/m68k/config.in Tue Jun 12 04:15:27 2001
+++ linux-2.4.15-pre6-jiffies64/arch/m68k/config.in Sun Nov 18 10:42:12 2001
@@ -545,4 +545,5 @@
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/mips/config.in linux-2.4.15-pre6-jiffies64/arch/mips/config.in
--- linux-2.4.15-pre6/arch/mips/config.in Mon Oct 15 22:41:34 2001
+++ linux-2.4.15-pre6-jiffies64/arch/mips/config.in Sun Nov 18 10:42:12 2001
@@ -519,4 +519,5 @@
if [ "$CONFIG_SMP" != "y" ]; then
bool 'Run uncached' CONFIG_MIPS_UNCACHED
fi
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/parisc/config.in linux-2.4.15-pre6-jiffies64/arch/parisc/config.in
--- linux-2.4.15-pre6/arch/parisc/config.in Wed Apr 18 02:19:25 2001
+++ linux-2.4.15-pre6-jiffies64/arch/parisc/config.in Sun Nov 18 10:42:12 2001
@@ -206,5 +206,6 @@
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/ppc/config.in linux-2.4.15-pre6-jiffies64/arch/ppc/config.in
--- linux-2.4.15-pre6/arch/ppc/config.in Sun Nov 18 10:41:30 2001
+++ linux-2.4.15-pre6-jiffies64/arch/ppc/config.in Sun Nov 18 10:42:12 2001
@@ -392,4 +392,5 @@
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool 'Include kgdb kernel debugger' CONFIG_KGDB
bool 'Include xmon kernel debugger' CONFIG_XMON
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/sh/config.in linux-2.4.15-pre6-jiffies64/arch/sh/config.in
--- linux-2.4.15-pre6/arch/sh/config.in Mon Oct 15 22:36:48 2001
+++ linux-2.4.15-pre6-jiffies64/arch/sh/config.in Sun Nov 18 10:42:12 2001
@@ -385,4 +385,5 @@
if [ "$CONFIG_SH_STANDARD_BIOS" = "y" ]; then
bool 'Early printk support' CONFIG_SH_EARLY_PRINTK
fi
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/sparc/config.in linux-2.4.15-pre6-jiffies64/arch/sparc/config.in
--- linux-2.4.15-pre6/arch/sparc/config.in Tue Jun 12 04:15:27 2001
+++ linux-2.4.15-pre6-jiffies64/arch/sparc/config.in Sun Nov 18 10:42:12 2001
@@ -265,4 +265,5 @@
comment 'Kernel hacking'
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/fs/proc/array.c linux-2.4.15-pre6-jiffies64/fs/proc/array.c
--- linux-2.4.15-pre6/fs/proc/array.c Thu Oct 11 18:00:01 2001
+++ linux-2.4.15-pre6-jiffies64/fs/proc/array.c Sun Nov 18 10:42:12 2001
@@ -343,7 +343,7 @@
ppid = task->pid ? task->p_opptr->pid : 0;
read_unlock(&tasklist_lock);
res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
-%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
+%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
task->pid,
task->comm,
@@ -366,7 +366,7 @@
nice,
0UL /* removed */,
task->it_real_value,
- task->start_time,
+ (unsigned long long)(task->start_time) - INITIAL_JIFFIES,
vsize,
mm ? mm->rss : 0, /* you might want to shift this left 3 */
task->rlim[RLIMIT_RSS].rlim_cur,
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/fs/proc/proc_misc.c linux-2.4.15-pre6-jiffies64/fs/proc/proc_misc.c
--- linux-2.4.15-pre6/fs/proc/proc_misc.c Sun Nov 18 10:41:35 2001
+++ linux-2.4.15-pre6-jiffies64/fs/proc/proc_misc.c Sun Nov 18 10:42:12 2001
@@ -40,6 +40,7 @@
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
+#include <asm/div64.h>
#define LOAD_INT(x) ((x) >> FSHIFT)
@@ -98,37 +99,59 @@
return proc_calc_metrics(page, start, off, count, eof, len);
}
+#if BITS_PER_LONG < 48
+
+u64 get_idle64(void)
+{
+ static unsigned long idle_hi, idle_last;
+ static spinlock_t idle64_lock = SPIN_LOCK_UNLOCKED;
+ unsigned long idle;
+
+ spin_lock(&idle64_lock);
+ idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
+ if (idle < idle_last) /* We have a wrap */
+ idle_hi++;
+ idle_last = idle;
+ spin_unlock(&idle64_lock);
+
+ return (idle | ((u64)idle_hi) << BITS_PER_LONG);
+}
+
+#else
+ /* Idle time won't overflow for 8716 years at HZ==1024 */
+
+static inline u64 get_idle64(void)
+{
+ return (u64)(init_tasks[0]->times.tms_utime
+ + init_tasks[0]->times.tms_stime);
+}
+
+#endif /* BITS_PER_LONG < 48 */
+
static int uptime_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- unsigned long uptime;
- unsigned long idle;
+ u64 uptime, idle;
+ unsigned long uptime_remainder, idle_remainder;
int len;
- uptime = jiffies;
- idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
+ uptime = get_jiffies64() - INITIAL_JIFFIES;
+ uptime_remainder = (unsigned long) do_div(uptime, HZ);
+ idle = get_idle64();
+ idle_remainder = (unsigned long) do_div(idle, HZ);
- /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
- that would overflow about every five days at HZ == 100.
- Therefore the identity a = (a / b) * b + a % b is used so that it is
- calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
- The part in front of the '+' always evaluates as 0 (mod 100). All divisions
- in the above formulas are truncating. For HZ being a power of 10, the
- calculations simplify to the version in the #else part (if the printf
- format is adapted to the same number of digits as zeroes in HZ.
- */
#if HZ!=100
len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- (((uptime % HZ) * 100) / HZ) % 100,
- idle / HZ,
- (((idle % HZ) * 100) / HZ) % 100);
+ (unsigned long) uptime,
+ (uptime_remainder * 100) / HZ,
+ (unsigned long) idle,
+ (idle_remainder * 100) / HZ);
#else
len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- uptime % HZ,
- idle / HZ,
- idle % HZ);
+ (unsigned long) uptime,
+ uptime_remainder,
+ (unsigned long) idle,
+ idle_remainder);
#endif
return proc_calc_metrics(page, start, off, count, eof, len);
}
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/include/linux/sched.h linux-2.4.15-pre6-jiffies64/include/linux/sched.h
--- linux-2.4.15-pre6/include/linux/sched.h Sun Nov 18 10:41:37 2001
+++ linux-2.4.15-pre6-jiffies64/include/linux/sched.h Sun Nov 18 11:41:06 2001
@@ -352,7 +352,7 @@
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
struct tms times;
- unsigned long start_time;
+ u64 start_time;
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
@@ -549,6 +549,8 @@
#include <asm/current.h>
extern unsigned long volatile jiffies;
+extern u64 get_jiffies64(void);
+
extern unsigned long itimer_ticks;
extern unsigned long itimer_next;
extern struct timeval xtime;
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/include/linux/timex.h linux-2.4.15-pre6-jiffies64/include/linux/timex.h
--- linux-2.4.15-pre6/include/linux/timex.h Mon Nov 5 21:42:13 2001
+++ linux-2.4.15-pre6-jiffies64/include/linux/timex.h Sun Nov 18 11:41:06 2001
@@ -53,6 +53,13 @@
#include <asm/param.h>
+#ifdef CONFIG_DEBUG_JIFFIESWRAP
+ /* Make the jiffies counter wrap around sooner. */
+# define INITIAL_JIFFIES ((unsigned long)(-300*HZ))
+#else
+# define INITIAL_JIFFIES 0
+#endif
+
/*
* The following defines establish the engineering parameters of the PLL
* model. The HZ variable establishes the timer interrupt frequency, 100 Hz
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/kernel/acct.c linux-2.4.15-pre6-jiffies64/kernel/acct.c
--- linux-2.4.15-pre6/kernel/acct.c Mon Mar 19 21:35:08 2001
+++ linux-2.4.15-pre6-jiffies64/kernel/acct.c Sun Nov 18 10:42:12 2001
@@ -56,6 +56,7 @@
#include <linux/tty.h>
#include <asm/uaccess.h>
+#include <asm/div64.h>
/*
* These constants control the amount of freespace that suspend and
@@ -227,20 +228,24 @@
* This routine has been adopted from the encode_comp_t() function in
* the kern_acct.c file of the FreeBSD operating system. The encoding
* is a 13-bit fraction with a 3-bit (base 8) exponent.
+ *
+ * Bumped up to encode 64 bit values. Unfortunately the result may
+ * overflow now.
*/
#define MANTSIZE 13 /* 13 bit mantissa. */
-#define EXPSIZE 3 /* Base 8 (3 bit) exponent. */
+#define EXPSIZE 3 /* 3 bit exponent. */
+#define EXPBASE 3 /* Base 8 (3 bit) exponent. */
#define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */
-static comp_t encode_comp_t(unsigned long value)
+static comp_t encode_comp_t(u64 value)
{
int exp, rnd;
exp = rnd = 0;
while (value > MAXFRACT) {
- rnd = value & (1 << (EXPSIZE - 1)); /* Round up? */
- value >>= EXPSIZE; /* Base 8 exponent == 3 bit shift. */
+ rnd = value & (1 << (EXPBASE - 1)); /* Round up? */
+ value >>= EXPBASE; /* Base 8 exponent == 3 bit shift. */
exp++;
}
@@ -248,16 +253,21 @@
* If we need to round up, do it (and handle overflow correctly).
*/
if (rnd && (++value > MAXFRACT)) {
- value >>= EXPSIZE;
+ value >>= EXPBASE;
exp++;
}
/*
* Clean it up and polish it off.
*/
- exp <<= MANTSIZE; /* Shift the exponent into place */
- exp += value; /* and add on the mantissa. */
- return exp;
+ if (exp >= (1 << EXPSIZE)) {
+ /* Overflow. Return largest representable number instead. */
+ return (1ul << (MANTSIZE + EXPSIZE)) - 1;
+ } else {
+ exp <<= MANTSIZE; /* Shift the exponent into place */
+ exp += value; /* and add on the mantissa. */
+ return exp;
+ }
}
/*
@@ -277,6 +287,7 @@
struct acct ac;
mm_segment_t fs;
unsigned long vsize;
+ u64 elapsed;
/*
* First check to see if there is enough free_space to continue
@@ -294,8 +305,10 @@
strncpy(ac.ac_comm, current->comm, ACCT_COMM);
ac.ac_comm[ACCT_COMM - 1] = '\0';
- ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
- ac.ac_etime = encode_comp_t(jiffies - current->start_time);
+ elapsed = get_jiffies64() - current->start_time;
+ ac.ac_etime = encode_comp_t(elapsed);
+ do_div(elapsed, HZ);
+ ac.ac_btime = xtime.tv_sec - elapsed;
ac.ac_utime = encode_comp_t(current->times.tms_utime);
ac.ac_stime = encode_comp_t(current->times.tms_stime);
ac.ac_uid = current->uid;
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/kernel/fork.c linux-2.4.15-pre6-jiffies64/kernel/fork.c
--- linux-2.4.15-pre6/kernel/fork.c Wed Oct 24 02:44:15 2001
+++ linux-2.4.15-pre6-jiffies64/kernel/fork.c Sun Nov 18 10:42:12 2001
@@ -647,7 +647,7 @@
}
#endif
p->lock_depth = -1; /* -1 = no lock */
- p->start_time = jiffies;
+ p->start_time = get_jiffies64();
INIT_LIST_HEAD(&p->local_pages);
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/kernel/info.c linux-2.4.15-pre6-jiffies64/kernel/info.c
--- linux-2.4.15-pre6/kernel/info.c Sat Apr 21 01:15:40 2001
+++ linux-2.4.15-pre6-jiffies64/kernel/info.c Sun Nov 18 10:42:12 2001
@@ -12,15 +12,19 @@
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
+#include <asm/div64.h>
asmlinkage long sys_sysinfo(struct sysinfo *info)
{
struct sysinfo val;
+ u64 uptime;
memset((char *)&val, 0, sizeof(struct sysinfo));
cli();
- val.uptime = jiffies / HZ;
+ uptime = get_jiffies64() - INITIAL_JIFFIES;
+ do_div(uptime, HZ);
+ val.uptime = (unsigned long) uptime;
val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/kernel/timer.c linux-2.4.15-pre6-jiffies64/kernel/timer.c
--- linux-2.4.15-pre6/kernel/timer.c Mon Oct 8 19:41:41 2001
+++ linux-2.4.15-pre6-jiffies64/kernel/timer.c Sun Nov 18 12:34:16 2001
@@ -65,7 +65,7 @@
extern int do_setitimer(int, struct itimerval *, struct itimerval *);
-unsigned long volatile jiffies;
+unsigned long volatile jiffies = INITIAL_JIFFIES;
unsigned int * prof_buffer;
unsigned long prof_len;
@@ -103,6 +103,8 @@
#define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))
+static inline void init_jiffieswrap_timer(void);
+
void init_timervecs (void)
{
int i;
@@ -115,9 +117,19 @@
}
for (i = 0; i < TVR_SIZE; i++)
INIT_LIST_HEAD(tv1.vec + i);
+
+#ifdef CONFIG_DEBUG_JIFFIESWRAP
+ tv1.index = INITIAL_JIFFIES & TVR_MASK;
+ tv2.index = (INITIAL_JIFFIES >> TVR_BITS) & TVN_MASK;
+ tv3.index = (INITIAL_JIFFIES >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
+ tv4.index = (INITIAL_JIFFIES >> (TVR_BITS + 2*TVN_BITS)) & TVN_MASK;
+ tv5.index = (INITIAL_JIFFIES >> (TVR_BITS + 3*TVN_BITS)) & TVN_MASK;
+#endif
+
+ init_jiffieswrap_timer();
}
-static unsigned long timer_jiffies;
+static unsigned long timer_jiffies = INITIAL_JIFFIES;
static inline void internal_add_timer(struct timer_list *timer)
{
@@ -638,7 +650,7 @@
}
/* jiffies at the most recent update of wall time */
-unsigned long wall_jiffies;
+unsigned long wall_jiffies = INITIAL_JIFFIES;
/*
* This spinlock protect us from races in SMP while playing with xtime. -arca
@@ -683,6 +695,60 @@
if (TQ_ACTIVE(tq_timer))
mark_bh(TQUEUE_BH);
}
+
+
+#if BITS_PER_LONG < 48
+
+u64 get_jiffies64(void)
+{
+ static unsigned long jiffies_hi = 0;
+ static unsigned long jiffies_last = INITIAL_JIFFIES;
+ static spinlock_t jiffies64_lock = SPIN_LOCK_UNLOCKED;
+ unsigned long jiffies_tmp, flags;
+
+ spin_lock_irqsave(&jiffies64_lock, flags);
+ jiffies_tmp = jiffies; /* avoid races */
+ if (jiffies_tmp < jiffies_last) /* We have a wrap */
+ jiffies_hi++;
+ jiffies_last = jiffies_tmp;
+ spin_unlock_irqrestore(&jiffies64_lock, flags);
+
+ return (jiffies_tmp | ((u64)jiffies_hi) << BITS_PER_LONG);
+}
+
+/* use a timer to periodically check for jiffies overflows */
+
+static struct timer_list jiffieswrap_timer;
+#define CHECK_JIFFIESWRAP_INTERVAL 0x7ffffffful
+
+static void check_jiffieswrap(void)
+{
+ mod_timer(&jiffieswrap_timer, jiffies + CHECK_JIFFIESWRAP_INTERVAL);
+ get_jiffies64();
+}
+
+static inline void init_jiffieswrap_timer(void)
+{
+ init_timer(&jiffieswrap_timer);
+ jiffieswrap_timer.expires = jiffies + CHECK_JIFFIESWRAP_INTERVAL;
+ jiffieswrap_timer.function = check_jiffieswrap;
+ add_timer(&jiffieswrap_timer);
+}
+
+#else
+ /* jiffies is wide enough to not wrap for 8716 years at HZ==1024 */
+
+static inline u64 get_jiffies64(void)
+{
+ return (u64)jiffies;
+}
+
+static inline void init_jiffieswrap_timer(void)
+{
+}
+
+#endif /* BITS_PER_LONG < 48 */
+
#if !defined(__alpha__) && !defined(__ia64__)
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/mm/oom_kill.c linux-2.4.15-pre6-jiffies64/mm/oom_kill.c
--- linux-2.4.15-pre6/mm/oom_kill.c Sun Nov 4 02:05:25 2001
+++ linux-2.4.15-pre6-jiffies64/mm/oom_kill.c Sun Nov 18 10:42:12 2001
@@ -69,11 +69,10 @@
/*
* CPU time is in seconds and run time is in minutes. There is no
* particular reason for this other than that it turned out to work
- * very well in practice. This is not safe against jiffie wraps
- * but we don't care _that_ much...
+ * very well in practice.
*/
cpu_time = (p->times.tms_utime + p->times.tms_stime) >> (SHIFT_HZ + 3);
- run_time = (jiffies - p->start_time) >> (SHIFT_HZ + 10);
+ run_time = (get_jiffies64() - p->start_time) >> (SHIFT_HZ + 10);
points /= int_sqrt(cpu_time);
points /= int_sqrt(int_sqrt(run_time));
On Sun, Nov 18, 2001 at 12:57:01PM +0100, Tim Schmielau wrote:
> [new patch further down]
>
> I extended the patch to use a counter for periodically checking for
> jiffies overflows, so none can go undetected anymore. Still the CPU time
> overhead is minimal as timer are implemented rather efficiently
>
I tried it, but it wouldn't apply cleanly (something in arch/arm
clashed). That didn't look too worrying, but compilation also failed:
make[1]: Leaving directory `/usr/src/linux-2.4.15pre6/arch/alpha/math-emu'
ld -static -T arch/alpha/vmlinux.lds -N arch/alpha/kernel/head.o init/main.o init/version.o \
--start-group \
arch/alpha/kernel/kernel.o arch/alpha/mm/mm.o kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o arch/alpha/math-emu/math-emu.o \
drivers/char/char.o drivers/block/block.o drivers/misc/misc.o drivers/net/net.o drivers/media/media.o drivers/ide/idedriver.
o drivers/scsi/scsidrv.o drivers/cdrom/driver.o drivers/sound/sounddrivers.o drivers/pci/driver.o drivers/video/video.o drivers/usb/u
sbdrv.o drivers/md/mddev.o \
net/network.o \
/usr/src/linux-2.4.15pre6/arch/alpha/lib/lib.a /usr/src/linux-2.4.15pre6/lib/lib.a /usr/src/linux-2.4.15pre6/arch/alpha/lib/l
ib.a \
--end-group \
-o vmlinux
kernel/kernel.o: In function `do_fork':
kernel/kernel.o(.text+0x3168): undefined reference to `get_jiffies64'
kernel/kernel.o(.text+0x316c): undefined reference to `get_jiffies64'
kernel/kernel.o: In function `sys_sysinfo':
kernel/kernel.o(.text+0x9c7c): undefined reference to `get_jiffies64'
kernel/kernel.o(.text+0x9c80): undefined reference to `get_jiffies64'
mm/mm.o: In function `badness':
mm/mm.o(.text+0x148b8): undefined reference to `get_jiffies64'
mm/mm.o(.text+0x148bc): more undefined references to `get_jiffies64' follow
make: *** [vmlinux] Error 1
alpha:/usr/src/linux#
This is on an Alpha, .config below.
Good luck,
Jurriaan
CONFIG_ALPHA=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
CONFIG_KMOD=y
CONFIG_ALPHA_MIATA=y
CONFIG_ISA=y
CONFIG_EISA=y
CONFIG_PCI=y
CONFIG_ALPHA_EV5=y
CONFIG_ALPHA_CIA=y
CONFIG_ALPHA_PYXIS=y
CONFIG_ALPHA_SRM=y
CONFIG_PCI_NAMES=y
CONFIG_NET=y
CONFIG_SYSVIPC=y
CONFIG_SYSCTL=y
CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
CONFIG_BLK_DEV_FD=y
CONFIG_BLK_DEV_LOOP=m
CONFIG_MD=y
CONFIG_BLK_DEV_MD=y
CONFIG_MD_RAID0=y
CONFIG_MD_RAID5=y
CONFIG_PACKET=y
CONFIG_NETLINK=y
CONFIG_RTNETLINK=y
CONFIG_NETFILTER=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_RTNETLINK=y
CONFIG_NETLINK=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_INET_ECN=y
CONFIG_SYN_COOKIES=y
CONFIG_IP_NF_CONNTRACK=m
CONFIG_IP_NF_FTP=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_NAT=m
CONFIG_IP_NF_NAT_NEEDED=y
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_NAT_FTP=m
CONFIG_IP_NF_COMPAT_IPCHAINS=y
CONFIG_IP_NF_NAT_NEEDED=y
CONFIG_IDE=y
CONFIG_BLK_DEV_IDE=y
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_IDEDISK_MULTI_MODE=y
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_BLK_DEV_IDEDMA_PCI=y
CONFIG_BLK_DEV_ADMA=y
CONFIG_IDEDMA_PCI_AUTO=y
CONFIG_BLK_DEV_IDEDMA=y
CONFIG_BLK_DEV_CMD64X=y
CONFIG_BLK_DEV_PDC202XX=y
CONFIG_PDC202XX_BURST=y
CONFIG_IDEDMA_AUTO=y
CONFIG_BLK_DEV_IDE_MODES=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_SYM53C8XX_2=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=m
CONFIG_NET_ETHERNET=y
CONFIG_NET_VENDOR_3COM=y
CONFIG_NET_PCI=y
CONFIG_TULIP=y
CONFIG_DE4X5=y
CONFIG_YELLOWFIN=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_UNIX98_PTYS=y
CONFIG_MOUSE=y
CONFIG_PSMOUSE=y
CONFIG_RTC=y
CONFIG_REISERFS_FS=y
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_ISO9660_FS=y
CONFIG_JOLIET=y
CONFIG_PROC_FS=y
CONFIG_DEVPTS_FS=y
CONFIG_EXT2_FS=y
CONFIG_UDF_FS=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_OSF_PARTITION=y
CONFIG_MSDOS_PARTITION=y
CONFIG_NLS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_VGA_CONSOLE=y
CONFIG_FB=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_MILLENIUM=y
CONFIG_FBCON_ADVANCED=y
CONFIG_FBCON_CFB4=y
CONFIG_FBCON_CFB8=y
CONFIG_FBCON_CFB16=y
CONFIG_FBCON_CFB24=y
CONFIG_FBCON_CFB32=y
CONFIG_FBCON_FONTS=y
CONFIG_FONT_SUN12x22=y
CONFIG_PCI_CONSOLE=y
CONFIG_SOUND=y
CONFIG_USB=y
CONFIG_USB_DEVICEFS=y
CONFIG_USB_OHCI=y
CONFIG_USB_STORAGE=y
CONFIG_USB_SCANNER=y
CONFIG_MATHEMU=y
CONFIG_MAGIC_SYSRQ=y
--
I am the burned out bulb you can not reach
Darkwing Duck
GNU/Linux 2.4.15-pre6 on Debian/Alpha 64-bits 988 bogomips load:2.54 1.76 0.82
On Sun, 18 Nov 2001, Jurriaan on Alpha wrote:
> On Sun, Nov 18, 2001 at 12:57:01PM +0100, Tim Schmielau wrote:
> > [new patch further down]
> >
> > I extended the patch to use a counter for periodically checking for
> > jiffies overflows, so none can go undetected anymore. Still the CPU time
> > overhead is minimal as timer are implemented rather efficiently
> >
> I tried it, but it wouldn't apply cleanly (something in arch/arm
> clashed). That didn't look too worrying, but compilation also failed:
>
[...]
> kernel/kernel.o: In function `do_fork':
> kernel/kernel.o(.text+0x3168): undefined reference to `get_jiffies64'
> kernel/kernel.o(.text+0x316c): undefined reference to `get_jiffies64'
> kernel/kernel.o: In function `sys_sysinfo':
> kernel/kernel.o(.text+0x9c7c): undefined reference to `get_jiffies64'
> kernel/kernel.o(.text+0x9c80): undefined reference to `get_jiffies64'
> mm/mm.o: In function `badness':
> mm/mm.o(.text+0x148b8): undefined reference to `get_jiffies64'
> mm/mm.o(.text+0x148bc): more undefined references to `get_jiffies64' follow
> make: *** [vmlinux] Error 1
> alpha:/usr/src/linux#
>
> This is on an Alpha, .config below.
Ack.
I thought it was a clever idea to delay the decision whether or not
to inline get_jiffies64 from the header file to the actual code, when
actually it was not.
Thank you for testing and spotting this even if the patch is of no use on
alpha.
New patch appended.
Tim
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/Documentation/Configure.help linux-2.4.15-pre6-jiffies64/Documentation/Configure.help
--- linux-2.4.15-pre6/Documentation/Configure.help Sun Nov 18 10:41:30 2001
+++ linux-2.4.15-pre6-jiffies64/Documentation/Configure.help Sun Nov 18 10:42:12 2001
@@ -23579,6 +23579,14 @@
of the BUG call as well as the EIP and oops trace. This aids
debugging but costs about 70-100K of memory.
+Debug jiffies counter wraparound (DANGEROUS)
+CONFIG_DEBUG_JIFFIESWRAP
+ Say Y here to initialize the jiffies counter to a value 5 minutes
+ before wraparound. This may make your system UNSTABLE and its
+ only use is to hunt down the causes of this instability.
+ If you don't know what the jiffies counter is or if you want
+ a stable system, say N.
+
Include kgdb kernel debugger
CONFIG_KGDB
Include in-kernel hooks for kgdb, the Linux kernel source level
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/arm/config.in linux-2.4.15-pre6-jiffies64/arch/arm/config.in
--- linux-2.4.15-pre6/arch/arm/config.in Sun Nov 18 10:41:30 2001
+++ linux-2.4.15-pre6-jiffies64/arch/arm/config.in Sun Nov 18 10:42:12 2001
@@ -601,6 +601,7 @@
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool 'Spinlock debugging' CONFIG_DEBUG_SPINLOCK
dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
# These options are only for real kernel hackers who want to get their hands dirty.
dep_bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_EXPERIMENTAL
dep_bool ' Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/cris/config.in linux-2.4.15-pre6-jiffies64/arch/cris/config.in
--- linux-2.4.15-pre6/arch/cris/config.in Mon Oct 15 22:42:14 2001
+++ linux-2.4.15-pre6-jiffies64/arch/cris/config.in Sun Nov 18 10:42:12 2001
@@ -250,4 +250,5 @@
if [ "$CONFIG_PROFILE" = "y" ]; then
int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
fi
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/i386/config.in linux-2.4.15-pre6-jiffies64/arch/i386/config.in
--- linux-2.4.15-pre6/arch/i386/config.in Sun Nov 18 10:41:30 2001
+++ linux-2.4.15-pre6-jiffies64/arch/i386/config.in Sun Nov 18 10:42:12 2001
@@ -407,6 +407,7 @@
bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
+ bool ' Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
fi
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/m68k/config.in linux-2.4.15-pre6-jiffies64/arch/m68k/config.in
--- linux-2.4.15-pre6/arch/m68k/config.in Tue Jun 12 04:15:27 2001
+++ linux-2.4.15-pre6-jiffies64/arch/m68k/config.in Sun Nov 18 10:42:12 2001
@@ -545,4 +545,5 @@
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/mips/config.in linux-2.4.15-pre6-jiffies64/arch/mips/config.in
--- linux-2.4.15-pre6/arch/mips/config.in Mon Oct 15 22:41:34 2001
+++ linux-2.4.15-pre6-jiffies64/arch/mips/config.in Sun Nov 18 10:42:12 2001
@@ -519,4 +519,5 @@
if [ "$CONFIG_SMP" != "y" ]; then
bool 'Run uncached' CONFIG_MIPS_UNCACHED
fi
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/parisc/config.in linux-2.4.15-pre6-jiffies64/arch/parisc/config.in
--- linux-2.4.15-pre6/arch/parisc/config.in Wed Apr 18 02:19:25 2001
+++ linux-2.4.15-pre6-jiffies64/arch/parisc/config.in Sun Nov 18 10:42:12 2001
@@ -206,5 +206,6 @@
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/ppc/config.in linux-2.4.15-pre6-jiffies64/arch/ppc/config.in
--- linux-2.4.15-pre6/arch/ppc/config.in Sun Nov 18 10:41:30 2001
+++ linux-2.4.15-pre6-jiffies64/arch/ppc/config.in Sun Nov 18 10:42:12 2001
@@ -392,4 +392,5 @@
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool 'Include kgdb kernel debugger' CONFIG_KGDB
bool 'Include xmon kernel debugger' CONFIG_XMON
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/sh/config.in linux-2.4.15-pre6-jiffies64/arch/sh/config.in
--- linux-2.4.15-pre6/arch/sh/config.in Mon Oct 15 22:36:48 2001
+++ linux-2.4.15-pre6-jiffies64/arch/sh/config.in Sun Nov 18 10:42:12 2001
@@ -385,4 +385,5 @@
if [ "$CONFIG_SH_STANDARD_BIOS" = "y" ]; then
bool 'Early printk support' CONFIG_SH_EARLY_PRINTK
fi
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/arch/sparc/config.in linux-2.4.15-pre6-jiffies64/arch/sparc/config.in
--- linux-2.4.15-pre6/arch/sparc/config.in Tue Jun 12 04:15:27 2001
+++ linux-2.4.15-pre6-jiffies64/arch/sparc/config.in Sun Nov 18 10:42:12 2001
@@ -265,4 +265,5 @@
comment 'Kernel hacking'
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Debug jiffies counter wraparound (DANGEROUS)' CONFIG_DEBUG_JIFFIESWRAP
endmenu
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/fs/proc/array.c linux-2.4.15-pre6-jiffies64/fs/proc/array.c
--- linux-2.4.15-pre6/fs/proc/array.c Thu Oct 11 18:00:01 2001
+++ linux-2.4.15-pre6-jiffies64/fs/proc/array.c Sun Nov 18 10:42:12 2001
@@ -343,7 +343,7 @@
ppid = task->pid ? task->p_opptr->pid : 0;
read_unlock(&tasklist_lock);
res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
-%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
+%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
task->pid,
task->comm,
@@ -366,7 +366,7 @@
nice,
0UL /* removed */,
task->it_real_value,
- task->start_time,
+ (unsigned long long)(task->start_time) - INITIAL_JIFFIES,
vsize,
mm ? mm->rss : 0, /* you might want to shift this left 3 */
task->rlim[RLIMIT_RSS].rlim_cur,
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/fs/proc/proc_misc.c linux-2.4.15-pre6-jiffies64/fs/proc/proc_misc.c
--- linux-2.4.15-pre6/fs/proc/proc_misc.c Sun Nov 18 10:41:35 2001
+++ linux-2.4.15-pre6-jiffies64/fs/proc/proc_misc.c Sun Nov 18 10:42:12 2001
@@ -40,6 +40,7 @@
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
+#include <asm/div64.h>
#define LOAD_INT(x) ((x) >> FSHIFT)
@@ -98,37 +99,59 @@
return proc_calc_metrics(page, start, off, count, eof, len);
}
+#if BITS_PER_LONG < 48
+
+u64 get_idle64(void)
+{
+ static unsigned long idle_hi, idle_last;
+ static spinlock_t idle64_lock = SPIN_LOCK_UNLOCKED;
+ unsigned long idle;
+
+ spin_lock(&idle64_lock);
+ idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
+ if (idle < idle_last) /* We have a wrap */
+ idle_hi++;
+ idle_last = idle;
+ spin_unlock(&idle64_lock);
+
+ return (idle | ((u64)idle_hi) << BITS_PER_LONG);
+}
+
+#else
+ /* Idle time won't overflow for 8716 years at HZ==1024 */
+
+static inline u64 get_idle64(void)
+{
+ return (u64)(init_tasks[0]->times.tms_utime
+ + init_tasks[0]->times.tms_stime);
+}
+
+#endif /* BITS_PER_LONG < 48 */
+
static int uptime_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- unsigned long uptime;
- unsigned long idle;
+ u64 uptime, idle;
+ unsigned long uptime_remainder, idle_remainder;
int len;
- uptime = jiffies;
- idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
+ uptime = get_jiffies64() - INITIAL_JIFFIES;
+ uptime_remainder = (unsigned long) do_div(uptime, HZ);
+ idle = get_idle64();
+ idle_remainder = (unsigned long) do_div(idle, HZ);
- /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
- that would overflow about every five days at HZ == 100.
- Therefore the identity a = (a / b) * b + a % b is used so that it is
- calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
- The part in front of the '+' always evaluates as 0 (mod 100). All divisions
- in the above formulas are truncating. For HZ being a power of 10, the
- calculations simplify to the version in the #else part (if the printf
- format is adapted to the same number of digits as zeroes in HZ.
- */
#if HZ!=100
len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- (((uptime % HZ) * 100) / HZ) % 100,
- idle / HZ,
- (((idle % HZ) * 100) / HZ) % 100);
+ (unsigned long) uptime,
+ (uptime_remainder * 100) / HZ,
+ (unsigned long) idle,
+ (idle_remainder * 100) / HZ);
#else
len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- uptime % HZ,
- idle / HZ,
- idle % HZ);
+ (unsigned long) uptime,
+ uptime_remainder,
+ (unsigned long) idle,
+ idle_remainder);
#endif
return proc_calc_metrics(page, start, off, count, eof, len);
}
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/include/linux/sched.h linux-2.4.15-pre6-jiffies64/include/linux/sched.h
--- linux-2.4.15-pre6/include/linux/sched.h Sun Nov 18 10:41:37 2001
+++ linux-2.4.15-pre6-jiffies64/include/linux/sched.h Sun Nov 18 23:08:34 2001
@@ -352,7 +352,7 @@
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
struct tms times;
- unsigned long start_time;
+ u64 start_time;
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
@@ -549,6 +549,18 @@
#include <asm/current.h>
extern unsigned long volatile jiffies;
+#if BITS_PER_LONG < 48
+# define NEEDS_JIFFIES64
+ extern u64 get_jiffies64(void);
+#else
+ /* jiffies is wide enough to not wrap for 8716 years at HZ==1024 */
+ static inline u64 get_jiffies64(void)
+ {
+ return (u64)jiffies;
+ }
+#endif
+
+
extern unsigned long itimer_ticks;
extern unsigned long itimer_next;
extern struct timeval xtime;
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/include/linux/timex.h linux-2.4.15-pre6-jiffies64/include/linux/timex.h
--- linux-2.4.15-pre6/include/linux/timex.h Mon Nov 5 21:42:13 2001
+++ linux-2.4.15-pre6-jiffies64/include/linux/timex.h Sun Nov 18 23:08:34 2001
@@ -53,6 +53,13 @@
#include <asm/param.h>
+#ifdef CONFIG_DEBUG_JIFFIESWRAP
+ /* Make the jiffies counter wrap around sooner. */
+# define INITIAL_JIFFIES ((unsigned long)(-300*HZ))
+#else
+# define INITIAL_JIFFIES 0
+#endif
+
/*
* The following defines establish the engineering parameters of the PLL
* model. The HZ variable establishes the timer interrupt frequency, 100 Hz
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/kernel/acct.c linux-2.4.15-pre6-jiffies64/kernel/acct.c
--- linux-2.4.15-pre6/kernel/acct.c Mon Mar 19 21:35:08 2001
+++ linux-2.4.15-pre6-jiffies64/kernel/acct.c Sun Nov 18 10:42:12 2001
@@ -56,6 +56,7 @@
#include <linux/tty.h>
#include <asm/uaccess.h>
+#include <asm/div64.h>
/*
* These constants control the amount of freespace that suspend and
@@ -227,20 +228,24 @@
* This routine has been adopted from the encode_comp_t() function in
* the kern_acct.c file of the FreeBSD operating system. The encoding
* is a 13-bit fraction with a 3-bit (base 8) exponent.
+ *
+ * Bumped up to encode 64 bit values. Unfortunately the result may
+ * overflow now.
*/
#define MANTSIZE 13 /* 13 bit mantissa. */
-#define EXPSIZE 3 /* Base 8 (3 bit) exponent. */
+#define EXPSIZE 3 /* 3 bit exponent. */
+#define EXPBASE 3 /* Base 8 (3 bit) exponent. */
#define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */
-static comp_t encode_comp_t(unsigned long value)
+static comp_t encode_comp_t(u64 value)
{
int exp, rnd;
exp = rnd = 0;
while (value > MAXFRACT) {
- rnd = value & (1 << (EXPSIZE - 1)); /* Round up? */
- value >>= EXPSIZE; /* Base 8 exponent == 3 bit shift. */
+ rnd = value & (1 << (EXPBASE - 1)); /* Round up? */
+ value >>= EXPBASE; /* Base 8 exponent == 3 bit shift. */
exp++;
}
@@ -248,16 +253,21 @@
* If we need to round up, do it (and handle overflow correctly).
*/
if (rnd && (++value > MAXFRACT)) {
- value >>= EXPSIZE;
+ value >>= EXPBASE;
exp++;
}
/*
* Clean it up and polish it off.
*/
- exp <<= MANTSIZE; /* Shift the exponent into place */
- exp += value; /* and add on the mantissa. */
- return exp;
+ if (exp >= (1 << EXPSIZE)) {
+ /* Overflow. Return largest representable number instead. */
+ return (1ul << (MANTSIZE + EXPSIZE)) - 1;
+ } else {
+ exp <<= MANTSIZE; /* Shift the exponent into place */
+ exp += value; /* and add on the mantissa. */
+ return exp;
+ }
}
/*
@@ -277,6 +287,7 @@
struct acct ac;
mm_segment_t fs;
unsigned long vsize;
+ u64 elapsed;
/*
* First check to see if there is enough free_space to continue
@@ -294,8 +305,10 @@
strncpy(ac.ac_comm, current->comm, ACCT_COMM);
ac.ac_comm[ACCT_COMM - 1] = '\0';
- ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
- ac.ac_etime = encode_comp_t(jiffies - current->start_time);
+ elapsed = get_jiffies64() - current->start_time;
+ ac.ac_etime = encode_comp_t(elapsed);
+ do_div(elapsed, HZ);
+ ac.ac_btime = xtime.tv_sec - elapsed;
ac.ac_utime = encode_comp_t(current->times.tms_utime);
ac.ac_stime = encode_comp_t(current->times.tms_stime);
ac.ac_uid = current->uid;
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/kernel/fork.c linux-2.4.15-pre6-jiffies64/kernel/fork.c
--- linux-2.4.15-pre6/kernel/fork.c Wed Oct 24 02:44:15 2001
+++ linux-2.4.15-pre6-jiffies64/kernel/fork.c Sun Nov 18 10:42:12 2001
@@ -647,7 +647,7 @@
}
#endif
p->lock_depth = -1; /* -1 = no lock */
- p->start_time = jiffies;
+ p->start_time = get_jiffies64();
INIT_LIST_HEAD(&p->local_pages);
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/kernel/info.c linux-2.4.15-pre6-jiffies64/kernel/info.c
--- linux-2.4.15-pre6/kernel/info.c Sat Apr 21 01:15:40 2001
+++ linux-2.4.15-pre6-jiffies64/kernel/info.c Sun Nov 18 10:42:12 2001
@@ -12,15 +12,19 @@
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
+#include <asm/div64.h>
asmlinkage long sys_sysinfo(struct sysinfo *info)
{
struct sysinfo val;
+ u64 uptime;
memset((char *)&val, 0, sizeof(struct sysinfo));
cli();
- val.uptime = jiffies / HZ;
+ uptime = get_jiffies64() - INITIAL_JIFFIES;
+ do_div(uptime, HZ);
+ val.uptime = (unsigned long) uptime;
val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/kernel/timer.c linux-2.4.15-pre6-jiffies64/kernel/timer.c
--- linux-2.4.15-pre6/kernel/timer.c Mon Oct 8 19:41:41 2001
+++ linux-2.4.15-pre6-jiffies64/kernel/timer.c Sun Nov 18 23:05:12 2001
@@ -65,7 +65,7 @@
extern int do_setitimer(int, struct itimerval *, struct itimerval *);
-unsigned long volatile jiffies;
+unsigned long volatile jiffies = INITIAL_JIFFIES;
unsigned int * prof_buffer;
unsigned long prof_len;
@@ -103,6 +103,8 @@
#define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))
+static inline void init_jiffieswrap_timer(void);
+
void init_timervecs (void)
{
int i;
@@ -115,9 +117,19 @@
}
for (i = 0; i < TVR_SIZE; i++)
INIT_LIST_HEAD(tv1.vec + i);
+
+#ifdef CONFIG_DEBUG_JIFFIESWRAP
+ tv1.index = INITIAL_JIFFIES & TVR_MASK;
+ tv2.index = (INITIAL_JIFFIES >> TVR_BITS) & TVN_MASK;
+ tv3.index = (INITIAL_JIFFIES >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
+ tv4.index = (INITIAL_JIFFIES >> (TVR_BITS + 2*TVN_BITS)) & TVN_MASK;
+ tv5.index = (INITIAL_JIFFIES >> (TVR_BITS + 3*TVN_BITS)) & TVN_MASK;
+#endif
+
+ init_jiffieswrap_timer();
}
-static unsigned long timer_jiffies;
+static unsigned long timer_jiffies = INITIAL_JIFFIES;
static inline void internal_add_timer(struct timer_list *timer)
{
@@ -638,7 +650,7 @@
}
/* jiffies at the most recent update of wall time */
-unsigned long wall_jiffies;
+unsigned long wall_jiffies = INITIAL_JIFFIES;
/*
* This spinlock protect us from races in SMP while playing with xtime. -arca
@@ -683,6 +695,54 @@
if (TQ_ACTIVE(tq_timer))
mark_bh(TQUEUE_BH);
}
+
+
+#ifdef NEEDS_JIFFIES64
+
+u64 get_jiffies64(void)
+{
+ static unsigned long jiffies_hi = 0;
+ static unsigned long jiffies_last = INITIAL_JIFFIES;
+ static spinlock_t jiffies64_lock = SPIN_LOCK_UNLOCKED;
+ unsigned long jiffies_tmp, flags;
+
+ spin_lock_irqsave(&jiffies64_lock, flags);
+ jiffies_tmp = jiffies; /* avoid races */
+ if (jiffies_tmp < jiffies_last) /* We have a wrap */
+ jiffies_hi++;
+ jiffies_last = jiffies_tmp;
+ spin_unlock_irqrestore(&jiffies64_lock, flags);
+
+ return (jiffies_tmp | ((u64)jiffies_hi) << BITS_PER_LONG);
+}
+
+/* use a timer to periodically check for jiffies overflows */
+
+static struct timer_list jiffieswrap_timer;
+#define CHECK_JIFFIESWRAP_INTERVAL (1ul << (BITS_PER_LONG-2))
+
+static void check_jiffieswrap(unsigned long data)
+{
+ mod_timer(&jiffieswrap_timer, jiffies + CHECK_JIFFIESWRAP_INTERVAL);
+ get_jiffies64();
+}
+
+static inline void init_jiffieswrap_timer(void)
+{
+ init_timer(&jiffieswrap_timer);
+ jiffieswrap_timer.expires = jiffies + CHECK_JIFFIESWRAP_INTERVAL;
+ jiffieswrap_timer.function = check_jiffieswrap;
+ add_timer(&jiffieswrap_timer);
+}
+
+#else
+
+static inline void init_jiffieswrap_timer(void)
+{
+}
+
+#endif /* NEEDS_JIFFIES64 */
+
#if !defined(__alpha__) && !defined(__ia64__)
diff -u -r --exclude-from dontdiff linux-2.4.15-pre6/mm/oom_kill.c linux-2.4.15-pre6-jiffies64/mm/oom_kill.c
--- linux-2.4.15-pre6/mm/oom_kill.c Sun Nov 4 02:05:25 2001
+++ linux-2.4.15-pre6-jiffies64/mm/oom_kill.c Sun Nov 18 10:42:12 2001
@@ -69,11 +69,10 @@
/*
* CPU time is in seconds and run time is in minutes. There is no
* particular reason for this other than that it turned out to work
- * very well in practice. This is not safe against jiffie wraps
- * but we don't care _that_ much...
+ * very well in practice.
*/
cpu_time = (p->times.tms_utime + p->times.tms_stime) >> (SHIFT_HZ + 3);
- run_time = (jiffies - p->start_time) >> (SHIFT_HZ + 10);
+ run_time = (get_jiffies64() - p->start_time) >> (SHIFT_HZ + 10);
points /= int_sqrt(cpu_time);
points /= int_sqrt(int_sqrt(run_time));