linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] (1/3) cleanup thread info on x86
@ 2002-10-31 19:18 David C. Hansen
  2002-10-31 19:20 ` [PATCH] (2/3) per-cpu interrupt stacks for x86 David C. Hansen
  2002-10-31 19:20 ` [PATCH] (3/3) stack overflow checking " David C. Hansen
  0 siblings, 2 replies; 10+ messages in thread
From: David C. Hansen @ 2002-10-31 19:18 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: lkml

[-- Attachment #1: Type: text/plain, Size: 442 bytes --]

These patches have been in Alan's tree for the last week with no
problems.

This is a port of work Ben LaHaise did around 2.5.20 time.  I split it
up and updated it for the new preempt_count semantics.

* clean thread info infrastructure (1/3)
   - take out all instances of things like (8191&esp) to get
     current stack address.

Has a few unused things that will be used in the following two patches.
-- 
Dave Hansen
haveblue@us.ibm.com

[-- Attachment #2: A-thread_info_cleanup-2.5.45-4.patch --]
[-- Type: text/plain, Size: 5035 bytes --]

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.855   -> 1.856  
#	arch/i386/kernel/head.S	1.17    -> 1.18   
#	include/asm-i386/thread_info.h	1.7     -> 1.8    
#	include/asm-i386/page.h	1.19    -> 1.20   
#	arch/i386/kernel/entry.S	1.37.1.2 -> 1.38.2.1
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/31	haveblue@elm3b96.(none)	1.856
# Merge elm3b96.(none):/work/dave/bk/linux-2.5
# into elm3b96.(none):/work/dave/bk/linux-2.5-thread_info_infra
# --------------------------------------------
#
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Thu Oct 31 11:10:55 2002
+++ b/arch/i386/kernel/entry.S	Thu Oct 31 11:10:55 2002
@@ -136,7 +136,7 @@
 	movl %ecx,CS(%esp)	#
 	movl %esp, %ebx
 	pushl %ebx
-	andl $-8192, %ebx	# GET_THREAD_INFO
+	GET_THREAD_INFO_WITH_ESP(%ebx)	# GET_THREAD_INFO
 	movl TI_EXEC_DOMAIN(%ebx), %edx	# Get the execution domain
 	movl 4(%edx), %edx	# Get the lcall7 handler for the domain
 	pushl $0x7
@@ -158,7 +158,7 @@
 	movl %ecx,CS(%esp)	#
 	movl %esp, %ebx
 	pushl %ebx
-	andl $-8192, %ebx	# GET_THREAD_INFO
+	GET_THREAD_INFO_WITH_ESP(%ebx)  # GET_THREAD_INFO
 	movl TI_EXEC_DOMAIN(%ebx), %edx	# Get the execution domain
 	movl 4(%edx), %edx	# Get the lcall7 handler for the domain
 	pushl $0x27
diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
--- a/arch/i386/kernel/head.S	Thu Oct 31 11:10:55 2002
+++ b/arch/i386/kernel/head.S	Thu Oct 31 11:10:55 2002
@@ -15,6 +15,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/desc.h>
+#include <asm/thread_info.h>
 
 #define OLD_CL_MAGIC_ADDR	0x90020
 #define OLD_CL_MAGIC		0xA33F
@@ -305,7 +306,7 @@
 	ret
 
 ENTRY(stack_start)
-	.long init_thread_union+8192
+	.long init_thread_union+THREAD_SIZE
 	.long __KERNEL_DS
 
 /* This is the default interrupt "handler" :-) */
diff -Nru a/include/asm-i386/page.h b/include/asm-i386/page.h
--- a/include/asm-i386/page.h	Thu Oct 31 11:10:55 2002
+++ b/include/asm-i386/page.h	Thu Oct 31 11:10:55 2002
@@ -3,7 +3,11 @@
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
-#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#ifndef __ASSEMBLY__
+#define PAGE_SIZE      (1UL << PAGE_SHIFT)
+#else
+#define PAGE_SIZE      (1 << PAGE_SHIFT)
+#endif
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 
 #define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
diff -Nru a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
--- a/include/asm-i386/thread_info.h	Thu Oct 31 11:10:55 2002
+++ b/include/asm-i386/thread_info.h	Thu Oct 31 11:10:55 2002
@@ -9,6 +9,7 @@
 
 #ifdef __KERNEL__
 
+#include <asm/page.h>
 #ifndef __ASSEMBLY__
 #include <asm/processor.h>
 #endif
@@ -54,10 +55,13 @@
  *
  * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
+#define THREAD_ORDER 1 
+#define INIT_THREAD_SIZE       THREAD_SIZE
+
 #ifndef __ASSEMBLY__
 #define INIT_THREAD_INFO(tsk)			\
 {						\
-	.task		= &tsk,			\
+	.task		= &tsk,         	\
 	.exec_domain	= &default_exec_domain,	\
 	.flags		= 0,			\
 	.cpu		= 0,			\
@@ -68,30 +72,36 @@
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_stack		(init_thread_union.stack)
 
+/* thread information allocation */
+#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
+#define alloc_thread_info() ((struct thread_info *) __get_free_pages(GFP_KERNEL,THREAD_ORDER))
+#define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER)
+#define get_thread_info(ti) get_task_struct((ti)->task)
+#define put_thread_info(ti) put_task_struct((ti)->task)
+
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
 {
 	struct thread_info *ti;
-	__asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~8191UL));
+	__asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~(THREAD_SIZE - 1)));
 	return ti;
 }
 
