Skip to contentSkip to conversation

Kexec based crash dumping

RFC Hariprasad Nellitheertha 6 participants 19 messages Aug 17, 2004 – Aug 20, 2004

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

Hi,

The patches that follow contain the initial implementation for kexec based crash dumping that we are working on. I had sent this to the fastboot mailing list a couple of weeks ago and this set of patches includes the changes made as per feedback from Andrew, Eric and others.

Main Idea

- Whenever a panic occurs, reboot to a new kernel using kexec using a small amount of memory (16MB). The rest of the memory is preserved across the reboot.
- In the second kernel, the memory contents from the failed kernel is available as an ELF format file for write-out.

Details on the design and implementation and on how to setup this facility are available in the first of the patches that follow. The patches have been made for the 2.6.8.1 kernel.

Kindly review these patches and provide feedback.

Thanks to Martin Bligh and Suparna for the design ideas and to Adam Litke who hacked up most of the memory preserving reboot code and the dump device abstraction code.

Regards, Hari

Signature · 4 lines
Hariprasad Nellitheertha
Linux Technology Center
India Software Labs
IBM India, Bangalore
#1 lore raw

Re: [PATCH][1/6]Documentation

Regards, Hari

Signature · 4 lines
Hariprasad Nellitheertha
Linux Technology Center
India Software Labs
IBM India, Bangalore

This patch contains the documentation for the kexec based crash dump tool.

Signed off by Hariprasad Nellitheertha <[email protected]>

---

 linux-2.6.8.1-hari/Documentation/kdump.txt |  101 +++++++++++++++++++++++++++++
 1 files changed, 101 insertions(+)
Documentation/kdump.txt new file +101 -0
diff -puN /dev/null Documentation/kdump.txt
@@ -0,0 +1,101 @@
+Documentation for kdump - the kexec based crash dumping solution
+================================================================
+
+DESIGN
+======
+
+We use kexec to reboot to a second kernel whenever a dump needs to be taken.
+This second kernel is booted with with very little memory (current
+implementation has this at 16MB). The contents of the 16MB of memory that
+the second kernel uses is copied onto a reserved area, before rebooting. So,
+we have the entire memory image of the previous kernel preserved.
+
+In the second kernel, this "old memory" can be accessed in two ways. The
+first one is through a device interface. We can create a /dev/hmem or
+whatever and write out the memory in raw format. The second interface is
+through /proc/vmcore. This exports the dump as an ELF format file which
+can be written out using any file copy command (cp, scp, etc). Further, gdb
+can be used to perform some minimal debugging on the dump file.
+
+Note that the two approaches are independent and the patches
+can be used depending on the functionality needed. More details on the
+patches below.
+
+PATCHES
+=======
+
+We currently have 6 patches.
+
+1) kd-doc-<version>.patch - Contains basic documentation (this document!!)
+2) kd-reb-<version>.patch - This patch ensures we do a kexec reboot upon panic
+   and also saves the first 16MB of memory into a backup area
+3) kd-copy-<version>.patch - This contains the code for reading the dump pages
+   in the second kernel.
+4) kd-reg-<version>.patch - This patch is for snapshotting the register contents
+   of all processors on to the backup area before rebooting.
+5) kd-elf-<version>.patch - This patch provides an ELF format interface to
+   the dump, post-reboot.
+6) kd-hmem-<version>.patch - This patch contains the code to access the dump as
+   an /dev/hmem.
+
+SETUP
+=====
+
+1) Apply the kexec patch on to the appropriate vanilla kernel tree.
+   The latest version of the kexec patch can be obtained from
+   http://www.xmission.com/~ebiederm/files/kexec/2.6.8-rc1-kexec1/
+   This patch should apply on 2.6.8-rc4 as well.
+   Older kexec patches can be found at
+   http://developer.osdl.org/rddunlap/kexec/
+
+2) Apply the crash dump patches.
+
+3) Ensure you have chosen the "kernel crash dumps" option under "Processor
+   type and features" and also the kexec syscall option under kernel hacking
+
+4) Load the second kernel to be booted using
+
+   kexec -l <kernel> --append="root=<root-dev> mem=16M dump init 1"
+
+5) System reboots into the second kernel when a panic occurs.
+   You could write a module to call panic, for testing purposes.
+
+6) Write out the dump file using
+
+   cp /proc/vmcore <dump-file>
+
+You can also access the dump as a device for a linear/raw view. To do this,
+you will need the kd-hmem-<version>.patch built into the kernel. To create
+the device, type
+
+  mknod /dev/hmem c 1 12
+
+Use "dd" with suitable options for count, bs and skip to access specific
+portions of the dump.
+
+ANALYSIS
+========
+
+You can run gdb on the dump file copied out of /proc/vmcore. Use vmlinux built
+with -g and run
+
+  gdb vmlinux <dump-file>
+
+Stack trace for the task on processor 0, register display, memory display
+work fine.
+
+TODO
+====
+
+1) Provide a kernel-pages only view for the dump. This could possibly turn up
+   as /proc/vmcore-kern.
+2) Provide register contents of all processors (similar to what multi-threaded
+   core dumps does).
+3) Modify "crash" to make it recognize this dump.
+4) Make the i386 kernel boot from any location so we can run the second kernel
+   from the reserved location instead of the current approach.
+
+CONTACT
+=======
+
+Hariprasad Nellitheertha - hari at in dot ibm dot com

_

#2 lore raw

Re: [PATCH][2/6]Memory preserving reboot using kexec

Regards, Hari

Signature · 4 lines
Hariprasad Nellitheertha
Linux Technology Center
India Software Labs
IBM India, Bangalore

This patch contains the code that does the memory preserving reboot. It copies over the first CRASH_BACKUP_SIZE amount of memory into a backup region before handing over to kexec.

Signed off by Hariprasad Nellitheertha <[email protected]> Signed off by Adam Litke <[email protected]>

