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 <asm/proto.h>
 
 #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 <linux/tqueue.h>
 #include <linux/profiler.h>
 
+#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}
 };