-/* thread information allocation */
-#define THREAD_SIZE (2*PAGE_SIZE)
-#define alloc_thread_info() ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
-#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
-#define get_thread_info(ti) get_task_struct((ti)->task)
-#define put_thread_info(ti) put_task_struct((ti)->task)
-
 #else /* !__ASSEMBLY__ */
 
+#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
+
 /* how to get the thread information struct from ASM */
 #define GET_THREAD_INFO(reg) \
-	movl $-8192, reg; \
+	movl $-THREAD_SIZE, reg; \
 	andl %esp, reg
 
-#endif
+/* use this one if reg already contains %esp */
+#define GET_THREAD_INFO_WITH_ESP(reg) \
+	andl $-THREAD_SIZE, reg
 
+#endif
+	 
 /*
  * thread information flags
  * - these are process state flags that various assembly files may need to access

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] (2/3) per-cpu interrupt stacks for x86
  2002-10-31 19:18 [PATCH] (1/3) cleanup thread info on x86 David C. Hansen
@ 2002-10-31 19:20 ` David C. Hansen
  2002-10-31 19:20 ` [PATCH] (3/3) stack overflow checking " David C. Hansen
  1 sibling, 0 replies; 10+ messages in thread
From: David C. Hansen @ 2002-10-31 19:20 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: lkml

[-- Attachment #1: Type: text/plain, Size: 316 bytes --]

* interrupt stacks (2/3)
   - allocate per-cpu interrupt stacks.  upon entry to
     common_interrupt, switch to the current cpu's stack.
   - inherit the interrupted task's preempt count, and pass
     back relevant task flags

Depends on the previously sent thread_info cleanup
-- 
Dave Hansen
haveblue@us.ibm.com

[-- Attachment #2: B-interrupt_stacks-2.5.45-4.patch --]
[-- Type: text/plain, Size: 7329 bytes --]

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.856   -> 1.857  
#	arch/i386/kernel/process.c	1.32    -> 1.32.1.1
#	arch/i386/kernel/irq.c	1.21.1.2 -> 1.23.1.1
#	include/asm-i386/thread_info.h	1.8     -> 1.10   
#	arch/i386/kernel/entry.S	1.38.2.1 -> 1.38.1.3
#	arch/i386/kernel/smpboot.c	1.36    -> 1.37   
#	arch/i386/kernel/init_task.c	1.6     -> 1.6.1.1
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/31	haveblue@elm3b96.(none)	1.857
# Merge
# --------------------------------------------
#
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Thu Oct 31 11:12:05 2002
+++ b/arch/i386/kernel/entry.S	Thu Oct 31 11:12:05 2002
@@ -334,7 +334,45 @@
 	ALIGN
 common_interrupt:
 	SAVE_ALL
+
+
+	GET_THREAD_INFO(%ebx)
+	movl TI_IRQ_STACK(%ebx),%ecx
+	movl TI_TASK(%ebx),%edx
+	movl %esp,%eax
+	leal (THREAD_SIZE-4)(%ecx),%esi # %ecx+THREAD_SIZE is next stack
+	                                # -4 keeps us in the right one
+	testl %ecx,%ecx                 # is there a valid irq_stack?
+
+	# switch to the irq stack
+#ifdef CONFIG_X86_HAVE_CMOV
+	cmovnz %esi,%esp
+#else
+	jz 1f
+	mov %esi,%esp
+1:
+#endif
+	
+	# update the task pointer in the irq stack
+	GET_THREAD_INFO(%esi)
+	movl %edx,TI_TASK(%esi)
+
+	# update the preempt count in the irq stack
+	movl TI_PRE_COUNT(%ebx),%ecx
+	movl %ecx,TI_PRE_COUNT(%esi)
+		
 	call do_IRQ
+
+	movl %eax,%esp                  # potentially restore non-irq stack
+	
+	# copy flags from the irq stack back into the task's thread_info
+	# %esi is saved over the do_IRQ call and contains the irq stack
+	# thread_info pointer
+	# %ebx contains the original thread_info pointer
+	movl TI_FLAGS(%esi),%eax
+	movl $0,TI_FLAGS(%esi)
+	LOCK orl %eax,TI_FLAGS(%ebx)
+
 	jmp ret_from_intr
 
 #define BUILD_INTERRUPT(name, nr)	\
diff -Nru a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c
--- a/arch/i386/kernel/init_task.c	Thu Oct 31 11:12:05 2002
+++ b/arch/i386/kernel/init_task.c	Thu Oct 31 11:12:05 2002
@@ -13,6 +13,10 @@
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 struct mm_struct init_mm = INIT_MM(init_mm);
 
+union thread_union init_irq_union
+	__attribute__((__section__(".data.init_task")));
+
+
 /*
  * Initial thread structure.
  *
diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
--- a/arch/i386/kernel/irq.c	Thu Oct 31 11:12:05 2002
+++ b/arch/i386/kernel/irq.c	Thu Oct 31 11:12:05 2002
@@ -311,7 +311,8 @@
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
-asmlinkage unsigned int do_IRQ(struct pt_regs regs)
+struct pt_regs *do_IRQ(struct pt_regs *regs) __attribute__((regparm(1)));
+struct pt_regs *do_IRQ(struct pt_regs *regs)
 {	
 	/* 
 	 * We ack quickly, we don't want the irq controller
@@ -323,7 +324,7 @@
 	 * 0 return value means that this irq is already being
 	 * handled by some other CPU. (or is disabled)
 	 */