---

 linux-2.6.8.1-hari/arch/i386/Kconfig                |   22 +++++++++++
 linux-2.6.8.1-hari/arch/i386/kernel/machine_kexec.c |   31 +++++++++++++++
 linux-2.6.8.1-hari/arch/i386/kernel/setup.c         |   11 +++++
 linux-2.6.8.1-hari/include/asm-i386/crash_dump.h    |   39 ++++++++++++++++++++
 linux-2.6.8.1-hari/include/linux/bootmem.h          |    1 
 linux-2.6.8.1-hari/include/linux/crash_dump.h       |   27 +++++++++++++
 linux-2.6.8.1-hari/kernel/panic.c                   |    6 +++
 linux-2.6.8.1-hari/mm/bootmem.c                     |    5 ++
 8 files changed, 142 insertions(+)
arch/i386/Kconfig renamed from arch/i386/Kconfig~kd-reb-268 +22 -0
diff -puN arch/i386/Kconfig~kd-reb-268 arch/i386/Kconfig
@@ -865,6 +865,28 @@ config REGPARM
 	generate incorrect output with certain kernel constructs when
 	-mregparm=3 is used.
 
+config CRASH_DUMP
+	bool "kernel crash dumps (EXPERIMENTAL)"
+	depends on KEXEC
+	help
+	  Generate crash dump using kexec.
+
+config BACKUP_BASE
+	int "location of the crash dumps backup region"
+	depends on CRASH_DUMP
+	default 128
+	help
+	Offset of backup region in terms of MB. Change this if you want
+	to modify the location of the crash dumps backup region.
+
+config BACKUP_SIZE
+	int "Size of the crash dumps backup region"
+	depends on CRASH_DUMP
+	range 16 64
+	default 16
+	help
+	The size of the backup region, in MB. This is also the size of the
+	memory that will be used to boot the second kernel after a crash.
 endmenu
 
 
arch/i386/kernel/machine_kexec.c renamed from arch/i386/kernel/machine_kexec.c~kd-reb-268 +31 -0
diff -puN arch/i386/kernel/machine_kexec.c~kd-reb-268 arch/i386/kernel/machine_kexec.c
@@ -9,6 +9,7 @@
 #include <linux/mm.h>
 #include <linux/kexec.h>
 #include <linux/delay.h>
+#include <linux/crash_dump.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
@@ -16,6 +17,7 @@
 #include <asm/io.h>
 #include <asm/apic.h>
 #include <asm/cpufeature.h>
+#include <asm/hw_irq.h>
 
 
 static void set_idt(void *newidt, __u16 limit)
@@ -76,6 +78,28 @@ const extern unsigned int relocate_new_k
 extern void use_mm(struct mm_struct *mm);
 
 /*
+ * We are going to do a memory preserving reboot. So, we copy over the
+ * first xxMB of memory into a backup location.
+ */
+void __relocate_base_mem(unsigned long backup_addr, unsigned long backup_size)
+{
+	unsigned long pfn, pfn_max;
+	void *src_addr, *dest_addr;
+	struct page *page;
+
+	pfn_max = backup_size >> PAGE_SHIFT;
+	for (pfn = 0; pfn < pfn_max; pfn++) {
+		src_addr = phys_to_virt(pfn << PAGE_SHIFT);
+		dest_addr = backup_addr + src_addr;
+		if (!pfn_valid(pfn))
+			continue;
+		page = pfn_to_page(pfn);
+		if (PageReserved(page))
+			copy_page(dest_addr, src_addr);
+	}
+}
+
+/*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
@@ -94,6 +118,13 @@ void machine_kexec(struct kimage *image)
 	reboot_code_buffer = page_to_pfn(image->reboot_code_pages) << PAGE_SHIFT;
 	indirection_page = image->head & PAGE_MASK;
 
+	/*
+	 * If we are here to do a crash dump, save the memory from
+	 * 0-16MB before we copy over the kexec kernel image.  Otherwise
+	 * our dump will show the wrong kernel entirely.
+	 */
+	relocate_base_mem();
+
 	/* copy it out */
 	memcpy((void *)reboot_code_buffer, relocate_new_kernel, relocate_new_kernel_size);
 
arch/i386/kernel/setup.c renamed from arch/i386/kernel/setup.c~kd-reb-268 +11 -0
diff -puN arch/i386/kernel/setup.c~kd-reb-268 arch/i386/kernel/setup.c
@@ -39,6 +39,7 @@
 #include <linux/efi.h>
 #include <linux/init.h>
 #include <linux/edd.h>
+#include <linux/crash_dump.h>
 #include <video/edid.h>
 #include <asm/e820.h>
 #include <asm/mpspec.h>
@@ -56,6 +57,7 @@
 unsigned long init_pg_tables_end __initdata = ~0UL;
 
 int disable_pse __initdata = 0;
+unsigned int dump_enabled;
 
 /*
  * Machine setup..
@@ -347,6 +349,9 @@ static void __init limit_regions(unsigne
 			}
 		}
 	}
+	/* If we are doing a crash dump, we still need to know the real mem size*/
+	set_saved_max_pfn();
+
 	for (i = 0; i < e820.nr_map; i++) {
 		if (e820.map[i].type == E820_RAM) {
 			current_addr = e820.map[i].addr + e820.map[i].size;
@@ -809,6 +814,9 @@ static void __init parse_cmdline_early (
 		if (c == ' ' && !memcmp(from, "highmem=", 8))
 			highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT;
 	
+		if (!memcmp(from, "dump", 4))
+			dump_enabled = 1;
+
 		c = *(from++);
 		if (!c)
 			break;
@@ -1082,6 +1090,9 @@ static unsigned long __init setup_memory
 		}
 	}
 #endif
+
+	crash_reserve_bootmem();
+
 	return max_low_pfn;
 }
 #else
