diff -urNp --exclude CVS --exclude BitKeeper --exclude {arch} --exclude .arch-ids x-ref/arch/i386/kernel/irq.c x/arch/i386/kernel/irq.c --- x-ref/arch/i386/kernel/irq.c 2003-10-01 17:59:39.000000000 +0200 +++ x/arch/i386/kernel/irq.c 2003-10-01 18:03:02.000000000 +0200 @@ -560,6 +560,10 @@ void enable_irq(unsigned int irq) spin_unlock_irqrestore(&desc->lock, flags); } +#ifdef CONFIG_DEBUG_STACKOVERFLOW +int sysctl_stackwarn = 1024; +#endif + /* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific @@ -587,13 +591,17 @@ asmlinkage unsigned int do_IRQ(struct pt /* Debugging check for stack overflow: is there less than 1KB free? */ __asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (8191)); - if (unlikely(esp < (sizeof(struct task_struct) + 1024))) { - extern void show_stack(unsigned long *); - - printk("do_IRQ: stack overflow: %ld\n", - esp - sizeof(struct task_struct)); - __asm__ __volatile__("movl %%esp,%0" : "=r" (esp)); - show_stack((void *)esp); + if (unlikely(esp < (sizeof(struct task_struct) + sysctl_stackwarn))) { + static unsigned long next_jiffies; /* ratelimiting */ + static long least_esp = THREAD_SIZE; + + if (time_after(jiffies, next_jiffies) || (esp < least_esp)) { + least_esp = esp; + next_jiffies = jiffies + 5*HZ; + printk("WARNING: do_IRQ: near stack overflow: %ld\n", + esp - sizeof(struct task_struct)); + dump_stack(); + } } #endif diff -urNp --exclude CVS --exclude BitKeeper --exclude {arch} --exclude .arch-ids x-ref/arch/i386/kernel/traps.c x/arch/i386/kernel/traps.c --- x-ref/arch/i386/kernel/traps.c 2003-10-01 17:59:39.000000000 +0200 +++ x/arch/i386/kernel/traps.c 2003-10-01 18:03:02.000000000 +0200 @@ -202,21 +202,27 @@ void show_trace(unsigned long * stack) { int i; unsigned long addr; + unsigned long *prev = NULL; if (!stack) stack = (unsigned long*)&stack; - printk("Call Trace: "); + printk("Call Trace: "); i = 1; while (((long) stack & (THREAD_SIZE-1)) != 0) { addr = *stack++; if (kernel_text_address(addr)) { - if (i && ((i % 6) == 0)) + if (prev) + printk(" (%02d)", (stack-prev)*sizeof(*stack)); + prev = stack; + if ((i % 4) == 0) printk("\n "); printk(" [<%08lx>]", addr); i++; } } + if (prev) + printk(" (%02d)", (stack-prev)*sizeof(*stack)); printk("\n"); } @@ -259,6 +265,7 @@ void show_stack(unsigned long * esp) void dump_stack(void) { show_stack(0); + printk("Code: <0>\n"); /* tell ksymoops trace ends here */ } void show_registers(struct pt_regs *regs) diff -urNp --exclude CVS --exclude BitKeeper --exclude {arch} --exclude .arch-ids x-ref/arch/x86_64/kernel/irq.c x/arch/x86_64/kernel/irq.c --- x-ref/arch/x86_64/kernel/irq.c 2003-10-01 17:59:43.000000000 +0200 +++ x/arch/x86_64/kernel/irq.c 2003-10-01 18:03:02.000000000 +0200 @@ -47,6 +47,8 @@ #include #ifdef CONFIG_DEBUG_STACKOVERFLOW +int sysctl_stackwarn = 128; + /* * Probalistic stack overflow check: * @@ -66,7 +68,7 @@ static inline void stack_overflow_check( } if (regs->rsp >= curbase && regs->rsp <= curbase + THREAD_SIZE && - regs->rsp < curbase + sizeof(struct task_struct) + 128 && + regs->rsp < curbase + sizeof(struct task_struct) + sysctl_stackwarn && warned + 60*HZ >= jiffies) { printk("do_IRQ: %s near stack overflow (cur:%Lx,rsp:%lx)\n", current->comm, curbase, regs->rsp); diff -urNp --exclude CVS --exclude BitKeeper --exclude {arch} --exclude .arch-ids x-ref/include/linux/sysctl.h x/include/linux/sysctl.h --- x-ref/include/linux/sysctl.h 2003-10-01 17:59:43.000000000 +0200 +++ x/include/linux/sysctl.h 2003-10-01 18:03:19.000000000 +0200 @@ -135,6 +135,8 @@ enum KERN_MAXTIMESLICE=62, /* int: nice -20 max timeslice */ KERN_MINTIMESLICE=63, /* int: nice +19 min timeslice */ KERN_HZ=64, /* unsigned long: interal kernel HZ */ + KERN_STACKWARN=65, /* int: do_IRQ warn when stackspace is less */ + KERN_STACKDEFER=66, /* int: do_softirq defer if stackspace less */ }; diff -urNp --exclude CVS --exclude BitKeeper --exclude {arch} --exclude .arch-ids x-ref/kernel/softirq.c x/kernel/softirq.c --- x-ref/kernel/softirq.c 2003-10-01 17:59:40.000000000 +0200 +++ x/kernel/softirq.c 2003-10-01 18:03:48.000000000 +0200 @@ -18,6 +18,15 @@ #include #include +#if !defined(CONFIG_PARISC) && \ + !defined(CONFIG_ARCH_S390) && !defined(CONFIG_X86_64) + +#define DEBUG_DUMP_DEEP_STACK 0 + +int sysctl_stackdefer = 80 * BITS_PER_LONG; + +#endif + /* - No shared variables, all the data are CPU local. - If a softirq needs serialization, let it serialize itself @@ -97,6 +106,33 @@ asmlinkage void do_softirq(void) if (pending) { struct softirq_action *h; +#if !defined(CONFIG_PARISC) && \ + !defined(CONFIG_ARCH_S390) && !defined(CONFIG_X86_64) + { + unsigned long esp = (unsigned long) &esp; + unsigned long tsk = (unsigned long) current; + + if (unlikely(esp < tsk + sizeof(struct task_struct) + + sysctl_stackdefer) && esp >= tsk && + tsk != (unsigned long) ksoftirqd_task(cpu)) { +#if DEBUG_DUMP_DEEP_STACK + static unsigned long next_jiffies; + if (time_after(jiffies, next_jiffies)) { + next_jiffies = jiffies + 5*HZ; + printk("WARNING: do_softirq: " + "deferring from stack at %ld\n", + esp-tsk-sizeof(struct task_struct)); + dump_stack(); + } +#endif /* DEBUG_DUMP_DEEP_STACK */ + + wakeup_softirqd(cpu); + local_irq_restore(flags); + return; + } + } +#endif /* !CONFIG_PARISC !CONFIG_ARCH_S390 !CONFIG_X86_64 */ + mask = ~pending; local_bh_disable(); restart: diff -urNp --exclude CVS --exclude BitKeeper --exclude {arch} --exclude .arch-ids x-ref/kernel/sysctl.c x/kernel/sysctl.c --- x-ref/kernel/sysctl.c 2003-10-01 17:59:43.000000000 +0200 +++ x/kernel/sysctl.c 2003-10-01 18:04:40.000000000 +0200 @@ -100,6 +100,14 @@ extern int sysctl_ieee_emulation_warning extern int sysctl_userprocess_debug; #endif +#ifdef CONFIG_DEBUG_STACKOVERFLOW +extern int sysctl_stackwarn; +#endif +#if !defined(CONFIG_PARISC) && \ + !defined(CONFIG_ARCH_S390) && !defined(CONFIG_X86_64) +extern int sysctl_stackdefer; +#endif + #ifdef CONFIG_PPC32 extern unsigned long zero_paged_on, powersave_nap; int proc_dol2crvec(ctl_table *table, int write, struct file *filp, @@ -298,6 +306,15 @@ static ctl_table kern_table[] = { &min_timeslice,sizeof(int),0644,NULL,&proc_dointvec}, {KERN_HZ, "HZ", &__HZ, sizeof(unsigned long),0444,NULL,&proc_doulongvec_minmax}, +#ifdef CONFIG_DEBUG_STACKOVERFLOW + {KERN_STACKWARN, "stackwarn", &sysctl_stackwarn, sizeof(int), + 0644, NULL, &proc_dointvec}, +#endif +#if !defined(CONFIG_PARISC) && \ + !defined(CONFIG_ARCH_S390) && !defined(CONFIG_X86_64) + {KERN_STACKDEFER, "stackdefer", &sysctl_stackdefer, sizeof(int), + 0644, NULL, &proc_dointvec}, +#endif {0} };