-	int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code  */
+	int irq = regs->orig_eax & 0xff; /* high bits used in ret_from_ code  */
 	int cpu = smp_processor_id();
 	irq_desc_t *desc = irq_desc + irq;
 	struct irqaction * action;
@@ -388,7 +389,7 @@
 	 */
 	for (;;) {
 		spin_unlock(&desc->lock);
-		handle_IRQ_event(irq, &regs, action);
+		handle_IRQ_event(irq, regs, action);
 		spin_lock(&desc->lock);
 		
 		if (likely(!(desc->status & IRQ_PENDING)))
@@ -407,7 +408,7 @@
 
 	irq_exit();
 
-	return 1;
+	return regs;
 }
 
 /**
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c	Thu Oct 31 11:12:05 2002
+++ b/arch/i386/kernel/process.c	Thu Oct 31 11:12:05 2002
@@ -413,6 +413,7 @@
 
 	/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
 
+	next_p->thread_info->irq_stack = prev_p->thread_info->irq_stack;
 	unlazy_fpu(prev_p);
 
 	/*
diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
--- a/arch/i386/kernel/smpboot.c	Thu Oct 31 11:12:05 2002
+++ b/arch/i386/kernel/smpboot.c	Thu Oct 31 11:12:05 2002
@@ -70,6 +70,11 @@
 /* Per CPU bogomips and other parameters */
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
 
+/* Per CPU interrupt stacks */
+extern union thread_union init_irq_union;
+union thread_union *irq_stacks[NR_CPUS] __cacheline_aligned =
+	{ &init_irq_union, };
+
 /* Set when the idlers are all forked */
 int smp_threads_ready;
 
@@ -764,6 +769,28 @@
 	return (send_status | accept_status);
 }
 
+static void __init setup_irq_stack(struct task_struct *p, int cpu)
+{
+	unsigned long stk;
+
+	stk = __get_free_pages(GFP_KERNEL, THREAD_ORDER+1);
+	if (!stk)
+		panic("I can't seem to allocate my irq stack.  Oh well, giving up.");
+
+	irq_stacks[cpu] = (void *)stk;
+	memset(irq_stacks[cpu], 0, THREAD_SIZE);
+	irq_stacks[cpu]->thread_info.cpu = cpu;
+	irq_stacks[cpu]->thread_info.preempt_count = 1;
+					/* interrupts are not preemptable */
+	p->thread_info->irq_stack = irq_stacks[cpu];
+
+	/* If we want to make the irq stack more than one unit
+	 * deep, we can chain then off of the irq_stack pointer
+	 * here.
+	 */
+}
+
+
 extern unsigned long cpu_initialized;
 
 static void __init do_boot_cpu (int apicid) 
@@ -787,6 +814,8 @@
 	if (IS_ERR(idle))
 		panic("failed fork for CPU %d", cpu);
 
+	setup_irq_stack(idle, cpu);
+
 	/*
 	 * We remove it from the pidhash and the runqueue
 	 * once we got the process:
@@ -804,7 +833,13 @@
 
 	/* So we see what's up   */
 	printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
-	stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle->thread_info);
+
+	/* The -4 is to correct for the fact that the stack pointer
+	 * is used to find the location of the thread_info structure
+	 * by masking off several of the LSBs.  Without the -4, esp
+	 * is pointing to the page after the one the stack is on.
+	 */
+	stack_start.esp = (void *)(THREAD_SIZE - 4 + (char *)idle->thread_info);
 
 	/*
 	 * This grunge runs the startup process for
diff -Nru a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
--- a/include/asm-i386/thread_info.h	Thu Oct 31 11:12:05 2002
+++ b/include/asm-i386/thread_info.h	Thu Oct 31 11:12:05 2002
@@ -29,9 +29,11 @@
 	__s32			preempt_count; /* 0 => preemptable, <0 => BUG */
 
 	mm_segment_t		addr_limit;	/* thread address space:
+						   0 for interrupts: illegal
 					 	   0-0xBFFFFFFF for user-thead
 						   0-0xFFFFFFFF for kernel-thread
 						*/
+	struct thread_info	*irq_stack;	/* pointer to cpu irq stack */
 
 	__u8			supervisor_stack[0];
 };
@@ -45,6 +47,7 @@
 #define TI_CPU		0x0000000C
 #define TI_PRE_COUNT	0x00000010
 #define TI_ADDR_LIMIT	0x00000014
+#define TI_IRQ_STACK	0x00000018
 
 #endif
 
@@ -67,6 +70,7 @@
 	.cpu		= 0,			\
 	.preempt_count	= 1,			\
 	.addr_limit	= KERNEL_DS,		\