include/asm-i386/crash_dump.h new file +39 -0
diff -puN /dev/null include/asm-i386/crash_dump.h
@@ -0,0 +1,39 @@
+/* asm-i386/crash_dump.h */
+#include <linux/bootmem.h>
+
+extern unsigned int dump_enabled;
+
+unsigned long __init find_max_low_pfn(void);
+void __init find_max_pfn(void);
+void __relocate_base_mem(unsigned long, unsigned long);
+
+extern unsigned int crashed;
+
+#ifdef CONFIG_CRASH_DUMP
+#define CRASH_BACKUP_BASE ((unsigned long)CONFIG_BACKUP_BASE * 0x100000)
+#define CRASH_BACKUP_SIZE ((unsigned long)CONFIG_BACKUP_SIZE * 0x100000)
+
+static inline void relocate_base_mem(void)
+{
+	if (crashed)
+		__relocate_base_mem(CRASH_BACKUP_BASE, CRASH_BACKUP_SIZE);
+}
+
+static inline void set_saved_max_pfn(void)
+{
+	find_max_pfn();
+	saved_max_pfn = find_max_low_pfn();
+}
+
+static inline void crash_reserve_bootmem(void)
+{
+	if (!dump_enabled)
+		reserve_bootmem(CRASH_BACKUP_BASE, CRASH_BACKUP_SIZE);
+}
+#else
+#define CRASH_BACKUP_BASE 0x08000000
+#define CRASH_BACKUP_SIZE 0x01000000
+static inline void relocate_base_mem(void) {}
+static inline void set_saved_max_pfn(void) {}
+static inline void crash_reserve_bootmem(void) {}
+#endif
include/linux/bootmem.h renamed from include/linux/bootmem.h~kd-reb-268 +1 -0
diff -puN include/linux/bootmem.h~kd-reb-268 include/linux/bootmem.h
@@ -21,6 +21,7 @@ extern unsigned long min_low_pfn;
  * highest page
  */
 extern unsigned long max_pfn;
+extern unsigned long saved_max_pfn;
 
 /*
  * node_bootmem_map is a map pointer - the bits represent all physical 
include/linux/crash_dump.h new file +27 -0
diff -puN /dev/null include/linux/crash_dump.h
@@ -0,0 +1,27 @@
+#include <linux/kexec.h>
+#include <linux/smp_lock.h>
+#include <linux/device.h>
+#include <asm/crash_dump.h>
+
+#ifdef CONFIG_CRASH_DUMP
+static inline void crash_machine_kexec(void)
+{
+	struct kimage *image;
+
+	if (crashed)
+		return;
+
+        image = xchg(&kexec_image, 0);
+        if (image) {
+		crashed = 1;
+		device_shutdown();
+		printk(KERN_EMERG "kexec: opening parachute\n");
+		machine_kexec(image);
+		while (1);
+        } else {
+		printk(KERN_EMERG "kexec: No kernel image loaded!\n");
+        }
+}
+#else
+static inline void crash_machine_kexec(void) {}
+#endif
kernel/panic.c renamed from kernel/panic.c~kd-reb-268 +6 -0
diff -puN kernel/panic.c~kd-reb-268 kernel/panic.c
@@ -19,10 +19,13 @@
 #include <linux/syscalls.h>
 #include <linux/interrupt.h>
 #include <linux/nmi.h>
+#include <linux/kexec.h>
+#include <linux/crash_dump.h>
 
 int panic_timeout;
 int panic_on_oops;
 int tainted;
+unsigned int crashed;
 
 EXPORT_SYMBOL(panic_timeout);
 
@@ -68,6 +71,9 @@ NORET_TYPE void panic(const char * fmt, 
 		sys_sync();
 	bust_spinlocks(0);
 
+	/* If we have crashed, perform a kexec reboot, for dump write-out */
+	crash_machine_kexec();
+
 #ifdef CONFIG_SMP
 	smp_send_stop();
 #endif
mm/bootmem.c renamed from mm/bootmem.c~kd-reb-268 +5 -0
diff -puN mm/bootmem.c~kd-reb-268 mm/bootmem.c
@@ -27,6 +27,11 @@
 unsigned long max_low_pfn;
 unsigned long min_low_pfn;
 unsigned long max_pfn;