+	.irq_stack	= &init_irq_union	\
 }
 
 #define init_thread_info	(init_thread_union.thread_info)

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] (3/3) stack overflow checking for x86
  2002-10-31 19:18 [PATCH] (1/3) cleanup thread info on x86 David C. Hansen
  2002-10-31 19:20 ` [PATCH] (2/3) per-cpu interrupt stacks for x86 David C. Hansen
@ 2002-10-31 19:20 ` David C. Hansen
  2002-10-31 21:30   ` Dave Jones
  1 sibling, 1 reply; 10+ messages in thread
From: David C. Hansen @ 2002-10-31 19:20 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: lkml

[-- Attachment #1: Type: text/plain, Size: 424 bytes --]

* stack checking (3/3)
   - use gcc's profiling features to check for stack overflows upon
     entry to functions.
   - Warn if the task goes over 4k.
   - Panic if the stack gets within 512 bytes of overflowing.
   - use kksymoops information, if available

This won't apply cleanly without the irqstack patch, but the conflict is
easy to resolve.  It requires the thread_info cleanup.
-- 
Dave Hansen
haveblue@us.ibm.com

[-- Attachment #2: C-stack_usage_check-2.5.45-4.patch --]
[-- Type: text/plain, Size: 6119 bytes --]

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.857.1.1 -> 1.859  
#	arch/i386/kernel/process.c	1.32.1.1 -> 1.36   
#	arch/i386/kernel/irq.c	1.23.1.1 -> 1.25   
#	            Makefile	1.326.2.11 -> 1.329  
#	include/asm-i386/thread_info.h	1.10    -> 1.11   
#	arch/i386/kernel/entry.S	1.38.1.3 -> 1.46   
#	  arch/i386/Makefile	1.24.2.3 -> 1.27   
#	arch/i386/boot/compressed/misc.c	1.9     -> 1.10   
#	arch/i386/kernel/init_task.c	1.6.1.1 -> 1.8    
#	arch/i386/kernel/i386_ksyms.c	1.36.2.3 -> 1.39   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/31	haveblue@elm3b96.(none)	1.859
# Merge elm3b96.(none):/work/dave/bk/linux-2.5-irq-stack
# into elm3b96.(none):/work/dave/bk/linux-2.5-irq-stack+overflow-detect
# --------------------------------------------
#
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Thu Oct 31 11:13:28 2002
+++ b/Makefile	Thu Oct 31 11:13:28 2002
@@ -168,7 +168,8 @@
 
 CPPFLAGS	:= -D__KERNEL__ -Iinclude
 CFLAGS 		:= $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
-	  	   -fomit-frame-pointer -fno-strict-aliasing -fno-common
+	  	   -fno-strict-aliasing -fno-common
+
 AFLAGS		:= -D__ASSEMBLY__ $(CPPFLAGS)
 
 export	VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \
@@ -254,6 +255,10 @@
 
 ifdef CONFIG_MODULES
 export EXPORT_FLAGS := -DEXPORT_SYMTAB
+endif
+
+ifneq ($(CONFIG_FRAME_POINTER),y)
+CFLAGS          += -fomit-frame-pointer
 endif
 
 #
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile	Thu Oct 31 11:13:28 2002
+++ b/arch/i386/Makefile	Thu Oct 31 11:13:28 2002
@@ -51,6 +51,10 @@
 MACHINE	:= mach-generic
 endif
 
+ifdef CONFIG_X86_STACK_CHECK
+CFLAGS += -p
+endif
+
 HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
 libs-y 					+= arch/i386/lib/
diff -Nru a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
--- a/arch/i386/boot/compressed/misc.c	Thu Oct 31 11:13:28 2002
+++ b/arch/i386/boot/compressed/misc.c	Thu Oct 31 11:13:28 2002
@@ -377,3 +377,7 @@
 	if (high_loaded) close_output_buffer_if_we_run_high(mv);
 	return high_loaded;
 }
+
+/* We don't actually check for stack overflows this early. */
+__asm__(".globl mcount ; mcount: ret\n");
+
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Thu Oct 31 11:13:28 2002
+++ b/arch/i386/kernel/entry.S	Thu Oct 31 11:13:28 2002
@@ -519,6 +519,61 @@
 	pushl $do_spurious_interrupt_bug
 	jmp error_code
 
+
+#ifdef CONFIG_X86_STACK_CHECK
+.data
+	.globl	stack_overflowed
+stack_overflowed:
+	.long	0
+.text
+
+ENTRY(mcount)
+	push %eax
+	movl $(THREAD_SIZE - 1),%eax
+	andl %esp,%eax
+	cmpl $STACK_WARN,%eax	/* more than half the stack is used*/
+	jle 1f
+2:
+	popl %eax
+	ret
+1:	
+	lock;   btsl    $0,stack_overflowed
+	jc      2b
+	
+	# switch to overflow stack
+	movl	%esp,%eax
+	movl	$(stack_overflow_stack + THREAD_SIZE - 4),%esp
+
+	pushf
+	cli
+	pushl	%eax
+
+	# push eip then esp of error for stack_overflow_panic
+	pushl	4(%eax)
+	pushl	%eax
+
+	# update the task pointer and cpu in the overflow stack's thread_info.
+	GET_THREAD_INFO_WITH_ESP(%eax)
+	movl	TI_TASK(%eax),%ebx
+	movl	%ebx,stack_overflow_stack+TI_TASK
+	movl	TI_CPU(%eax),%ebx
+	movl	%ebx,stack_overflow_stack+TI_CPU
+
+	call	stack_overflow
+
+	# pop off call arguments
+	addl	$8,%esp 
+
+	popl	%eax
+	popf
+	movl	%eax,%esp
+	popl	%eax
+	movl	$0,stack_overflowed
+	ret
+
+#warning stack check enabled
+#endif
+
 .data
 ENTRY(sys_call_table)
 	.long sys_ni_syscall	/* 0 - old "setup()" system call*/
diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
--- a/arch/i386/kernel/i386_ksyms.c	Thu Oct 31 11:13:28 2002
+++ b/arch/i386/kernel/i386_ksyms.c	Thu Oct 31 11:13:28 2002
@@ -211,3 +211,8 @@
 EXPORT_SYMBOL(edd);
 EXPORT_SYMBOL(eddnr);
 #endif
+
+#ifdef CONFIG_X86_STACK_CHECK
+extern void mcount(void);
+EXPORT_SYMBOL(mcount);
+#endif
diff -Nru a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c
--- a/arch/i386/kernel/init_task.c	Thu Oct 31 11:13:28 2002
+++ b/arch/i386/kernel/init_task.c	Thu Oct 31 11:13:28 2002
@@ -16,6 +16,10 @@
 union thread_union init_irq_union
 	__attribute__((__section__(".data.init_task")));
 
+#ifdef CONFIG_X86_STACK_CHECK
+union thread_union stack_overflow_stack
+	__attribute__((__section__(".data.init_task")));
+#endif
 
 /*
  * Initial thread structure.
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c	Thu Oct 31 11:13:28 2002
+++ b/arch/i386/kernel/process.c	Thu Oct 31 11:13:28 2002
@@ -156,7 +156,25 @@
 
 __setup("idle=", idle_setup);
 
-void show_regs(struct pt_regs * regs)
+void stack_overflow(unsigned long esp, unsigned long eip)
+{
+	int panicing = ((esp&(THREAD_SIZE-1)) <= STACK_PANIC);
+
+	printk( "esp: 0x%x masked: 0x%x STACK_PANIC:0x%x %d %d\n", 
+		esp, (esp&(THREAD_SIZE-1)), STACK_PANIC, (((esp&(THREAD_SIZE-1)) <= STACK_PANIC)), panicing );
+	
+	if (panicing)
+		print_symbol("stack overflow from %s\n", eip);
+	else
+		print_symbol("excessive stack use from %s\n", eip);
+	printk("esp: %p\n", (void*)esp);
+	show_trace((void*)esp);
+	
+	if (panicing)
+		panic("stack overflow\n");
+}
+
+asmlinkage void show_regs(struct pt_regs * regs)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
 
diff -Nru a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
--- a/include/asm-i386/thread_info.h	Thu Oct 31 11:13:28 2002
+++ b/include/asm-i386/thread_info.h	Thu Oct 31 11:13:28 2002
@@ -60,6 +60,8 @@
  */
 #define THREAD_ORDER 1 
 #define INIT_THREAD_SIZE       THREAD_SIZE
+#define STACK_PANIC		0x200ul
+#define STACK_WARN		((THREAD_SIZE)>>1)
 
 #ifndef __ASSEMBLY__
 #define INIT_THREAD_INFO(tsk)			\

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] (3/3) stack overflow checking for x86
  2002-10-31 19:20 ` [PATCH] (3/3) stack overflow checking " David C. Hansen
@ 2002-10-31 21:30   ` Dave Jones
  2002-10-31 22:08     ` David C. Hansen
  2002-11-01 12:59     ` Alan Cox
  0 siblings, 2 replies; 10+ messages in thread
From: Dave Jones @ 2002-10-31 21:30 UTC (permalink / raw)
  To: David C. Hansen; +Cc: Linus Torvalds, lkml

On Thu, Oct 31, 2002 at 11:20:52AM -0800, David C. Hansen wrote:
 > * stack checking (3/3)
 >    - use gcc's profiling features to check for stack overflows upon
 >      entry to functions.
 >    - Warn if the task goes over 4k.
 >    - Panic if the stack gets within 512 bytes of overflowing.
 >    - use kksymoops information, if available
 > 
 > This won't apply cleanly without the irqstack patch, but the conflict is
 > easy to resolve.  It requires the thread_info cleanup.

I'm wondering about interaction between this patch and the
already merged CONFIG_DEBUG_STACKOVERFLOW ?

		Dave

-- 
| Dave Jones.        http://www.codemonkey.org.uk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] (3/3) stack overflow checking for x86
  2002-10-31 21:30   ` Dave Jones
@ 2002-10-31 22:08     ` David C. Hansen
  2002-11-01 12:59     ` Alan Cox
  1 sibling, 0 replies; 10+ messages in thread
From: David C. Hansen @ 2002-10-31 22:08 UTC (permalink / raw)
  To: Dave Jones; +Cc: Linus Torvalds, lkml

On Thu, 2002-10-31 at 13:30, Dave Jones wrote:
> On Thu, Oct 31, 2002 at 11:20:52AM -0800, David C. Hansen wrote:
>  > * stack checking (3/3)
>  >    - use gcc's profiling features to check for stack overflows upon
>  >      entry to functions.
>  >    - Warn if the task goes over 4k.
>  >    - Panic if the stack gets within 512 bytes of overflowing.
>  >    - use kksymoops information, if available
>  > 
>  > This won't apply cleanly without the irqstack patch, but the conflict is
>  > easy to resolve.  It requires the thread_info cleanup.
> 
> I'm wondering about interaction between this patch and the
> already merged CONFIG_DEBUG_STACKOVERFLOW ?

The currently merged one is very, very simple, but relatively worthless.
There are no guarantees about catching an overflow, especially if it
happens in a long call chain _after_ do_IRQ with interrupts disabled.  
Ben's version checks on entrance to every function, making it _much_
more likely to be caught, even during an interrupt.  But, the currently
merged one doesn't have any strange compiler requirements, like adding
the -p option.

The irq stack patch would make the current check pretty worthless
because the check happens just after the switch to a fresh irqstack
would have happened.