+/*
+ * If we have booted due to a crash, max_pfn will be a very low value. We need
+ * to know the amount of memory that the previous kernel used.
+ */
+unsigned long saved_max_pfn;
 
 EXPORT_SYMBOL(max_pfn);		/* This is exported so
 				 * dma_get_required_mask(), which uses

_

#3 lore raw

Re: [PATCH][3/6]Interface for copying the dump pages

Regards, Hari

Signature · 4 lines
Hariprasad Nellitheertha
Linux Technology Center
India Software Labs
IBM India, Bangalore

This patch provides the interfaces necessary to read the dump contents, treating it as a high memory device.

Signed off by Hariprasad Nellitheertha <[email protected]>

---

 linux-2.6.8.1-hari/arch/i386/mm/highmem.c     |   18 ++++++++++
 linux-2.6.8.1-hari/drivers/char/mem.c         |   44 ++++++++++++++++++++++++++
 linux-2.6.8.1-hari/include/asm-i386/highmem.h |    1 
 linux-2.6.8.1-hari/include/linux/highmem.h    |    1 
 4 files changed, 64 insertions(+)
arch/i386/mm/highmem.c renamed from arch/i386/mm/highmem.c~kd-copy-268 +18 -0
diff -puN arch/i386/mm/highmem.c~kd-copy-268 arch/i386/mm/highmem.c
@@ -74,6 +74,24 @@ void kunmap_atomic(void *kvaddr, enum km
 	preempt_check_resched();
 }
 
+/* This is the same as kmap_atomic but takes in a pfn instead of a
+ * struct page.
+ */
+void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+{
+        enum fixed_addresses idx;
+        unsigned long vaddr;
+
+        inc_preempt_count();
+
+        idx = type + KM_TYPE_NR*smp_processor_id();
+        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+        set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot));
+        __flush_tlb_one(vaddr);
+
+        return (void*) vaddr;
+}
+
 struct page *kmap_atomic_to_page(void *ptr)
 {
 	unsigned long idx, vaddr = (unsigned long)ptr;
drivers/char/mem.c renamed from drivers/char/mem.c~kd-copy-268 +44 -0

65 lines not on this page · raw message

include/asm-i386/highmem.h renamed from include/asm-i386/highmem.h~kd-copy-268 +1 -0
diff -puN include/asm-i386/highmem.h~kd-copy-268 include/asm-i386/highmem.h
@@ -61,6 +61,7 @@ void *kmap(struct page *page);
 void kunmap(struct page *page);
 void *kmap_atomic(struct page *page, enum km_type type);
 void kunmap_atomic(void *kvaddr, enum km_type type);
+void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
 struct page *kmap_atomic_to_page(void *ptr);
 
 #define flush_cache_kmaps()	do { } while (0)
include/linux/highmem.h renamed from include/linux/highmem.h~kd-copy-268 +1 -0
diff -puN include/linux/highmem.h~kd-copy-268 include/linux/highmem.h
@@ -30,6 +30,7 @@ static inline void *kmap(struct page *pa
 
 #define kmap_atomic(page, idx)		page_address(page)
 #define kunmap_atomic(addr, idx)	do { } while (0)
+#define kmap_atomic_pfn(pfn, idx)	page_address(pfn_to_page(pfn))
 #define kmap_atomic_to_page(ptr)	virt_to_page(ptr)
 
 #endif /* CONFIG_HIGHMEM */

_

#4 lore raw

Re: [PATCH][4/6]Register snapshotting before kexec-boot

Regards, Hari

Signature · 4 lines
Hariprasad Nellitheertha
Linux Technology Center
India Software Labs
IBM India, Bangalore

This patch contains the code for stopping the other cpus and snapshotting their register values before doing the kexec reboot.

Signed off by Hariprasad Nellitheertha <[email protected]>

---

 linux-2.6.8.1-hari/arch/i386/kernel/Makefile                   |    1 
 linux-2.6.8.1-hari/arch/i386/kernel/crash_dump.c               |   98 ++++++++++
 linux-2.6.8.1-hari/arch/i386/kernel/machine_kexec.c            |   14 +
 linux-2.6.8.1-hari/arch/i386/kernel/smp.c                      |   13 +
 linux-2.6.8.1-hari/include/asm-i386/crash_dump.h               |   32 +++
 linux-2.6.8.1-hari/include/asm-i386/mach-default/irq_vectors.h |    1 
 linux-2.6.8.1-hari/include/asm-i386/smp.h                      |    1 
 7 files changed, 156 insertions(+), 4 deletions(-)
arch/i386/kernel/Makefile renamed from arch/i386/kernel/Makefile~kd-reg-268 +1 -0
diff -puN arch/i386/kernel/Makefile~kd-reg-268 arch/i386/kernel/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_X86_MPPARSE)	+= mpparse.o
 obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o nmi.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
 obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit.o
 obj-$(CONFIG_MODULES)		+= module.o
arch/i386/kernel/crash_dump.c new file +98 -0

98 lines not on this page · raw message

arch/i386/kernel/machine_kexec.c renamed from arch/i386/kernel/machine_kexec.c~kd-reg-268 +12 -2
diff -puN arch/i386/kernel/machine_kexec.c~kd-reg-268 arch/i386/kernel/machine_kexec.c
@@ -17,8 +17,9 @@
 #include <asm/io.h>
 #include <asm/apic.h>
 #include <asm/cpufeature.h>
-#include <asm/hw_irq.h>
 
+struct pt_regs crash_smp_regs[NR_CPUS];
+u32 crash_smp_current_task[NR_CPUS];
 
 static void set_idt(void *newidt, __u16 limit)
 {
@@ -97,6 +98,14 @@ void __relocate_base_mem(unsigned long b
 		if (PageReserved(page))
 			copy_page(dest_addr, src_addr);
 	}
+
+	/* Now copy over the saved task pointers and the registers
+	 * to the end of the  reserved area
+	 */
+	dest_addr = (void *)(__va(CRASH_BACKUP_BASE + CRASH_BACKUP_SIZE));
+	memcpy(dest_addr, crash_smp_regs, (sizeof(struct pt_regs)*NR_CPUS));
+	dest_addr += sizeof(struct pt_regs)*NR_CPUS;
+	memcpy(dest_addr, crash_smp_current_task, (sizeof(u32)*NR_CPUS));
 }
 
 /*
@@ -111,7 +120,8 @@ void machine_kexec(struct kimage *image)
 
 	/* switch to an mm where the reboot_code_buffer is identity mapped */
 	use_mm(&init_mm);
-	stop_apics();
+
+	crash_dump_stop_cpus();
 
 	/* Interrupts aren't acceptable while we reboot */
 	local_irq_disable();
arch/i386/kernel/smp.c renamed from arch/i386/kernel/smp.c~kd-reg-268 +12 -1
diff -puN arch/i386/kernel/smp.c~kd-reg-268 arch/i386/kernel/smp.c
@@ -143,6 +143,9 @@ inline void __send_IPI_shortcut(unsigned
 	 */
 	cfg = __prepare_ICR(shortcut, vector);
 
+	if (vector == CRASH_DUMP_VECTOR)
+		cfg = (cfg&~APIC_VECTOR_MASK)|APIC_DM_NMI;
+
 	/*
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
@@ -221,6 +224,9 @@ inline void send_IPI_mask_sequence(cpuma
 			 */
 			cfg = __prepare_ICR(0, vector);
 			
+			if (vector == CRASH_DUMP_VECTOR)
+				cfg = (cfg&~APIC_VECTOR_MASK)|APIC_DM_NMI;
+
 			/*
 			 * Send the IPI. The write to APIC_ICR fires this off.
 			 */
@@ -467,6 +473,11 @@ void flush_tlb_all(void)
 	on_each_cpu(do_flush_tlb_all, NULL, 1, 1);
 }
 
+void crash_dump_send_ipi(void)
+{
+	send_IPI_allbutself(CRASH_DUMP_VECTOR);
+}
+
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
@@ -548,7 +559,7 @@ int smp_call_function (void (*func) (voi
 	return 0;
 }
 
-static void stop_this_cpu (void * dummy)
+void stop_this_cpu (void * dummy)
 {
 	/*
 	 * Remove this CPU:
include/asm-i386/crash_dump.h renamed from include/asm-i386/crash_dump.h~kd-reg-268 +31 -1
diff -puN include/asm-i386/crash_dump.h~kd-reg-268 include/asm-i386/crash_dump.h
@@ -1,5 +1,7 @@
 /* asm-i386/crash_dump.h */
 #include <linux/bootmem.h>
+#include <asm/hw_irq.h>
+#include <asm/apic.h>
 
 extern unsigned int dump_enabled;
 
@@ -8,6 +10,11 @@ void __init find_max_pfn(void);
 void __relocate_base_mem(unsigned long, unsigned long);
 
 extern unsigned int crashed;
+extern struct pt_regs crash_smp_regs[NR_CPUS];
+extern u32 crash_smp_current_task[NR_CPUS];
+extern void crash_dump_save_this_cpu(struct pt_regs *, int);
+extern void __crash_dump_stop_cpus(void);
+extern void crash_get_current_regs(struct pt_regs *regs);
 
 #ifdef CONFIG_CRASH_DUMP
 #define CRASH_BACKUP_BASE ((unsigned long)CONFIG_BACKUP_BASE * 0x100000)
@@ -28,7 +35,26 @@ static inline void set_saved_max_pfn(voi
 static inline void crash_reserve_bootmem(void)
 {
 	if (!dump_enabled)
-		reserve_bootmem(CRASH_BACKUP_BASE, CRASH_BACKUP_SIZE);
+		reserve_bootmem(CRASH_BACKUP_BASE, CRASH_BACKUP_SIZE + PAGE_SIZE);
+}
+
+static inline void crash_dump_stop_cpus(void)
+{
+	if (!crashed)
+	stop_apics();
+	else {
+		int cpu = smp_processor_id();
+
+		crash_smp_current_task[cpu] = (int)current;
+		crash_get_current_regs(&crash_smp_regs[cpu]);
+
+		/* This also captures the register states of the other cpus */
+		__crash_dump_stop_cpus();
+#if defined(CONFIG_X86_IO_APIC)
+		disable_IO_APIC();
+#endif
+		disconnect_bsp_APIC();
+	}
 }
 #else
 #define CRASH_BACKUP_BASE 0x08000000
@@ -36,4 +62,8 @@ static inline void crash_reserve_bootmem
 static inline void relocate_base_mem(void) {}
 static inline void set_saved_max_pfn(void) {}
 static inline void crash_reserve_bootmem(void) {}
+static inline void crash_dump_stop_cpus(void)
+{
+	stop_apics();
+}
 #endif
include/asm-i386/mach-default/irq_vectors.h renamed from include/asm-i386/mach-default/irq_vectors.h~kd-reg-268 +1 -0
diff -puN include/asm-i386/mach-default/irq_vectors.h~kd-reg-268 include/asm-i386/mach-default/irq_vectors.h
@@ -48,6 +48,7 @@
 #define INVALIDATE_TLB_VECTOR	0xfd
 #define RESCHEDULE_VECTOR	0xfc
 #define CALL_FUNCTION_VECTOR	0xfb
+#define CRASH_DUMP_VECTOR	0xfa
 
 #define THERMAL_APIC_VECTOR	0xf0
 /*
include/asm-i386/smp.h renamed from include/asm-i386/smp.h~kd-reg-268 +1 -0
diff -puN include/asm-i386/smp.h~kd-reg-268 include/asm-i386/smp.h
@@ -41,6 +41,7 @@ extern void smp_message_irq(int cpl, voi
 extern void smp_invalidate_rcv(void);		/* Process an NMI */
 extern void (*mtrr_hook) (void);
 extern void zap_low_mappings (void);
+extern void stop_this_cpu(void *);
 
 #define MAX_APICID 256
 

_

#5 lore raw

Re: [PATCH][5/6]ELF format interface for the dump

Regards, Hari

Signature · 4 lines
Hariprasad Nellitheertha
Linux Technology Center
India Software Labs
IBM India, Bangalore

This patch contains the code that provides an ELF format interface to the previous kernel's memory post kexec reboot.

Signed off by Hariprasad Nellitheertha <[email protected]>

---

 linux-2.6.8.1-hari/fs/proc/Makefile           |    1 
 linux-2.6.8.1-hari/fs/proc/kcore.c            |   10 -
 linux-2.6.8.1-hari/fs/proc/proc_misc.c        |   13 +
 linux-2.6.8.1-hari/fs/proc/vmcore.c           |  233 ++++++++++++++++++++++++++
 linux-2.6.8.1-hari/include/linux/crash_dump.h |    6 
 linux-2.6.8.1-hari/include/linux/proc_fs.h    |    2 
 6 files changed, 260 insertions(+), 5 deletions(-)
fs/proc/Makefile renamed from fs/proc/Makefile~kd-elf-268 +1 -0
diff -puN fs/proc/Makefile~kd-elf-268 fs/proc/Makefile
@@ -11,4 +11,5 @@ proc-y       += inode.o root.o base.o ge
 		kmsg.o proc_tty.o proc_misc.o
 
 proc-$(CONFIG_PROC_KCORE)	+= kcore.o
+proc-$(CONFIG_CRASH_DUMP)	+= vmcore.o
 proc-$(CONFIG_PROC_DEVICETREE)	+= proc_devtree.o
fs/proc/kcore.c renamed from fs/proc/kcore.c~kd-elf-268 +5 -5
diff -puN fs/proc/kcore.c~kd-elf-268 fs/proc/kcore.c
@@ -114,7 +114,7 @@ static size_t get_kcore_size(int *nphdr,
 /*
  * determine size of ELF note
  */
-static int notesize(struct memelfnote *en)
+int notesize(struct memelfnote *en)
 {
 	int sz;
 
@@ -129,7 +129,7 @@ static int notesize(struct memelfnote *e
 /*
  * store a note in the header buffer
  */
-static char *storenote(struct memelfnote *men, char *bufp)
+char *storenote(struct memelfnote *men, char *bufp)
 {
 	struct elf_note en;
 
@@ -156,7 +156,7 @@ static char *storenote(struct memelfnote
  * store an ELF coredump header in the supplied buffer
  * nphdr is the number of elf_phdr to insert
  */
-static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff)
+void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff, struct kcore_list *clist)
 {
 	struct elf_prstatus prstatus;	/* NT_PRSTATUS */
 	struct elf_prpsinfo prpsinfo;	/* NT_PRPSINFO */
@@ -208,7 +208,7 @@ static void elf_kcore_store_hdr(char *bu
 	nhdr->p_align	= 0;
 
 	/* setup ELF PT_LOAD program header for every area */
-	for (m=kclist; m; m=m->next) {
+	for (m=clist; m; m=m->next) {
 		phdr = (struct elf_phdr *) bufp;
 		bufp += sizeof(struct elf_phdr);
 		offset += sizeof(struct elf_phdr);
@@ -305,7 +305,7 @@ read_kcore(struct file *file, char __use
 			return -ENOMEM;
 		}
 		memset(elf_buf, 0, elf_buflen);
-		elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen);
+		elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen, kclist);
 		read_unlock(&kclist_lock);
 		if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
 			kfree(elf_buf);
fs/proc/proc_misc.c renamed from fs/proc/proc_misc.c~kd-elf-268 +13 -0
diff -puN fs/proc/proc_misc.c~kd-elf-268 fs/proc/proc_misc.c
@@ -44,6 +44,8 @@
 #include <linux/jiffies.h>
 #include <linux/sysrq.h>
 #include <linux/vmalloc.h>
+#include <linux/bootmem.h>
+#include <linux/crash_dump.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -628,6 +630,7 @@ static struct file_operations proc_sysrq
 #endif
 
 struct proc_dir_entry *proc_root_kcore;
+struct proc_dir_entry *proc_vmcore;
 
 static void create_seq_entry(char *name, mode_t mode, struct file_operations *f)
 {
@@ -689,6 +692,16 @@ void __init proc_misc_init(void)
 				(size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
 	}
 #endif
+#ifdef CONFIG_CRASH_DUMP
+	if (dump_enabled) {
+		proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL);
+		if (proc_vmcore) {
+			proc_vmcore->proc_fops = &proc_vmcore_operations;
+			proc_vmcore->size =
+				(size_t)(saved_max_pfn << PAGE_SHIFT);
+		}
+	}
+#endif
 	if (prof_on) {
 		entry = create_proc_entry("profile", S_IWUSR | S_IRUGO, NULL);
 		if (entry) {
fs/proc/vmcore.c new file +233 -0

233 lines not on this page · raw message

include/linux/crash_dump.h renamed from include/linux/crash_dump.h~kd-elf-268 +6 -0
diff -puN include/linux/crash_dump.h~kd-elf-268 include/linux/crash_dump.h
@@ -3,6 +3,12 @@
 #include <linux/device.h>
 #include <asm/crash_dump.h>
 
+extern struct memelfnote memelfnote;
+extern int notesize(struct memelfnote *);
+extern char *storenote(struct memelfnote *, char *);
+extern ssize_t copy_hmem_page(unsigned long, char *, size_t, int);
+extern void elf_kcore_store_hdr(char *, int, int, struct kcore_list *);
+
 #ifdef CONFIG_CRASH_DUMP
 static inline void crash_machine_kexec(void)
 {
include/linux/proc_fs.h renamed from include/linux/proc_fs.h~kd-elf-268 +2 -0
diff -puN include/linux/proc_fs.h~kd-elf-268 include/linux/proc_fs.h
@@ -82,6 +82,7 @@ extern struct proc_dir_entry *proc_net;
 extern struct proc_dir_entry *proc_bus;
 extern struct proc_dir_entry *proc_root_driver;
 extern struct proc_dir_entry *proc_root_kcore;
+extern struct proc_dir_entry *proc_vmcore;
 
 extern void proc_root_init(void);
 extern void proc_misc_init(void);
@@ -112,6 +113,7 @@ extern int proc_readdir(struct file *, v
 extern struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *);
 
 extern struct file_operations proc_kcore_operations;
+extern struct file_operations proc_vmcore_operations;
 extern struct file_operations proc_kmsg_operations;
 extern struct file_operations ppc_htab_operations;
 

_

#6 lore raw

Re: [PATCH][6/6]Device abstraction for linear/raw view of the dump

Regards, Hari

Signature · 4 lines
Hariprasad Nellitheertha
Linux Technology Center
India Software Labs
IBM India, Bangalore

This patch contains the code that enables us to access the previous kernel's memory as /dev/hmem.

Signed off by Hariprasad Nellitheertha <[email protected]> Signed off by Adam Litke <[email protected]>

---

 linux-2.6.8.1-hari/Documentation/devices.txt |    1 
 linux-2.6.8.1-hari/drivers/char/mem.c        |   72 +++++++++++++++++++++++++++
 2 files changed, 73 insertions(+)
Documentation/devices.txt renamed from Documentation/devices.txt~kd-hmem-268 +1 -0
diff -puN Documentation/devices.txt~kd-hmem-268 Documentation/devices.txt
@@ -100,6 +100,7 @@ Your cooperation is appreciated.
 		  9 = /dev/urandom	Faster, less secure random number gen.
 		 10 = /dev/aio		Asyncronous I/O notification interface
 		 11 = /dev/kmsg		Writes to this come out as printk's
+		 12 = /dev/hmem		Access to kexec-ed crash dump
   1 block	RAM disk
 		  0 = /dev/ram0		First RAM disk
 		  1 = /dev/ram1		Second RAM disk
drivers/char/mem.c renamed from drivers/char/mem.c~kd-hmem-268 +72 -0

102 lines not on this page · raw message

_

#7 lore raw

Re: [PATCH][6/6]Device abstraction for linear/raw view of the dump

Quoted 2 lines

This patch contains the code that enables us to access the previous kernel's memory as /dev/hmem.

One of the bits of feedback we got at kernel summit was that nobody liked the /dev/hmem name ... could we change it to /dev/oldmem, perhaps?

Thanks,

M.

#8 lore raw

Re: [PATCH][6/6]Device abstraction for linear/raw view of the dump

Hi Martin,

Quoted 5 lines · Martin J. Bligh
Quoted 2 lines

This patch contains the code that enables us to access the previous kernel's memory as /dev/hmem.

One of the bits of feedback we got at kernel summit was that nobody liked the /dev/hmem name ... could we change it to /dev/oldmem, perhaps?

I'll change it to /dev/oldmem in the next iteration of the patches.

Quoted 5 lines

Thanks,

M.

Regards, Hari

Signature · 4 lines
Hariprasad Nellitheertha
Linux Technology Center
India Software Labs
IBM India, Bangalore
#9 lore raw

Re: [PATCH][4/6]Register snapshotting before kexec-boot

In reply to Hariprasad Nellitheertha

arch/i386/kernel/machine_kexec.c void __relocate_base_mem(unsigned long b · line 105

Quoted 5 lines · Hariprasad Nellitheertha

Regards, Hari

arch/i386/kernel/machine_kexec.c renamed from arch/i386/kernel/machine_kexec.c~kd-reg-268 +4 -0
+       /* Now copy over the saved task pointers and the registers
+        * to the end of the  reserved area
+        */
+       dest_addr = (void *)(__va(CRASH_BACKUP_BASE + CRASH_BACKUP_SIZE));

Why the cast? Isn't __va() already returning a void*?

-- Dave

#10 lore raw

Re: [PATCH][4/6]Register snapshotting before kexec-boot

In reply to Hariprasad Nellitheertha

This patch is needed so that the kexec patches will compile on systems that don't have APIC's enabled.

- Ted

# This is a BitKeeper generated diff -Nru style patch. #
# ChangeSet

#   2004/08/18 09:41:41-04:00 [email protected] 
#   Fix so that kexec patches compile on systems when 
#   CONFIG_X86_LOCAL_APIC is disabled.
# 
# include/asm-i386/crash_dump.h
#   2004/08/18 09:41:29-04:00 [email protected] +2 -0
#   Fix so that kexec patches compile on systems when 
#   CONFIG_X86_LOCAL_APIC is disabled.
# 
diff -Nru a/include/asm-i386/crash_dump.h b/include/asm-i386/crash_dump.h
--- a/include/asm-i386/crash_dump.h	2004-08-18 09:42:15 -04:00
+++ b/include/asm-i386/crash_dump.h	2004-08-18 09:42:15 -04:00
@@ -53,7 +53,9 @@
 #if defined(CONFIG_X86_IO_APIC)
 		disable_IO_APIC();
 #endif
+#if defined(CONFIG_X86_LOCAL_APIC)
 		disconnect_bsp_APIC();
+#endif
 	}
 }
 #else
#11 lore raw

Re: [PATCH][4/6]Register snapshotting before kexec-boot

Hi Ted,

Quoted 2 lines · Theodore Ts'o

This patch is needed so that the kexec patches will compile on systems that don't have APIC's enabled.

Thanks a lot for the patch.

Regards, Hari

Signature · 4 lines
Hariprasad Nellitheertha
Linux Technology Center
India Software Labs
IBM India, Bangalore
#12 lore raw

Re: [PATCH][3/6]Interface for copying the dump pages

In reply to Hariprasad Nellitheertha
Quoted 4 lines · Hariprasad Nellitheertha

Regards, Hari
+/* This is the same as kmap_atomic but takes in a pfn instead of a
+ * struct page.
+ */

How about:

/*
* This is the same as kmap_atomic() but can map memory that doesn't
* necessarily have struct page associated with it.
*/

Quoted 2 lines

+ssize_t copy_hmem_page(unsigned long pfn, char *buf, size_t csize, int userbuf)

...

drivers/char/mem.c static int mmap_mem(struct file * file, · line 246

Quoted 8 lines
drivers/char/mem.c renamed from drivers/char/mem.c~kd-copy-268 +8 -0
+       if (pfn == -1) {
+               /* Give them a zeroed page */
+               if (userbuf) {
+                       if (clear_user(buf, csize))
+                               return -EFAULT;
+               } else
+                       memset(buf, 0, csize);
+       } else {

This is really hackish. If you want to zero a userspace page, just zero it in the caller's code, or call a different function. Zeroing a userspace page has nothing to do with copying a highmem page, and it really shouldn't be here. Just changing it from taking a 0 to a -1 from the last time you posted it doesn't really make it any better.

Also, that function might belong in the same area as copy_highpage(), not in some driver. In any case, it certainly needs a big fat comment explaining why it is special, and different from copy_highpage().

If it shouldn't be moved and really is isolated to the mem.c driver, it needs to be declared static.

-- Dave

#13 lore raw

Re: [PATCH][2/6]Memory preserving reboot using kexec

In reply to Hariprasad Nellitheertha
Quoted 10 lines · Hariprasad Nellitheertha

Regards, Hari

arch/i386/kernel/machine_kexec.c renamed from arch/i386/kernel/machine_kexec.c~kd-reb-268 +7 -0
+void __relocate_base_mem(unsigned long backup_addr, unsigned long backup_size)
+{
+       unsigned long pfn, pfn_max;
+       void *src_addr, *dest_addr;
+       struct page *page;
+
+       pfn_max = backup_size >> PAGE_SHIFT;

arch/i386/kernel/machine_kexec.c const extern unsigned int relocate_new_k · line 100

Quoted 10 lines
arch/i386/kernel/machine_kexec.c renamed from arch/i386/kernel/machine_kexec.c~kd-reb-268 +10 -0
+       for (pfn = 0; pfn < pfn_max; pfn++) {
+               src_addr = phys_to_virt(pfn << PAGE_SHIFT);
+               dest_addr = backup_addr + src_addr;
+               if (!pfn_valid(pfn))
+                       continue;
+               page = pfn_to_page(pfn);
+               if (PageReserved(page))
+                       copy_page(dest_addr, src_addr);
+       }
+}

You're getting a little sloppy with your types in there. I know you probably aren't getting warnings for passing unsigned longs to copy_page(), but you should probably still be passing pointers to it.

I think the general convention is to keep physical addresses in unsigned longs and virtual addresses in pointers. Just keep that in mind.

include/asm-i386/crash_dump.h line 35

Quoted 2 lines
include/asm-i386/crash_dump.h new file +2 -0
+#define CRASH_BACKUP_BASE 0x08000000
+#define CRASH_BACKUP_SIZE 0x01000000

What are these numbers? Why do you need to define them when your config option is off?

mm/bootmem.c line 34

Quoted 5 lines
mm/bootmem.c renamed from mm/bootmem.c~kd-reb-268 +5 -0
+/*
+ * If we have booted due to a crash, max_pfn will be a very low value. We need
+ * to know the amount of memory that the previous kernel used.
+ */
+unsigned long saved_max_pfn;

I'd probably put that comment next to the place where saved_max_pfn is used instead of where it is declared.

-- Dave

#14 lore raw
In reply to Hariprasad Nellitheertha
Quoted 3 lines · Hariprasad Nellitheertha

The patches that follow contain the initial implementation for kexec based crash dumping that we are working on.

It seems to be coming together nicely.

Where do we stand with support for other architectures? Do you expect that each architecture will involve a lot of work?

And how much of the i386 implementation do you expect x86_64 can reuse?

#15 lore raw

Hi Andrew,

Quoted 9 lines · Andrew Morton
Quoted 3 lines · Hariprasad Nellitheertha

The patches that follow contain the initial implementation for kexec based crash dumping that we are working on.

It seems to be coming together nicely.

Where do we stand with support for other architectures? Do you expect that each architecture will involve a lot of work?

I don't think so. The main architecture dependent components are register snapshotting and silencing of other cpus. These are not new problems to solve as other projects such as LKCD, KDB have already done this for most archs.

Quoted 3 lines

And how much of the i386 implementation do you expect x86_64 can reuse?

We should be able to re-use most of the code. The x86_64 port should be ready pretty quickly once kexec itself is available.

Regards, Hari

Signature · 4 lines
Hariprasad Nellitheertha
Linux Technology Center
India Software Labs
IBM India, Bangalore
#16 lore raw
In reply to Andrew Morton
Quoted 6 lines · Andrew Morton
Quoted 3 lines · Hariprasad Nellitheertha

The patches that follow contain the initial implementation for kexec based crash dumping that we are working on.

It seems to be coming together nicely.

Well it is coming. There is a lot of exploratory work still needed to find what it takes to reliably get a kernel working in the hostile environment present after a kernel panic. That really has barely begun and it likely to turn up some unexpected architecture specific issues.

Eric

#17 lore raw
In reply to Hariprasad Nellitheertha
Quoted 6 lines · Hariprasad Nellitheertha

Hi,

The patches that follow contain the initial implementation for kexec based crash dumping that we are working on. I had sent this to the fastboot mailing list a couple of weeks ago and this set of patches includes the changes made as per feedback from Andrew, Eric and others.

One significant change is missing. You do not separate out the two use cases of kexec. So on a system that is configured to use call sys_reboot(LINUX_REBOOT_CMD_KEXEC) on reboot I will get a core dump if using your code.

Or alternatively if I call sys_kexec_load and then something in the shutdown scripts triggers a kernel panic it is not OK to start boot the new kernel instead of taking normal panic behavior.

Until the two uses of kexec are separated they two uses of kexec remain mutually exclusive and incompatible, and it I cannot merge your patches into the existing kexec patchset.

.....

In general I still your kexec on panic code is doing way to much, and I think a lot of that is that you don't have a kernel that will run when loaded at a different physical address.

To that end I have written a patch that accomplishes exactly that. Please see my just released kexec patchset.

Eric

#18 lore raw
Quoted 9 lines · Eric W. Biederman
Quoted 6 lines · Hariprasad Nellitheertha

Hi,

The patches that follow contain the initial implementation for kexec based crash dumping that we are working on. I had sent this to the fastboot mailing list a couple of weeks ago and this set of patches includes the changes made as per feedback from Andrew, Eric and others.

Quoted 4 lines

One significant change is missing. You do not separate out the two use cases of kexec. So on a system that is configured to use call sys_reboot(LINUX_REBOOT_CMD_KEXEC) on reboot I will get a core dump if using your code.

In some ways, whether we are doing a "crash dump" reboot or a "normal" kexec reboot is determined by the command line parameters that are passed to the kexec loaded kernel. If we do not restrict the memory size and do not add the keyword "dump" in the command line, it will do a normal kexec reboot. The dump file will not show up in the second kernel.

Quoted 4 lines

Or alternatively if I call sys_kexec_load and then something in the shutdown scripts triggers a kernel panic it is not OK to start boot the new kernel instead of taking normal panic behavior.

A way to disable kexec reboot from panic code is indeed needed. I will add the necessary code to do this.

Quoted 5 lines

Until the two uses of kexec are separated they two uses of kexec remain mutually exclusive and incompatible, and it I cannot merge your patches into the existing kexec patchset.

Quoted 8 lines

.....

In general I still your kexec on panic code is doing way to much, and I think a lot of that is that you don't have a kernel that will run when loaded at a different physical address.

To that end I have written a patch that accomplishes exactly that. Please see my just released kexec patchset.

Will work on the necessary changes so we can use your patchset.

Quoted 2 lines

Eric

Thanks and Regards, Hari

Signature · 4 lines
Hariprasad Nellitheertha
Linux Technology Center
India Software Labs
IBM India, Bangalore