But, if they both get in, it can be cleaned up later because even if
both are turned on, nothing will blow up.  
-- 
Dave Hansen
haveblue@us.ibm.com


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] (3/3) stack overflow checking for x86
  2002-10-31 21:30   ` Dave Jones
  2002-10-31 22:08     ` David C. Hansen
@ 2002-11-01 12:59     ` Alan Cox
  2002-11-01 13:42       ` Dave Jones
  1 sibling, 1 reply; 10+ messages in thread
From: Alan Cox @ 2002-11-01 12:59 UTC (permalink / raw)
  To: Dave Jones; +Cc: David C. Hansen, Linus Torvalds, lkml

On Thu, 2002-10-31 at 21:30, Dave Jones wrote:
>  > This won't apply cleanly without the irqstack patch, but the conflict is
>  > easy to resolve.  It requires the thread_info cleanup.
> 
> I'm wondering about interaction between this patch and the
> already merged CONFIG_DEBUG_STACKOVERFLOW ?

It replaces it and actually makes it useful since IRQ usage is now
bounded and defined relative to non IRQ usage. Without IRQ stacks you
don't have a hope in hell of catching overflows that depend on an irq
occuring at the right moment


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] (3/3) stack overflow checking for x86
  2002-11-01 12:59     ` Alan Cox
@ 2002-11-01 13:42       ` Dave Jones
  0 siblings, 0 replies; 10+ messages in thread
From: Dave Jones @ 2002-11-01 13:42 UTC (permalink / raw)
  To: Alan Cox; +Cc: David C. Hansen, Linus Torvalds, lkml

On Fri, Nov 01, 2002 at 12:59:06PM +0000, Alan Cox wrote:
 > On Thu, 2002-10-31 at 21:30, Dave Jones wrote:
 > >  > This won't apply cleanly without the irqstack patch, but the conflict is
 > >  > easy to resolve.  It requires the thread_info cleanup.
 > > 
 > > I'm wondering about interaction between this patch and the
 > > already merged CONFIG_DEBUG_STACKOVERFLOW ?
 > 
 > It replaces it and actually makes it useful since IRQ usage is now
 > bounded and defined relative to non IRQ usage. Without IRQ stacks you
 > don't have a hope in hell of catching overflows that depend on an irq
 > occuring at the right moment

 Yeah, I figured it worked better, but wondered why the patch didn't
 remove the existing implementation.

		Dave

-- 
| Dave Jones.        http://www.codemonkey.org.uk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] (3/3) stack overflow checking for x86
  2002-10-18 22:31 ` Dave Hansen
@ 2002-10-18 22:48   ` Andreas Dilger
  0 siblings, 0 replies; 10+ messages in thread
From: Andreas Dilger @ 2002-10-18 22:48 UTC (permalink / raw)
  To: Dave Hansen; +Cc: Linus Torvalds, linux-kernel

On Oct 18, 2002  15:31 -0700, Dave Hansen wrote:
> Greg KH just pointed out that someone else snuck in an overflow check. 
>  However, they take completely different approaches.  The Ben LaHaise 
> one that I posted uses GCC features to check the stack on entry to all 
> functions.  The one in the tree now is much, much simpler than Ben's, 
> but only works only for detecting problems at the time that an 
> interrupt actually occurs.

Yes, we had that patch in the RH 2.4 kernel, but it didn't detect the
stack overflow we spent days to track.  Our problem was just one of
a really deep stack: RPC-to-network-filesystem-on-ext3-with-htree.
This overflowed the 8kB stack even without an interrupt happening.

We fixed the htree and the network filesystem stack usage, but if we
added LVM/EVMS into the mix (which we would have in production) and
threw in a piggy interrupt handler we would possibly again overflow
an 8kB stack, so having a per-entry/exit stack checker would be great.

Cheers, Andreas
--
Andreas Dilger
http://www-mddsp.enel.ucalgary.ca/People/adilger/
http://sourceforge.net/projects/ext2resize/


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] (3/3) stack overflow checking for x86
  2002-10-18 22:07 Dave Hansen
@ 2002-10-18 22:31 ` Dave Hansen
  2002-10-18 22:48   ` Andreas Dilger
  0 siblings, 1 reply; 10+ messages in thread
From: Dave Hansen @ 2002-10-18 22:31 UTC (permalink / raw)
  To: Dave Hansen; +Cc: Linus Torvalds, linux-kernel

Dave Hansen wrote:
> * stack checking (3/3)
>    - use gcc's profiling features to check for stack overflows upon
>      entry to functions.
>    - Warn if the task goes over 4k.
>    - Panic if the stack gets within 512 bytes of overflowing.
>    - use kksymoops information, if available
> 
> This won't apply cleanly without the irqstack patch, but the conflict is 
> easy to resolve.  It requires the thread_info cleanup.

Greg KH just pointed out that someone else snuck in an overflow check. 
  However, they take completely different approaches.  The Ben LaHaise 
one that I posted uses GCC features to check the stack on entry to all 
functions.  The one in the tree now is much, much simpler than Ben's, 
but only works only for detecting problems at the time that an 
interrupt actually occurs.

-- 
Dave Hansen
haveblue@us.ibm.com


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] (3/3) stack overflow checking for x86
@ 2002-10-18 22:07 Dave Hansen
  2002-10-18 22:31 ` Dave Hansen
  0 siblings, 1 reply; 10+ messages in thread
From: Dave Hansen @ 2002-10-18 22:07 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 430 bytes --]

* stack checking (3/3)
    - use gcc's profiling features to check for stack overflows upon
      entry to functions.
    - Warn if the task goes over 4k.
    - Panic if the stack gets within 512 bytes of overflowing.
    - use kksymoops information, if available

This won't apply cleanly without the irqstack patch, but the conflict 
is easy to resolve.  It requires the thread_info cleanup.
-- 
Dave Hansen
haveblue@us.ibm.com

[-- Attachment #2: C-stack_usage_check-2.5.43+bk-1.patch --]
[-- Type: text/plain, Size: 7667 bytes --]

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.858.1.2 -> 1.863  
#	arch/i386/kernel/process.c	1.32.1.1 -> 1.36   
#	arch/i386/Config.help	1.21.1.2 -> 1.24   
#	            Makefile	1.320.1.1 -> 1.322  
#	include/asm-i386/thread_info.h	1.10    -> 1.11   
#	arch/i386/kernel/entry.S	1.38.1.2 -> 1.45   
#	 arch/i386/config.in	1.56.1.4 -> 1.59   
#	  arch/i386/Makefile	1.21.1.1 -> 1.23   
#	arch/i386/boot/compressed/misc.c	1.9     -> 1.10   
#	arch/i386/kernel/init_task.c	1.6.1.1 -> 1.8    
#	arch/i386/kernel/i386_ksyms.c	1.34.1.2 -> 1.36   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/16	haveblue@elm3b96.(none)	1.861
# change warning semantics
# --------------------------------------------
# 02/10/16	haveblue@elm3b96.(none)	1.862
# entry.S:
#   don't need stack_warn_lock anymore
# --------------------------------------------
# 02/10/16	haveblue@elm3b96.(none)	1.863
# merge
# --------------------------------------------
#
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Wed Oct 16 14:14:00 2002
+++ b/Makefile	Wed Oct 16 14:14:00 2002
@@ -156,7 +156,8 @@
 
 CPPFLAGS	:= -D__KERNEL__ -Iinclude
 CFLAGS 		:= $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
-	  	   -fomit-frame-pointer -fno-strict-aliasing -fno-common
+	  	   -fno-strict-aliasing -fno-common
+
 AFLAGS		:= -D__ASSEMBLY__ $(CPPFLAGS)
 
 export	VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \
@@ -255,6 +256,10 @@
 
 ifdef CONFIG_MODULES
 export EXPORT_FLAGS := -DEXPORT_SYMTAB
+endif
+
+ifneq ($(CONFIG_FRAME_POINTER),y)
+CFLAGS          += -fomit-frame-pointer
 endif
 
 #
diff -Nru a/arch/i386/Config.help b/arch/i386/Config.help
--- a/arch/i386/Config.help	Wed Oct 16 14:14:00 2002
+++ b/arch/i386/Config.help	Wed Oct 16 14:14:00 2002
@@ -1050,6 +1050,20 @@
   symbolic stack backtraces. This increases the size of the kernel
   somewhat, as all symbols have to be loaded into the kernel image.
 
+CONFIG_X86_STACK_CHECK
+  Say Y here to have the kernel attempt to detect when the per-task
+  kernel stack overflows. 
+
+  Some older versions of gcc don't handle the -p option correctly.  
+  Kernprof is affected by the same problem, which is described here:
+  http://oss.sgi.com/projects/kernprof/faq.html#Q9
+
+  Basically, if you get oopses in __free_pages_ok during boot when
+  you have this turned on, you need to fix gcc.  The Redhat 2.96 
+  version and gcc-3.x seem to work.  
+
+  If not debugging a stack overflow problem, say N
+
 CONFIG_DEBUG_OBSOLETE
   Say Y here if you want to reduce the chances of the tree compiling,
   and are prepared to dig into driver internals to fix compile errors.
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile	Wed Oct 16 14:14:00 2002
+++ b/arch/i386/Makefile	Wed Oct 16 14:14:00 2002
@@ -49,6 +49,10 @@
 MACHINE	:= mach-generic
 endif
 
+ifdef CONFIG_X86_STACK_CHECK
+CFLAGS += -p
+endif
+
 HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
 libs-y 					+= arch/i386/lib/
diff -Nru a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
--- a/arch/i386/boot/compressed/misc.c	Wed Oct 16 14:14:00 2002
+++ b/arch/i386/boot/compressed/misc.c	Wed Oct 16 14:14:00 2002
@@ -377,3 +377,7 @@
 	if (high_loaded) close_output_buffer_if_we_run_high(mv);
 	return high_loaded;
 }
+
+/* We don't actually check for stack overflows this early. */
+__asm__(".globl mcount ; mcount: ret\n");
+
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in	Wed Oct 16 14:14:00 2002
+++ b/arch/i386/config.in	Wed Oct 16 14:14:00 2002
@@ -467,6 +467,11 @@
       bool '  Highmem debugging' CONFIG_DEBUG_HIGHMEM
    fi
    bool '  Load all symbols for debugging/kksymoops' CONFIG_KALLSYMS
+   bool '  Check for stack overflows' CONFIG_X86_STACK_CHECK
+   if [ "$CONFIG_X86_STACK_CHECK" = "y" ]; then
+      define_bool CONFIG_FRAME_POINTER y
+   fi
+
 fi
 
 if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Wed Oct 16 14:14:00 2002
+++ b/arch/i386/kernel/entry.S	Wed Oct 16 14:14:00 2002
@@ -519,6 +519,61 @@
 	pushl $do_spurious_interrupt_bug
 	jmp error_code
 
+
+#ifdef CONFIG_X86_STACK_CHECK
+.data
+	.globl	stack_overflowed
+stack_overflowed:
+	.long	0
+.text
+
+ENTRY(mcount)
+	push %eax
+	movl $(THREAD_SIZE - 1),%eax
+	andl %esp,%eax
+	cmpl $STACK_WARN,%eax	/* more than half the stack is used*/
+	jle 1f
+2:
+	popl %eax
+	ret
+1:	
+	lock;   btsl    $0,stack_overflowed
+	jc      2b
+	
+	# switch to overflow stack
+	movl	%esp,%eax
+	movl	$(stack_overflow_stack + THREAD_SIZE - 4),%esp
+
+	pushf
+	cli
+	pushl	%eax
+
+	# push eip then esp of error for stack_overflow_panic
+	pushl	4(%eax)
+	pushl	%eax
+
+	# update the task pointer and cpu in the overflow stack's thread_info.
+	GET_THREAD_INFO_WITH_ESP(%eax)
+	movl	TI_TASK(%eax),%ebx
+	movl	%ebx,stack_overflow_stack+TI_TASK
+	movl	TI_CPU(%eax),%ebx
+	movl	%ebx,stack_overflow_stack+TI_CPU
+
+	call	stack_overflow
+
+	# pop off call arguments
+	addl	$8,%esp 
+
+	popl	%eax
+	popf
+	movl	%eax,%esp
+	popl	%eax
+	movl	$0,stack_overflowed
+	ret
+
+#warning stack check enabled
+#endif
+
 .data
 ENTRY(sys_call_table)
 	.long sys_ni_syscall	/* 0 - old "setup()" system call*/
diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
--- a/arch/i386/kernel/i386_ksyms.c	Wed Oct 16 14:14:00 2002
+++ b/arch/i386/kernel/i386_ksyms.c	Wed Oct 16 14:14:00 2002
@@ -192,3 +192,8 @@
 EXPORT_SYMBOL(is_sony_vaio_laptop);
 
 EXPORT_SYMBOL(__PAGE_KERNEL);
+
+#ifdef CONFIG_X86_STACK_CHECK
+extern void mcount(void);
+EXPORT_SYMBOL(mcount);
+#endif
diff -Nru a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c
--- a/arch/i386/kernel/init_task.c	Wed Oct 16 14:14:00 2002
+++ b/arch/i386/kernel/init_task.c	Wed Oct 16 14:14:00 2002
@@ -16,6 +16,10 @@
 union thread_union init_irq_union
 	__attribute__((__section__(".data.init_task")));
 
+#ifdef CONFIG_X86_STACK_CHECK
+union thread_union stack_overflow_stack
+	__attribute__((__section__(".data.init_task")));
+#endif
 
 /*
  * Initial thread structure.
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c	Wed Oct 16 14:14:00 2002
+++ b/arch/i386/kernel/process.c	Wed Oct 16 14:14:00 2002
@@ -156,7 +156,25 @@
 
 __setup("idle=", idle_setup);
 
-void show_regs(struct pt_regs * regs)
+void stack_overflow(unsigned long esp, unsigned long eip)
+{
+	int panicing = ((esp&(THREAD_SIZE-1)) <= STACK_PANIC);
+
+	printk( "esp: 0x%x masked: 0x%x STACK_PANIC:0x%x %d %d\n", 
+		esp, (esp&(THREAD_SIZE-1)), STACK_PANIC, (((esp&(THREAD_SIZE-1)) <= STACK_PANIC)), panicing );
+	
+	if (panicing)
+		print_symbol("stack overflow from %s\n", eip);
+	else
+		print_symbol("excessive stack use from %s\n", eip);
+	printk("esp: %p\n", (void*)esp);
+	show_trace((void*)esp);
+	
+	if (panicing)
+		panic("stack overflow\n");
+}
+
+asmlinkage void show_regs(struct pt_regs * regs)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
 
diff -Nru a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
--- a/include/asm-i386/thread_info.h	Wed Oct 16 14:14:00 2002
+++ b/include/asm-i386/thread_info.h	Wed Oct 16 14:14:00 2002
@@ -60,6 +60,8 @@
  */
 #define THREAD_ORDER 1 
 #define INIT_THREAD_SIZE       THREAD_SIZE
+#define STACK_PANIC		0x200ul
+#define STACK_WARN		((THREAD_SIZE)>>1)
 
 #ifndef __ASSEMBLY__
 #define INIT_THREAD_INFO(tsk)			\

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2002-11-01 13:37 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-10-31 19:18 [PATCH] (1/3) cleanup thread info on x86 David C. Hansen
2002-10-31 19:20 ` [PATCH] (2/3) per-cpu interrupt stacks for x86 David C. Hansen
2002-10-31 19:20 ` [PATCH] (3/3) stack overflow checking " David C. Hansen
2002-10-31 21:30   ` Dave Jones
2002-10-31 22:08     ` David C. Hansen
2002-11-01 12:59     ` Alan Cox
2002-11-01 13:42       ` Dave Jones
  -- strict thread matches above, loose matches on Subject: below --
2002-10-18 22:07 Dave Hansen
2002-10-18 22:31 ` Dave Hansen
2002-10-18 22:48   ` Andreas Dilger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).