rpms/kernel/FC-3 linux-2.6-alsa-snd-intel8x0m-semaphore.patch, NONE, 1.1 linux-2.6-crashdump-common.patch, NONE, 1.1 linux-2.6-crashdump-reboot-exports.patch, NONE, 1.1 linux-2.6-diskdump.patch, NONE, 1.1 linux-2.6-dump_smp_call_function.patch, NONE, 1.1 linux-2.6-netconsole.patch, NONE, 1.1 linux-2.6-netdump.patch, NONE, 1.1 linux-2.6-scsi-sym2-alloc_lcb_tags-atomic.patch, NONE, 1.1 kernel-2.6.spec, 1.868, 1.869 linux-2.6-compile-fixes.patch, 1.1, 1.2 linux-2.6.11-panic-stackdump.patch, 1.1, 1.2

fedora-cvs-commits at redhat.com fedora-cvs-commits at redhat.com
Fri Aug 26 08:26:23 UTC 2005


Author: davej

Update of /cvs/dist/rpms/kernel/FC-3
In directory cvs.devel.redhat.com:/tmp/cvs-serv5986

Modified Files:
	kernel-2.6.spec linux-2.6-compile-fixes.patch 
	linux-2.6.11-panic-stackdump.patch 
Added Files:
	linux-2.6-alsa-snd-intel8x0m-semaphore.patch 
	linux-2.6-crashdump-common.patch 
	linux-2.6-crashdump-reboot-exports.patch 
	linux-2.6-diskdump.patch 
	linux-2.6-dump_smp_call_function.patch 
	linux-2.6-netconsole.patch linux-2.6-netdump.patch 
	linux-2.6-scsi-sym2-alloc_lcb_tags-atomic.patch 
Log Message:
sync with FC-4


linux-2.6-alsa-snd-intel8x0m-semaphore.patch:
 intel8x0m.c |    2 ++
 1 files changed, 2 insertions(+)

--- NEW FILE linux-2.6-alsa-snd-intel8x0m-semaphore.patch ---
--- linux-2.6.12/sound/pci/intel8x0m.c~	2005-08-26 03:07:21.000000000 -0400
+++ linux-2.6.12/sound/pci/intel8x0m.c	2005-08-26 03:07:41.000000000 -0400
@@ -500,6 +500,8 @@ static unsigned short snd_intel8x0_codec
 			res = 0xffff;
 		}
 	}
+	if (reg == AC97_GPIO_STATUS)
+		iagetword(chip, 0); /* clear semaphore */
 	return res;
 }
 

linux-2.6-crashdump-common.patch:
 Documentation/sysrq.txt         |    8 +
 arch/i386/kernel/nmi.c          |    1 
 arch/i386/kernel/traps.c        |    3 
 arch/i386/mm/init.c             |   47 +++++++
 arch/i386/mm/pgtable.c          |    3 
 arch/ppc64/kernel/process.c     |    1 
 arch/ppc64/kernel/traps.c       |    3 
 arch/ppc64/mm/init.c            |   29 ++++
 arch/s390/kernel/traps.c        |    6 
 arch/x86_64/kernel/process.c    |    2 
 arch/x86_64/kernel/traps.c      |    6 
 arch/x86_64/mm/fault.c          |    1 
 arch/x86_64/mm/init.c           |   33 +++++
 drivers/char/sysrq.c            |   13 +-
 include/asm-generic/crashdump.h |   47 +++++++
 include/asm-i386/crashdump.h    |  123 ++++++++++++++++++++
 include/asm-i386/kmap_types.h   |    4 
 include/asm-ppc64/crashdump.h   |   61 +++++++++
 include/asm-x86_64/crashdump.h  |   86 +++++++++++++
 include/linux/kernel.h          |   18 ++
 kernel/Makefile                 |    2 
 kernel/dump.c                   |  246 ++++++++++++++++++++++++++++++++++++++++
 kernel/panic.c                  |    3 
 kernel/printk.c                 |   20 +++
 kernel/sched.c                  |    2 
 25 files changed, 763 insertions(+), 5 deletions(-)

--- NEW FILE linux-2.6-crashdump-common.patch ---
--- linux-2.6.12/drivers/char/sysrq.c.orig	2005-08-18 12:40:07.000000000 -0400
+++ linux-2.6.12/drivers/char/sysrq.c	2005-08-18 14:29:25.000000000 -0400
@@ -125,6 +125,17 @@
 	.enable_mask	= SYSRQ_ENABLE_BOOT,
 };
 
+/* crash sysrq handler */
+static void sysrq_handle_crash(int key, struct pt_regs *pt_regs,
+			       struct tty_struct *tty) {
+	*( (char *) 0) = 0;
+}
+static struct sysrq_key_op sysrq_crash_op = {
+	.handler =       sysrq_handle_crash,
+	.help_msg =      "Crash",
+	.action_msg =    "Crashing the kernel by request",
+};
+
 static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
 			      struct tty_struct *tty) 
 {
@@ -284,7 +284,7 @@ static struct sysrq_key_op *sysrq_key_ta
 		 it is handled specially on the sparc
 		 and will never arrive */
 /* b */	&sysrq_reboot_op,
-/* c */ NULL,
+/* c */ &sysrq_crash_op,
 /* d */	NULL,
 /* e */	&sysrq_term_op,
 /* f */	&sysrq_moom_op,
--- /dev/null	2005-08-18 08:15:49.820487896 -0400
+++ linux-2.6.12/include/asm-ppc64/crashdump.h	2005-08-18 14:23:59.000000000 -0400
@@ -0,0 +1,61 @@
+#ifndef _ASM_PPC64_CRASHDUMP_H
+#define _ASM_PPC64_CRASHDUMP_H
+
+/*
+ * linux/include/asm-ppc64/crashdump.h
+ *
+ * Copyright (c) 2003, 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef __KERNEL__
+
+#include <asm/time.h>
+
+extern int page_is_ram (unsigned long);
+extern unsigned long next_ram_page (unsigned long);
+
+#define platform_timestamp(x) (x = get_tb())
+
+#define platform_fix_regs()						\
+{									\
+       memcpy(&myregs, regs, sizeof(struct pt_regs));			\
+};
+
+#define platform_init_stack(stackptr) do { } while (0)
+#define platform_cleanup_stack(stackptr) do { } while (0)
+
+typedef asmlinkage void (*crashdump_func_t)(struct pt_regs *, void *);
+
+static inline void platform_start_crashdump(void *stackptr,
+					   crashdump_func_t dumpfunc,
+					   struct pt_regs *regs)
+{
+	dumpfunc(regs, NULL);
+}
+
+#define platform_freeze_cpu()					\
+{								\
+	current->thread.ksp = __get_SP();			\
+	for (;;) local_irq_disable();				\
+}
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_PPC64_CRASHDUMP_H */
--- /dev/null	2005-08-18 08:15:49.820487896 -0400
+++ linux-2.6.12/include/asm-x86_64/crashdump.h	2005-08-18 14:23:59.000000000 -0400
@@ -0,0 +1,86 @@
+/*
+ * include/asm-x86_64/crashdump.h
+ *
+ * Copyright (C) Hitachi, Ltd. 2004
+ * Written by Satoshi Oshima (oshima at sdl.hitachi.co.jp)
+ *
+ * Derived from include/asm-i386/diskdump.h
+ * Copyright (c) 2004 FUJITSU LIMITED
+ * Copyright (c) 2003 Red Hat, Inc. All rights reserved.
+ *
+ */
+
+#ifndef _ASM_X86_64_CRASHDUMP_H
+#define _ASM_X86_64_CRASHDUMP_H
+
+#ifdef __KERNEL__
+
+#include <linux/elf.h>
+
+extern int page_is_ram(unsigned long);
+extern unsigned long next_ram_page(unsigned long);
+
+#define platform_fix_regs() \
+{                                                                      \
+       unsigned long rsp;                                              \
+       unsigned short ss;                                              \
+       rsp = (unsigned long) ((char *)regs + sizeof (struct pt_regs)); \
+       ss = __KERNEL_DS;                                               \
+       if (regs->cs & 3) {                                             \
+               rsp = regs->rsp;                                        \
+               ss = regs->ss & 0xffff;                                 \
+       }                                                               \
+       myregs = *regs;                                                 \
+       myregs.rsp = rsp;                                               \
+       myregs.ss = (myregs.ss & (~0xffff)) | ss;                       \
+}
+
+#define platform_timestamp(x) rdtscll(x)
+
+#define platform_freeze_cpu()					\
+{								\
+	for (;;) local_irq_disable();				\
+}
+
+static inline void platform_init_stack(void **stackptr)
+{
+	struct page *page;
+
+	if ((page = alloc_page(GFP_KERNEL)))
+		*stackptr = (void *)page_address(page);
+
+	if (*stackptr)
+		memset(*stackptr, 0, PAGE_SIZE);
+	else
+		printk(KERN_WARNING
+		    "crashdump: unable to allocate separate stack\n");
+}
+
+#define platform_cleanup_stack(stackptr)               \
+do {                                                   \
+	if (stackptr)                                  \
+		free_page((unsigned long)stackptr);    \
+} while (0)
+
+typedef asmlinkage void (*crashdump_func_t)(struct pt_regs *, void *);
+
+static inline void platform_start_crashdump(void *stackptr,
+					    crashdump_func_t dumpfunc,
+					    struct pt_regs *regs)
+{								
+	static unsigned long old_rsp;
+	unsigned long new_rsp;
+
+	if (stackptr) {
+		asm volatile("movq %%rsp,%0" : "=r" (old_rsp));
+		new_rsp = (unsigned long)stackptr + PAGE_SIZE;
+		asm volatile("movq %0,%%rsp" :: "r" (new_rsp));
+		dumpfunc(regs, NULL);
+		asm volatile("movq %0,%%rsp" :: "r" (old_rsp));
+	} else
+		dumpfunc(regs, NULL);
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_X86_64_CRASHDUMP_H */
--- linux-2.6.12/include/asm-i386/kmap_types.h.orig	2005-06-17 15:48:29.000000000 -0400
+++ linux-2.6.12/include/asm-i386/kmap_types.h	2005-08-18 14:23:59.000000000 -0400
@@ -23,7 +23,9 @@
 D(10)	KM_IRQ1,
 D(11)	KM_SOFTIRQ0,
 D(12)	KM_SOFTIRQ1,
-D(13)	KM_TYPE_NR
+D(13)	KM_CRASHDUMP,
+D(14)	KM_UNUSED,
+D(15)	KM_TYPE_NR
 };
 
 #undef D
--- /dev/null	2005-08-18 08:15:49.820487896 -0400
+++ linux-2.6.12/include/asm-i386/crashdump.h	2005-08-18 14:23:59.000000000 -0400
@@ -0,0 +1,123 @@
+#ifndef _ASM_I386_CRASHDUMP_H
+#define _ASM_I386_CRASHDUMP_H
+
+/*
+ * linux/include/asm-i386/crashdump.h
+ *
+ * Copyright (c) 2003, 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef __KERNEL__
+
+#include <asm/irq.h>
+
+/*
+ *  Structure taken from arch/i386/kernel/irq.c.  It used to live in asm/irq.h.
+ */
+#ifdef CONFIG_4KSTACKS
+union dump_irq_ctx {
+	struct thread_info	tinfo;
+	u32			stack[THREAD_SIZE/sizeof(u32)];
+};
+#endif
+
+extern int page_is_ram (unsigned long);
+extern unsigned long next_ram_page (unsigned long);
+
+#define platform_timestamp(x) rdtscll(x)
+
+#define platform_fix_regs()						\
+{									\
+       unsigned long esp;						\
+       unsigned short ss;						\
+       esp = (unsigned long) ((char *)regs + sizeof (struct pt_regs));	\
+       ss = __KERNEL_DS;						\
+       if (regs->xcs & 3) {						\
+               esp = regs->esp;						\
+               ss = regs->xss & 0xffff;					\
+       }								\
+       myregs = *regs;							\
+       myregs.esp = esp;						\
+       myregs.xss = (myregs.xss & 0xffff0000) | ss;			\
+};
+
+static inline void platform_init_stack(void **stackptr)
+{
+#ifdef CONFIG_4KSTACKS
+	*stackptr = (void *)kmalloc(sizeof(union dump_irq_ctx), GFP_KERNEL);
+	if (*stackptr)
+		memset(*stackptr, 0, sizeof(union dump_irq_ctx));
+	else
+		printk(KERN_WARNING
+		       "crashdump: unable to allocate separate stack\n");
+#else
+	*stackptr = NULL;
+#endif
+}
+
+typedef asmlinkage void (*crashdump_func_t)(struct pt_regs *, void *);
+
+static inline void platform_start_crashdump(void *stackptr,
+					   crashdump_func_t dumpfunc,
+					   struct pt_regs *regs)
+{
+	if (!stackptr)
+		dumpfunc(regs, NULL);
+#ifdef CONFIG_4KSTACKS
+	else {
+		u32 *dsp;
+		union dump_irq_ctx * curctx;
+		union dump_irq_ctx * dumpctx;
+
+		curctx = (union dump_irq_ctx *) current_thread_info();
+		dumpctx = (union dump_irq_ctx *) stackptr;
+
+		/* build the stack frame on the IRQ stack */
+		dsp = (u32*) ((char*)dumpctx + sizeof(*dumpctx));
+		dumpctx->tinfo.task = curctx->tinfo.task;
+		dumpctx->tinfo.previous_esp = current_stack_pointer;
+
+		*--dsp = (u32) NULL;
+		*--dsp = (u32) regs;
+
+		asm volatile(
+			"       xchgl   %%ebx,%%esp     \n"
+			"	call    *%%eax          \n"
+			"	xchgl   %%ebx,%%esp     \n"
+			: : "a"(dumpfunc), "b"(dsp)
+			: "memory", "cc", "edx", "ecx"
+		);
+	}
+#endif
+}
+
+#define platform_cleanup_stack(stackptr)	\
+do {						\
+	if (stackptr)				\
+		kfree(stackptr);		\
+} while (0)
+
+#define platform_freeze_cpu()					\
+{								\
+	for (;;) local_irq_disable();				\
+}
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_I386_CRASHDUMP_H */
--- linux-2.6.12/include/linux/kernel.h.orig	2005-08-18 12:41:12.000000000 -0400
+++ linux-2.6.12/include/linux/kernel.h	2005-08-18 14:23:59.000000000 -0400
@@ -175,6 +175,17 @@
 extern void add_taint(unsigned);
 extern int check_tainted(void);
 
+#define crashdump_mode()       unlikely(netdump_mode || diskdump_mode)
+
+struct pt_regs;
+extern void try_crashdump(struct pt_regs *);
+extern void (*netdump_func) (struct pt_regs *regs);
+extern int netdump_mode;
+extern void (*diskdump_func) (struct pt_regs *regs);
+extern int diskdump_mode;
+
+#define crashdump_func()	unlikely(netdump_func || diskdump_func)
+
 /* Values used for system_state */
 extern enum system_states {
 	SYSTEM_BOOTING,
@@ -182,6 +193,7 @@
 	SYSTEM_HALT,
 	SYSTEM_POWER_OFF,
 	SYSTEM_RESTART,
+	SYSTEM_DUMPING,
 } system_state;
 
 #define TAINT_PROPRIETARY_MODULE	(1<<0)
@@ -204,6 +216,12 @@
 #define pr_info(fmt,arg...) \
 	printk(KERN_INFO fmt,##arg)
 
+#define pr_err(fmt,arg...) \
+	printk(KERN_ERR fmt,##arg)
+
+#define pr_warn(fmt,arg...) \
+	printk(KERN_WARNING fmt,##arg)
+
 /*
  *      Display an IP address in readable format.
  */
--- /dev/null	2005-08-18 08:15:49.820487896 -0400
+++ linux-2.6.12/include/asm-generic/crashdump.h	2005-08-18 14:23:59.000000000 -0400
@@ -0,0 +1,47 @@
+#ifndef _ASM_GENERIC_CRASHDUMP_H_
+#define _ASM_GENERIC_CRASHDUMP_H_
+
+/*
+ * linux/include/asm-generic/crashdump.h
+ *
+ * Copyright (c) 2003, 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __KERNEL__
+
+#define platform_timestamp(x) do { (x) = 0; } while (0)  
+
+#define platform_fix_regs() do { } while (0)
+#define platform_init_stack(stackptr) do { } while (0)
+#define platform_cleanup_stack(stackptr) do { } while (0)
+#define platform_start_crashdump(stackptr,dumpfunc,regs) (0)
+
+#undef ELF_CORE_COPY_REGS
+#define ELF_CORE_COPY_REGS(x, y) do { struct pt_regs *z; z = (y); } while (0)
+
+#define show_mem() do {} while (0)
+
+#define show_state() do {} while (0)
+
+#define show_regs(x) do { struct pt_regs *z; z = (x); } while (0)
+
+#undef KM_CRASHDUMP
+#define KM_CRASHDUMP 0
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_GENERIC_CRASHDUMP_H */
--- linux-2.6.12/Documentation/sysrq.txt.orig	2005-08-18 12:39:53.000000000 -0400
+++ linux-2.6.12/Documentation/sysrq.txt	2005-08-18 14:23:59.000000000 -0400
@@ -74,6 +74,10 @@
 
 'c'	- Will perform a kexec reboot in order to take a crashdump.
 
+'c'     - Intentionally crash the system without syncing or unmounting
+          your disks.  This is most useful if the NETDUMP client package
+          and/or the DISKDUMP package have been installed.
+
 'o'     - Will shut your system off (if configured and supported).
 
 's'     - Will attempt to sync all mounted filesystems.
@@ -127,6 +131,10 @@
 'C'rashdump can be used to manually trigger a crashdump when the system is hung.
 The kernel needs to have been built with CONFIG_KEXEC enabled.
 
+'C'rash immediately crashes your system.  This is most useful if the machine
+has been configured as a NETDUMP client because an OOPS report is generated
+and a kernel crash dump is sent to the NETDUMP server.
+
 'S'ync is great when your system is locked up, it allows you to sync your
 disks and will certainly lessen the chance of data loss and fscking. Note
 that the sync hasn't taken place until you see the "OK" and "Done" appear
--- /dev/null	2005-08-18 08:15:49.820487896 -0400
+++ linux-2.6.12/kernel/dump.c	2005-08-18 14:23:59.000000000 -0400
@@ -0,0 +1,246 @@
+/*
+ *  linux/kernel/dump.c
+ *
+ *  Copyright (C) 2004  FUJITSU LIMITED
+ *  Written by Nobuhiro Tachino (ntachino at jp.fujitsu.com)
+ *
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/nmi.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/genhd.h>
+#include <linux/diskdump.h>
+#include <asm/diskdump.h>
+
+static DECLARE_MUTEX(dump_ops_mutex);
+struct disk_dump_ops* dump_ops = NULL;
+
+int diskdump_mode = 0;
+EXPORT_SYMBOL_GPL(diskdump_mode);
+
+void (*diskdump_func) (struct pt_regs *regs) = NULL;
+EXPORT_SYMBOL_GPL(diskdump_func);
+
+static unsigned long long timestamp_base;
+static unsigned long timestamp_hz;
+
+
+/*
+ * register/unregister diskdump operations
+ */
+int diskdump_register_ops(struct disk_dump_ops* op)
+{
+	down(&dump_ops_mutex);
+	if (dump_ops) {
+		up(&dump_ops_mutex);
+		return -EEXIST;
+	}
+	dump_ops = op;
+	up(&dump_ops_mutex);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(diskdump_register_ops);
+
+void diskdump_unregister_ops(void)
+{
+	down(&dump_ops_mutex);
+	dump_ops = NULL;
+	up(&dump_ops_mutex);
+}
+
+EXPORT_SYMBOL_GPL(diskdump_unregister_ops);
+
+
+/*
+ * sysfs interface
+ */
+static struct gendisk *device_to_gendisk(struct device *dev)
+{
+	struct dentry *d;
+	struct qstr qstr;
+
+	/* trace symlink to "block" */
+	qstr.name = "block";
+	qstr.len = strlen(qstr.name);
+	qstr.hash = full_name_hash(qstr.name, qstr.len);
+	d = d_lookup(dev->kobj.dentry, &qstr);
+	if (!d || !d->d_fsdata)
+		return NULL;
+	else
+		return container_of(d->d_fsdata, struct gendisk, kobj);
+}
+
+ssize_t diskdump_sysfs_store(struct device *dev, const char *buf, size_t count)
+{
+	struct gendisk *disk;
+	struct block_device *bdev;
+	int part, remove = 0;
+
+	if (!dump_ops || !dump_ops->add_dump || !dump_ops->remove_dump)
+		return count;
+
+	/* get partition number */
+	sscanf (buf, "%d\n", &part);
+	if (part < 0) {
+		part = -part;
+		remove = 1;
+	}
+
+	/* get block device */
+	if (!(disk = device_to_gendisk(dev)) ||
+	    !(bdev = bdget_disk(disk, part)))
+		return count;
+
+	/* add/remove device */
+	down(&dump_ops_mutex);
+	if (!remove)
+		dump_ops->add_dump(dev, bdev);
+	else
+		dump_ops->remove_dump(bdev);
+	up(&dump_ops_mutex);
+
+	return count;
+}
+
+EXPORT_SYMBOL_GPL(diskdump_sysfs_store);
+
+ssize_t diskdump_sysfs_show(struct device *dev, char *buf)
+{
+	struct gendisk *disk;
+	struct block_device *bdev;
+	int part, tmp, len = 0, maxlen = 1024;
+	char* p = buf; 
+	char name[BDEVNAME_SIZE];
+
+	if (!dump_ops || !dump_ops->find_dump)
+		return 0;
+
+	/* get gendisk */
+	disk = device_to_gendisk(dev);
+	if (!disk || !disk->part)
+		return 0;
+
+	/* print device */
+	down(&dump_ops_mutex);
+	for (part = 0; part < disk->minors - 1; part++) {
+		bdev = bdget_disk(disk, part);
+		if (dump_ops->find_dump(bdev)) {
+			tmp = sprintf(p, "%s\n", bdevname(bdev, name));
+			len += tmp;
+			p += tmp;
+		}
+		bdput(bdev);
+		if(len >= maxlen)
+			break;
+	}
+	up(&dump_ops_mutex);
+
+	return len;
+}
+
+EXPORT_SYMBOL_GPL(diskdump_sysfs_show);
+
+/*
+ * run timer/tasklet/workqueue during dump
+ */
+void diskdump_setup_timestamp(void)
+{
+	unsigned long long t;
+
+	platform_timestamp(timestamp_base);
+	udelay(1000000/HZ);
+	platform_timestamp(t);
+	timestamp_hz = (unsigned long)(t - timestamp_base);
+	diskdump_update();
+}
+
+EXPORT_SYMBOL_GPL(diskdump_setup_timestamp);
+
+void diskdump_update(void)
+{
+	unsigned long long t;
+
+	touch_nmi_watchdog();
+
+	/* update jiffies */
+	platform_timestamp(t);
+	while (t > timestamp_base + timestamp_hz) {
+		timestamp_base += timestamp_hz;
+		jiffies++;
+		platform_timestamp(t);
+	}
+
+	dump_run_timers();
+	dump_run_tasklet();
+	dump_run_workqueue();
+}
+
+EXPORT_SYMBOL_GPL(diskdump_update);
+
+
+/*
+ * register/unregister hook
+ */
+int diskdump_register_hook(void (*dump_func) (struct pt_regs *))
+{
+	if (diskdump_func)
+		return -EEXIST;
+
+	diskdump_func = dump_func;
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(diskdump_register_hook);
+
+void diskdump_unregister_hook(void)
+{
+	diskdump_func = NULL;
+}
+
+EXPORT_SYMBOL_GPL(diskdump_unregister_hook);
+
+void (*netdump_func) (struct pt_regs *regs) = NULL;
+int netdump_mode = 0;
+EXPORT_SYMBOL_GPL(netdump_mode);
+
+/*
+ * Try crashdump. Diskdump is first, netdump is second.
+ * We clear diskdump_func before call of diskdump_func, so
+ * If double panic would occur in diskdump, netdump can handle
+ * it.
+ */
+void try_crashdump(struct pt_regs *regs)
+{
+	void (*func)(struct pt_regs *);
+
+	if (diskdump_func) {
+		func = diskdump_func;
+		diskdump_func = NULL;
+		func(regs);
+	}
+	if (netdump_func)
+		netdump_func(regs);
+}
--- linux-2.6.12/kernel/printk.c.orig	2005-08-18 12:40:55.000000000 -0400
+++ linux-2.6.12/kernel/printk.c	2005-08-18 14:23:59.000000000 -0400
@@ -357,6 +357,20 @@
 }
 
 /*
+ * Crashdump special routine. Don't print to global log_buf, just to the
+ * actual console device(s).
+ */
+static void crashdump_call_console_drivers(const char *buf, unsigned long len)
+{
+	struct console *con;
+
+	for (con = console_drivers; con; con = con->next) {
+		if ((con->flags & CON_ENABLED) && con->write)
+			con->write(con, buf, len);
+	}
+}
+
+/*
  * Call the console drivers on a range of log_buf
  */
 static void __call_console_drivers(unsigned long start, unsigned long end)
@@ -531,6 +545,12 @@
 	/* Emit the output into the temporary buffer */
 	printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
 
+	if (unlikely(crashdump_mode())) {
+		crashdump_call_console_drivers(printk_buf, printed_len);
+		spin_unlock_irqrestore(&logbuf_lock, flags);
+		goto out;
+	}
+
 	/*
 	 * Copy the output into log_buf.  If the caller didn't provide
 	 * appropriate log level tags, we insert them here
--- linux-2.6.12/kernel/Makefile.orig	2005-08-18 12:41:10.000000000 -0400
+++ linux-2.6.12/kernel/Makefile	2005-08-18 14:23:59.000000000 -0400
@@ -7,7 +7,7 @@
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o pid.o \
 	    rcupdate.o intermodule.o extable.o params.o posix-timers.o \
-	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o
+	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o dump.o
 
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
--- linux-2.6.12/kernel/sched.c.orig	2005-08-18 12:41:14.000000000 -0400
+++ linux-2.6.12/kernel/sched.c	2005-08-18 14:32:27.000000000 -0400
@@ -4177,6 +4177,8 @@
 	read_unlock(&tasklist_lock);
 }
 
+EXPORT_SYMBOL_GPL(show_state);
+
 /**
  * init_idle - set up an idle thread for a given CPU
  * @idle: task in question
--- linux-2.6.12/kernel/panic.c~	2005-08-26 02:38:59.000000000 -0400
+++ linux-2.6.12/kernel/panic.c	2005-08-26 02:39:18.000000000 -0400
@@ -70,6 +70,9 @@ NORET_TYPE void panic(const char * fmt, 
 	printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
 	bust_spinlocks(0);
 
+	if (crashdump_func())
+		BUG();
+
 #ifdef CONFIG_SMP
 	smp_send_stop();
 #endif
--- linux-2.6.12/arch/s390/kernel/traps.c.orig	2005-08-18 12:40:01.000000000 -0400
+++ linux-2.6.12/arch/s390/kernel/traps.c	2005-08-18 14:23:59.000000000 -0400
@@ -286,12 +286,16 @@
 	bust_spinlocks(1);
 	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
         show_regs(regs);
+	try_crashdump(regs);  
 	bust_spinlocks(0);
         spin_unlock_irq(&die_lock);
 	if (in_interrupt())
 		panic("Fatal exception in interrupt");
-	if (panic_on_oops)
+	if (panic_on_oops) {
+		if (netdump_func)
+			netdump_func = NULL;
 		panic("Fatal exception: panic_on_oops");
+	}
         do_exit(SIGSEGV);
 }
 
--- linux-2.6.12/arch/i386/mm/init.c.orig	2005-08-18 12:41:14.000000000 -0400
+++ linux-2.6.12/arch/i386/mm/init.c	2005-08-18 14:23:58.000000000 -0400
@@ -229,6 +229,53 @@
 	return 0;
 }
 
+unsigned long next_ram_page(unsigned long pagenr)
+{
+	int i;
+	unsigned long addr, end;
+	unsigned long min_pageno = ULONG_MAX;
+
+	pagenr++;
+
+	if (efi_enabled) {
+		efi_memory_desc_t *md;
+
+		for (i = 0; i < memmap.nr_map; i++) {
+			md = &memmap.map[i];
+			if (!is_available_memory(md))
+				continue;
+			addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT;
+			end = (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> PAGE_SHIFT;
+
+			if ((pagenr >= addr) && (pagenr < end))
+				return pagenr;
+			if ((pagenr < addr) && (addr < min_pageno))
+				min_pageno = addr;
+		}
+		return min_pageno;
+	}
+
+	for (i = 0; i < e820.nr_map; i++) {
+
+		if (e820.map[i].type != E820_RAM)	/* not usable memory */
+			continue;
+		/*
+		 *	!!!FIXME!!! Some BIOSen report areas as RAM that
+		 *	are not. Notably the 640->1Mb area. We need a sanity
+		 *	check here.
+		 */
+		addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
+		end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT;
+		if  ((pagenr >= addr) && (pagenr < end))
+			return pagenr;
+		if ((pagenr < addr) && (addr < min_pageno))
+			min_pageno = addr;
+	}
+	return min_pageno;
+}
+
+EXPORT_SYMBOL_GPL(next_ram_page);
+
 /*
  * devmem_is_allowed() checks to see if /dev/mem access to a certain address is
  * valid. The argument is a physical page number.
--- linux-2.6.12/arch/i386/mm/pgtable.c.orig	2005-08-18 12:39:56.000000000 -0400
+++ linux-2.6.12/arch/i386/mm/pgtable.c	2005-08-18 14:23:58.000000000 -0400
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <linux/spinlock.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -63,6 +64,8 @@
 	printk(KERN_INFO "%lu pages pagetables\n", ps.nr_page_table_pages);
 }
 
+EXPORT_SYMBOL_GPL(show_mem);
+
 /*
  * Associate a virtual page frame with a given physical page frame 
  * and protection flags for that frame.
--- linux-2.6.12/arch/i386/kernel/traps.c.orig	2005-08-18 14:09:19.000000000 -0400
+++ linux-2.6.12/arch/i386/kernel/traps.c	2005-08-18 14:10:35.000000000 -0400
@@ -342,6 +342,7 @@
 			printk("\n");
 	notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
 		show_registers(regs);
+		try_crashdump(regs);
   	} else
 		printk(KERN_ERR "Recursive die() failure, output suppressed\n");
 
@@ -356,6 +357,8 @@
 		panic("Fatal exception in interrupt");
 
 	if (panic_on_oops) {
+		if (netdump_func)
+			netdump_func = NULL;
 		printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
 		ssleep(5);
 		panic("Fatal exception");
--- linux-2.6.12/arch/i386/kernel/nmi.c.orig	2005-08-18 14:06:49.000000000 -0400
+++ linux-2.6.12/arch/i386/kernel/nmi.c	2005-08-18 14:06:56.000000000 -0400
@@ -577,3 +577,4 @@
 EXPORT_SYMBOL(release_lapic_nmi);
 EXPORT_SYMBOL(disable_timer_nmi_watchdog);
 EXPORT_SYMBOL(enable_timer_nmi_watchdog);
+EXPORT_SYMBOL(touch_nmi_watchdog);
--- linux-2.6.12/arch/x86_64/mm/fault.c.orig	2005-08-18 12:41:10.000000000 -0400
+++ linux-2.6.12/arch/x86_64/mm/fault.c	2005-08-18 14:23:59.000000000 -0400
@@ -534,6 +534,7 @@
 	__die("Oops", regs, error_code);
 	/* Executive summary in case the body of the oops scrolled away */
 	printk(KERN_EMERG "CR2: %016lx\n", address);
+	try_crashdump(regs);
 	oops_end(); 
 	do_exit(SIGKILL);
 
--- linux-2.6.12/arch/x86_64/mm/init.c.orig	2005-08-18 12:41:25.000000000 -0400
+++ linux-2.6.12/arch/x86_64/mm/init.c	2005-08-18 14:23:59.000000000 -0400
@@ -23,6 +23,7 @@
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
 #include <linux/proc_fs.h>
+#include <linux/module.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -85,6 +86,8 @@
 	printk("%d pages swap cached\n",cached);
 }
 
+EXPORT_SYMBOL_GPL(show_mem);
+
 /* References to section boundaries */
 
 extern char _text, _etext, _edata, __bss_start, _end[];
@@ -398,6 +401,35 @@
 
 extern int swiotlb_force;
 
+unsigned long next_ram_page (unsigned long pagenr)
+{
+	int i;
+	unsigned long min_pageno = ULONG_MAX;
+
+	pagenr++;
+
+	for (i = 0; i < e820.nr_map; i++) {
+		unsigned long addr, end;
+
+		if (e820.map[i].type != E820_RAM)	/* not usable memory */
+			continue;
+		/*
+		 *	!!!FIXME!!! Some BIOSen report areas as RAM that
+		 *	are not. Notably the 640->1Mb area. We need a sanity
+		 *	check here.
+		 */
+		addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
+		end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT;
+		if  ((pagenr >= addr) && (pagenr < end))
+			return pagenr;
+		if ((pagenr < addr) && (addr < min_pageno))
+			min_pageno = addr;
+	}
+	return min_pageno;
+}
+
+EXPORT_SYMBOL_GPL(next_ram_page);
+
 /*
  * devmem_is_allowed() checks to see if /dev/mem access to a certain address is
  * valid. The argument is a physical page number.
@@ -577,6 +609,7 @@
 		return 0;
 	return pfn_valid(pte_pfn(*pte));
 }
+EXPORT_SYMBOL_GPL(kern_addr_valid);
 
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
--- linux-2.6.12/arch/x86_64/kernel/process.c.orig	2005-08-18 12:41:10.000000000 -0400
+++ linux-2.6.12/arch/x86_64/kernel/process.c	2005-08-18 14:23:59.000000000 -0400
@@ -314,6 +314,8 @@
 	show_trace(&regs->rsp);
 }
 
+EXPORT_SYMBOL_GPL(show_regs);
+
 /*
  * Free current thread data structures etc..
  */
--- linux-2.6.12/arch/x86_64/kernel/traps.c.orig	2005-08-18 12:40:02.000000000 -0400
+++ linux-2.6.12/arch/x86_64/kernel/traps.c	2005-08-18 14:23:59.000000000 -0400
@@ -363,8 +363,11 @@
 	die_owner = -1;
 	bust_spinlocks(0); 
 	spin_unlock(&die_lock); 
-	if (panic_on_oops)
+	if (panic_on_oops) {
+		if (netdump_func)
+			netdump_func = NULL;
 		panic("Oops"); 
+	}
 } 
 
 void __die(const char * str, struct pt_regs * regs, long err)
@@ -394,6 +397,7 @@
 	oops_begin();
 	handle_BUG(regs);
 	__die(str, regs, err);
+	try_crashdump(regs);
 	oops_end();
 	do_exit(SIGSEGV); 
 }
--- linux-2.6.12/arch/ppc64/mm/init.c.orig	2005-08-18 12:41:13.000000000 -0400
+++ linux-2.6.12/arch/ppc64/mm/init.c	2005-08-18 14:23:59.000000000 -0400
@@ -113,6 +113,7 @@
 	printk("%ld pages shared\n", shared);
 	printk("%ld pages swap cached\n", cached);
 }
+EXPORT_SYMBOL_GPL(show_mem);
 
 #ifdef CONFIG_PPC_ISERIES
 
@@ -528,6 +529,34 @@
 }
 EXPORT_SYMBOL(page_is_ram);
 
+unsigned long next_ram_page(unsigned long pfn)
+{
+	int i;
+	unsigned long paddr, base;
+	unsigned long best_base = (ULONG_MAX << PAGE_SHIFT);
+
+	pfn++;
+	paddr = (pfn << PAGE_SHIFT);
+                                                                                
+	for (i=0; i < lmb.memory.cnt; i++) {
+#ifdef CONFIG_MSCHUNKS
+		base = lmb.memory.region[i].physbase;
+#else
+		base = lmb.memory.region[i].base;
+#endif
+		if ((paddr >= base)
+		    && (paddr < (base + lmb.memory.region[i].size)))
+			return (paddr >> PAGE_SHIFT);
+		if ((paddr < base) && (base < best_base))
+			best_base = base;
+	}
+	if (best_base < (ULONG_MAX << PAGE_SHIFT))
+		return (best_base >> PAGE_SHIFT);
+	else
+		return ULONG_MAX;
+}
+EXPORT_SYMBOL_GPL(next_ram_page);
+
 /*
  * Initialize the bootmem system and give it all the memory we
  * have available.
--- linux-2.6.12/arch/ppc64/kernel/process.c.orig	2005-08-18 12:40:01.000000000 -0400
+++ linux-2.6.12/arch/ppc64/kernel/process.c	2005-08-18 14:23:59.000000000 -0400
@@ -257,6 +257,7 @@
 
 	printk("\n");
 }
+EXPORT_SYMBOL_GPL(show_regs);
 
 void show_regs(struct pt_regs * regs)
 {
--- linux-2.6.12/arch/ppc64/kernel/traps.c.orig	2005-08-18 12:40:01.000000000 -0400
+++ linux-2.6.12/arch/ppc64/kernel/traps.c	2005-08-18 14:23:59.000000000 -0400
@@ -135,6 +135,7 @@
 		printk("\n");
 	print_modules();
 	show_regs(regs);
+	try_crashdump(regs);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
 
@@ -142,6 +143,8 @@
 		panic("Fatal exception in interrupt");
 
 	if (panic_on_oops) {
+		if (netdump_func)
+			netdump_func = NULL;
 		printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
 		ssleep(5);
 		panic("Fatal exception");

linux-2.6-crashdump-reboot-exports.patch:
 process.c |    2 ++
 1 files changed, 2 insertions(+)

--- NEW FILE linux-2.6-crashdump-reboot-exports.patch ---
--- linux-2.6.12/arch/i386/kernel/process.c.orig	2005-08-22 14:06:18.768231301 -0400
+++ linux-2.6.12/arch/i386/kernel/process.c	2005-08-22 14:06:19.889041887 -0400
@@ -327,6 +327,8 @@ void show_regs(struct pt_regs * regs)
 	show_trace(NULL, &regs->esp);
 }
 
+EXPORT_SYMBOL(show_regs);
+
 /*
  * This gets run with %ebx containing the
  * function to call, and %edx containing

linux-2.6-diskdump.patch:
 drivers/block/Kconfig          |    5 
 drivers/block/Makefile         |    1 
 drivers/block/diskdump.c       | 1121 +++++++++++++++++++++++++++++++++++++++++
 include/asm-generic/diskdump.h |   13 
 include/asm-i386/diskdump.h    |   55 ++
 include/asm-ia64/diskdump.h    |   63 ++
 include/asm-ppc/diskdump.h     |    6 
 include/asm-ppc64/diskdump.h   |   55 ++
 include/asm-s390/diskdump.h    |    6 
 include/asm-x86_64/diskdump.h  |   44 +
 include/linux/diskdump.h       |  186 ++++++
 include/linux/interrupt.h      |    4 
 include/linux/timer.h          |    3 
 include/linux/workqueue.h      |    3 
 kernel/softirq.c               |   32 +
 kernel/timer.c                 |   45 +
 kernel/workqueue.c             |   34 +
 17 files changed, 1671 insertions(+), 5 deletions(-)

--- NEW FILE linux-2.6-diskdump.patch ---
--- linux-2.6.12/drivers/block/Kconfig.diskdump.orig	2005-06-17 15:48:29.000000000 -0400
+++ linux-2.6.12/drivers/block/Kconfig	2005-08-19 16:47:34.228261668 -0400
@@ -495,6 +495,11 @@ config CDROM_PKTCDVD_WCACHE
 	  this option is dangerous unless the CD-RW media is known good, as we
 	  don't do deferred write error handling yet.
 
+config DISKDUMP
+	tristate "Disk dump support"
+	---help---
+	  Disk dump support.
+
 source "drivers/s390/block/Kconfig"
 
 source "drivers/block/Kconfig.iosched"
--- linux-2.6.12/drivers/block/Makefile.diskdump.orig	2005-06-17 15:48:29.000000000 -0400
+++ linux-2.6.12/drivers/block/Makefile	2005-08-19 16:47:34.229261501 -0400
@@ -45,3 +45,4 @@ obj-$(CONFIG_VIODASD)		+= viodasd.o
 obj-$(CONFIG_BLK_DEV_SX8)	+= sx8.o
 obj-$(CONFIG_BLK_DEV_UB)	+= ub.o
 
+obj-$(CONFIG_DISKDUMP)		+= diskdump.o
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/drivers/block/diskdump.c	2005-08-19 16:47:34.227261834 -0400
@@ -0,0 +1,1121 @@
+/*
+ *  linux/drivers/block/diskdump.c
+ *
+ *  Copyright (C) 2004  FUJITSU LIMITED
+ *  Copyright (C) 2002  Red Hat, Inc.
+ *  Written by Nobuhiro Tachino (ntachino at jp.fujitsu.com)
+ *
+ *  Some codes were derived from netdump and copyright belongs to
+ *  Red Hat, Inc.
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/highmem.h>
+#include <linux/smp_lock.h>
+#include <linux/nmi.h>
+#include <linux/crc32.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/diskdump.h>
+#include <asm/diskdump.h>
+
+#define Dbg(x, ...)	pr_debug("disk_dump: " x "\n", ## __VA_ARGS__)
+#define Err(x, ...)	pr_err  ("disk_dump: " x "\n", ## __VA_ARGS__)
+#define Warn(x, ...)	pr_warn ("disk_dump: " x "\n", ## __VA_ARGS__)
+#define Info(x, ...)	pr_info ("disk_dump: " x "\n", ## __VA_ARGS__)
+
+#define ROUNDUP(x, y)	(((x) + ((y)-1))/(y))
+
+/* 512byte sectors to blocks */
+#define SECTOR_BLOCK(s)	((s) >> (DUMP_BLOCK_SHIFT - 9))
+
+/* The number of block which is used for saving format information */
+#define USER_PARAM_BLOCK	2
+
+static int fallback_on_err = 1;
+static int allow_risky_dumps = 1;
+static unsigned int block_order = 2;
+static int sample_rate = 8;
+module_param_named(fallback_on_err, fallback_on_err, bool, S_IRUGO|S_IWUSR);
+module_param_named(allow_risky_dumps, allow_risky_dumps, bool, S_IRUGO|S_IWUSR);
+module_param_named(block_order, block_order, uint, S_IRUGO|S_IWUSR);
+module_param_named(sample_rate, sample_rate, int, S_IRUGO|S_IWUSR);
+
+static unsigned long timestamp_1sec;
+static uint32_t module_crc;
+static char *scratch;
+static struct disk_dump_header dump_header;
+static struct disk_dump_sub_header dump_sub_header;
+
+/* Registered dump devices */
+static LIST_HEAD(disk_dump_devices);
+
+/* Registered dump types, e.g. SCSI, ... */
+static LIST_HEAD(disk_dump_types);
+
+static DECLARE_MUTEX(disk_dump_mutex);
+
+static unsigned int header_blocks;		/* The size of all headers */
+static unsigned int bitmap_blocks;		/* The size of bitmap header */
+static unsigned int total_ram_blocks;		/* The size of memory */
+static unsigned int total_blocks;		/* The sum of above */
+/*
+ * This is not a parameter actually, but used to pass the number of
+ * required blocks to userland tools
+ */
+module_param_named(total_blocks, total_blocks, uint, S_IRUGO);
+
+struct notifier_block *disk_dump_notifier_list;
+EXPORT_SYMBOL_GPL(disk_dump_notifier_list);
+
+unsigned long volatile diskdump_base_jiffies;
+void *diskdump_stack;
+enum disk_dump_states disk_dump_state = DISK_DUMP_INITIAL;
+
+extern int panic_timeout;
+extern unsigned long max_pfn;
+
+static asmlinkage void disk_dump(struct pt_regs *, void *);
+
+
+#if CONFIG_SMP
+static void freeze_cpu(void *dummy)
+{
+	unsigned int cpu = smp_processor_id();
+
+	dump_header.tasks[cpu] = current;
+
+	platform_freeze_cpu();
+}
+#endif
+
+static int lapse = 0;		/* 200msec unit */
+
+static inline unsigned long eta(unsigned long nr, unsigned long maxnr)
+{
+	unsigned long long eta;
+
+	if (nr == 0)
+		nr = 1;
+
+	eta = ((maxnr << 8) / nr) * (unsigned long long)lapse;
+
+	return (unsigned long)(eta >> 8) - lapse;
+}
+
+static inline void print_status(unsigned int nr, unsigned int maxnr)
+{
+	static char *spinner = "/|\\-";
+	static unsigned long long prev_timestamp = 0;
+	unsigned long long timestamp;
+
+	if (nr == 0)
+		nr++;
+
+	platform_timestamp(timestamp);
+
+	if (timestamp - prev_timestamp > (timestamp_1sec/5)) {
+		prev_timestamp = timestamp;
+		lapse++;
+		printk("%u/%u    %lu ETA %c          \r",
+			nr, maxnr, eta(nr, maxnr) / 5, spinner[lapse & 3]);
+	}
+}
+
+static inline void clear_status(int nr, int maxnr)
+{
+	printk("                                       \r");
+	lapse = 0;
+}
+
+/*
+ * Checking the signature on a block. The format is as follows.
+ *
+ * 1st word = 'disk'
+ * 2nd word = 'dump'
+ * 3rd word = block number
+ * 4th word = ((block number + 7) * 11) & 0xffffffff
+ * 5th word = ((4th word + 7)* 11) & 0xffffffff
+ * ..
+ *
+ * Return 1 if the signature is correct, else return 0
+ */
+static int check_block_signature(void *buf, unsigned int block_nr)
+{
+	int word_nr = PAGE_SIZE / sizeof(int);
+	int *words = buf;
+	unsigned int val;
+	int i;
+
+	/*
+	 * Block 2 is used for the area which formatter saves options like
+	 * the sampling rate or the number of blocks. the Kernel part does not
+	 * check this block.
+	 */
+	if (block_nr == USER_PARAM_BLOCK)
+		return 1;
+
+	if (memcmp(buf, DUMP_PARTITION_SIGNATURE, sizeof(*words)))
+		return 0;
+
+	val = block_nr;
+	for (i = 2; i < word_nr; i++) {
+		if (words[i] != val)
+			return 0;
+		val = (val + 7) * 11;
+	}
+
+	return 1;
+}
+
+/*
+ * Read one block into the dump partition
+ */
+static int read_blocks(struct disk_dump_partition *dump_part, unsigned int nr,
+		       char *buf, int len)
+{
+	struct disk_dump_device *device = dump_part->device;
+	int ret;
+
+	local_irq_disable();
+	touch_nmi_watchdog();
+	ret = device->ops.rw_block(dump_part, READ, nr, buf, len);
+	if (ret < 0) {
+		Err("read error on block %u", nr);
+		return ret;
+	}
+	return 0;
+}
+
+static int write_blocks(struct disk_dump_partition *dump_part, unsigned int offs, char *buf, int len)
+{
+	struct disk_dump_device *device = dump_part->device;
+	int ret;
+
+	local_irq_disable();
+	touch_nmi_watchdog();
+	ret = device->ops.rw_block(dump_part, WRITE, offs, buf, len);
+	if (ret < 0) {
+		Err("write error on block %u", offs);
+		return ret;
+	}
+	return 0;
+}
+
+/*
+ * Initialize the common header
+ */
+
+/*
+ * Write the common header
+ */
+static int write_header(struct disk_dump_partition *dump_part)
+{
+	memset(scratch, 0, PAGE_SIZE);
+	memcpy(scratch, &dump_header, sizeof(dump_header));
+
+	return write_blocks(dump_part, 1, scratch, 1);
+}
+
+/*
+ * Check the signaures in all blocks of the dump partition
+ * Return 1 if the signature is correct, else return 0
+ */
+static int check_dump_partition(struct disk_dump_partition *dump_part,
+				unsigned int partition_size)
+{
+	unsigned int blk;
+	int ret;
+	unsigned int chunk_blks, skips;
+	int i;
+
+	if (sample_rate < 0)		/* No check */
+		return 1;
+
+	/*
+	 * If the device has limitations of transfer size, use it.
+	 */
+	chunk_blks = 1 << block_order;
+	if (dump_part->device->max_blocks)
+		 chunk_blks = min(chunk_blks, dump_part->device->max_blocks);
+	skips = chunk_blks << sample_rate;
+
+	lapse = 0;
+	for (blk = 0; blk < partition_size; blk += skips) {
+		unsigned int len;
+redo:
+		len = min(chunk_blks, partition_size - blk);
+		if ((ret = read_blocks(dump_part, blk, scratch, len)) < 0)
+			return 0;
+		print_status(blk + 1, partition_size);
+		for (i = 0; i < len; i++)
+			if (!check_block_signature(scratch + i * DUMP_BLOCK_SIZE, blk + i)) {
+				Err("bad signature in block %u", blk + i);
+				return 0;
+			}
+	}
+	/* Check the end of the dump partition */
+	if (blk - skips + chunk_blks < partition_size) {
+		blk = partition_size - chunk_blks;
+		goto redo;
+	}
+	clear_status(blk, partition_size);
+	return 1;
+}
+
+/*
+ * Write memory bitmap after location of dump headers.
+ */
+#define PAGE_PER_BLOCK	(PAGE_SIZE * 8)
+#define idx_to_pfn(nr, byte, bit) (((nr) * PAGE_SIZE + (byte)) * 8 + (bit))
+
+static int write_bitmap(struct disk_dump_partition *dump_part,
+			unsigned int bitmap_offset, unsigned int bitmap_blocks)
+{
+	unsigned int nr;
+	unsigned long pfn, next_ram_pfn;
+	int bit, byte;
+	int ret = 0;
+	unsigned char val;
+
+	for (nr = 0; nr < bitmap_blocks; nr++) {
+		pfn = idx_to_pfn(nr, 0, 0);
+		next_ram_pfn = next_ram_page(pfn - 1);
+
+		if (pfn + PAGE_PER_BLOCK <= next_ram_pfn)
+			memset(scratch, 0, PAGE_SIZE);
+		else
+			for (byte = 0; byte < PAGE_SIZE; byte++) {
+				val = 0;
+				for (bit = 0; bit < 8; bit++)
+					if (page_is_ram(idx_to_pfn(nr, byte,
+								   bit)))
+						val |= (1 << bit);
+				scratch[byte] = (char)val;
+			}
+		if ((ret = write_blocks(dump_part, bitmap_offset + nr,
+					scratch, 1)) < 0) {
+			Err("I/O error %d on block %u", ret, bitmap_offset + nr);
+			break;
+		}
+	}
+	return ret;
+}
+
+/*
+ * Write whole memory to dump partition.
+ * Return value is the number of writen blocks.
+ */
+static int write_memory(struct disk_dump_partition *dump_part, int offset,
+			unsigned int max_blocks_written,
+			unsigned int *blocks_written)
+{
+	char *kaddr;
+	unsigned int blocks = 0;
+	struct page *page;
+	unsigned long nr;
+	int ret = 0;
+	int blk_in_chunk = 0;
+
+	for (nr = next_ram_page(ULONG_MAX); nr < ULONG_MAX; nr = next_ram_page(nr)) {
+		print_status(blocks, max_blocks_written);
+
+
+		if (blocks >= max_blocks_written) {
+			Warn("dump device is too small. %lu pages were not saved", max_pfn - blocks);
+			goto out;
+		}
+
+		page = pfn_to_page(nr);
+		if (nr != page_to_pfn(page)) {
+			/* page_to_pfn() is called from kmap_atomic().
+			 * If page->flag is broken, it specified a wrong
+			 * zone and it causes kmap_atomic() fail.
+			 */
+			Err("Bad page. PFN %lu flags %lx\n",
+			    nr, (unsigned long)page->flags);
+			memset(scratch + blk_in_chunk * PAGE_SIZE, 0,
+			       PAGE_SIZE);
+			sprintf(scratch + blk_in_chunk * PAGE_SIZE,
+				"Bad page. PFN %lu flags %lx\n",
+			 	 nr, (unsigned long)page->flags);
+			goto write;
+		}
+
+		if (!kern_addr_valid((unsigned long)pfn_to_kaddr(nr))) {
+			memset(scratch + blk_in_chunk * PAGE_SIZE, 0,
+			       PAGE_SIZE);
+			sprintf(scratch + blk_in_chunk * PAGE_SIZE,
+				"Unmapped page. PFN %lu\n", nr);
+			goto write;
+		}
+
+		kaddr = kmap_atomic(page, KM_CRASHDUMP);
+		/*
+		 * need to copy because adapter drivers use
+		 * virt_to_bus()
+		 */
+		memcpy(scratch + blk_in_chunk * PAGE_SIZE, kaddr, PAGE_SIZE);
+		kunmap_atomic(kaddr, KM_CRASHDUMP);
+
+write:
+		blk_in_chunk++;
+		blocks++;
+
+		if (blk_in_chunk >= (1 << block_order)) {
+			ret = write_blocks(dump_part, offset, scratch,
+					   blk_in_chunk);
+			if (ret < 0) {
+				Err("I/O error %d on block %u", ret, offset);
+				break;
+			}
+			offset += blk_in_chunk;
+			blk_in_chunk = 0;
+		}
+	}
+	if (ret >= 0 && blk_in_chunk > 0) {
+		ret = write_blocks(dump_part, offset, scratch, blk_in_chunk);
+		if (ret < 0)
+			Err("I/O error %d on block %u", ret, offset);
+	}
+
+out:
+	clear_status(nr, max_blocks_written);
+
+	*blocks_written = blocks;
+	return ret;
+}
+
+/*
+ * Select most suitable dump device. sanity_check() returns the state
+ * of each dump device. 0 means OK, negative value means NG, and
+ * positive value means it maybe work. select_dump_partition() first
+ * try to select a sane device and if it has no sane device and
+ * allow_risky_dumps is set, it select one from maybe OK devices.
+ *
+ * XXX We cannot handle multiple partitions yet.
+ */
+static struct disk_dump_partition *select_dump_partition(void)
+{
+	struct disk_dump_device *dump_device;
+	struct disk_dump_partition *dump_part;
+	int sanity;
+	int strict_check = 1;
+
+redo:
+	/*
+	 * Select a sane polling driver.
+	 */
+	list_for_each_entry(dump_device, &disk_dump_devices, list) {
+		sanity = 0;
+		if (dump_device->ops.sanity_check)
+			sanity = dump_device->ops.sanity_check(dump_device);
+		if (sanity < 0 || (sanity > 0 && strict_check))
+			continue;
+		list_for_each_entry(dump_part, &dump_device->partitions, list)
+				return dump_part;
+	}
+	if (allow_risky_dumps && strict_check) {
+		strict_check = 0;
+		goto redo;
+	}
+	return NULL;
+}
+
+static int dump_err = 0;	/* Indicate Error state which occured in
+				 * disk_dump(). We need to make it global
+				 * because disk_dump() can't pass
+				 * error state as return value.
+				 */
+
+static void freeze_other_cpus(void)
+{
+#if CONFIG_SMP
+	int	i;
+
+	smp_call_function(freeze_cpu, NULL, 1, -1);
+	diskdump_mdelay(3000);
+	printk("CPU frozen: ");
+	for (i = 0; i < NR_CPUS; i++) {
+		if (dump_header.tasks[i] != NULL)
+			printk("#%d", i);
+
+	}
+	printk("\n");
+	printk("CPU#%d is executing diskdump.\n", smp_processor_id());
+#else
+	diskdump_mdelay(1000);
+#endif
+	dump_header.tasks[smp_processor_id()] = current;
+}
+
+static void start_disk_dump(struct pt_regs *regs)
+{
+	unsigned long flags;
+
+	/* Inhibit interrupt and stop other CPUs */
+	local_irq_save(flags);
+	preempt_disable();
+
+	/*
+	 * Check the checksum of myself
+	 */
+	if (down_trylock(&disk_dump_mutex)) {
+		Err("down_trylock(disk_dump_mutex) failed.");
+		goto done;
+	}
+
+	if (!check_crc_module()) {
+		Err("checksum error. diskdump common module may be compromised.");
+		goto done;
+	}
+
+	disk_dump_state = DISK_DUMP_RUNNING;
+
+	diskdump_mode = 1;
+
+	Dbg("notify dump start.");
+	notifier_call_chain(&disk_dump_notifier_list, 0, NULL);
+
+	touch_nmi_watchdog();
+	freeze_other_cpus();
+
+	/*
+	 *  Some platforms may want to execute netdump on its own stack.
+	 */
+	platform_start_crashdump(diskdump_stack, disk_dump, regs);
+
+done:
+	/*
+	 * If diskdump failed and fallback_on_err is set,
+	 * We just return and leave panic to netdump.
+	 */
+	if (dump_err) {
+		disk_dump_state = DISK_DUMP_FAILURE;
+		if (fallback_on_err && dump_err)
+			return;
+	} else {
+		disk_dump_state = DISK_DUMP_SUCCESS;
+	}
+
+	Dbg("notify panic.");
+	notifier_call_chain(&panic_notifier_list, 0, NULL);
+
+	if (panic_timeout > 0) {
+		int i;
+		/*
+	 	 * Delay timeout seconds before rebooting the machine. 
+		 * We can't use the "normal" timers since we just panicked..
+	 	 */
+		printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout);
+		for (i = 0; i < panic_timeout; i++) {
+			touch_nmi_watchdog();
+			diskdump_mdelay(1000);
+		}
+
+		/*
+		 *	Should we run the reboot notifier. For the moment Im
+		 *	choosing not too. It might crash, be corrupt or do
+		 *	more harm than good for other reasons.
+		 */
+		machine_restart(NULL);
+	}
+	printk(KERN_EMERG "halt\n");
+	for (;;) {
+		touch_nmi_watchdog();
+		machine_halt();
+		diskdump_mdelay(1000);
+	}
+}
+
+static asmlinkage void disk_dump(struct pt_regs *regs, void *platform_arg)
+{
+	struct pt_regs myregs;
+	unsigned int max_written_blocks, written_blocks;
+	struct disk_dump_device *dump_device = NULL;
+	struct disk_dump_partition *dump_part = NULL;
+	int ret;
+
+	dump_err = -EIO;
+
+	/*
+	 * Setup timer/tasklet
+	 */
+	dump_clear_timers();
+	dump_clear_tasklet();
+	dump_clear_workqueue();
+
+	/* Save original jiffies value */
+	diskdump_base_jiffies = jiffies;
+
+	diskdump_setup_timestamp();
+
+	platform_fix_regs();
+
+	if (list_empty(&disk_dump_devices)) {
+		Err("adapter driver is not registered.");
+		goto done;
+	}
+
+	printk("start dumping\n");
+
+	if (!(dump_part = select_dump_partition())) {
+		Err("No sane dump device found");
+		goto done;
+	}
+	dump_device = dump_part->device;
+
+	/*
+	 * Stop ongoing I/O with polling driver and make the shift to I/O mode
+	 * for dump
+	 */
+	Dbg("do quiesce");
+	if (dump_device->ops.quiesce)
+		if ((ret = dump_device->ops.quiesce(dump_device)) < 0) {
+			Err("quiesce failed. error %d", ret);
+			goto done;
+		}
+
+	if (SECTOR_BLOCK(dump_part->nr_sects) < header_blocks + bitmap_blocks) {
+		Warn("dump partition is too small. Aborted");
+		goto done;
+	}
+
+	/* Check dump partition */
+	printk("check dump partition...\n");
+	if (!check_dump_partition(dump_part, total_blocks)) {
+		Err("check partition failed.");
+		goto done;
+	}
+
+	/*
+	 * Write the common header
+	 */
+	memcpy(dump_header.signature, DISK_DUMP_SIGNATURE,
+	       sizeof(dump_header.signature));
+	dump_header.utsname	     = system_utsname;
+	dump_header.timestamp	     = xtime;
+	dump_header.status	     = DUMP_HEADER_INCOMPLETED;
+	dump_header.block_size	     = PAGE_SIZE;
+	dump_header.sub_hdr_size     = size_of_sub_header();
+	dump_header.bitmap_blocks    = bitmap_blocks;
+	dump_header.max_mapnr	     = max_pfn;
+	dump_header.total_ram_blocks = total_ram_blocks;
+	dump_header.device_blocks    = SECTOR_BLOCK(dump_part->nr_sects);
+	dump_header.current_cpu	     = smp_processor_id();
+	dump_header.nr_cpus	     = num_online_cpus();
+	dump_header.written_blocks   = 2;
+
+	write_header(dump_part);
+
+	/*
+	 * Write the architecture dependent header
+	 */
+	Dbg("write sub header");
+	if ((ret = write_sub_header()) < 0) {
+		Err("writing sub header failed. error %d", ret);
+		goto done;
+	}
+
+	Dbg("writing memory bitmaps..");
+	if ((ret = write_bitmap(dump_part, header_blocks, bitmap_blocks)) < 0)
+		goto done;
+
+	max_written_blocks = total_ram_blocks;
+	if (dump_header.device_blocks < total_blocks) {
+		Warn("dump partition is too small. actual blocks %u. expected blocks %u. whole memory will not be saved",
+				dump_header.device_blocks, total_blocks);
+		max_written_blocks -= (total_blocks - dump_header.device_blocks);
+	}
+
+	dump_header.written_blocks += dump_header.sub_hdr_size;
+	dump_header.written_blocks += dump_header.bitmap_blocks;
+	write_header(dump_part);
+
+	printk("dumping memory..\n");
+	if ((ret = write_memory(dump_part, header_blocks + bitmap_blocks,
+				max_written_blocks, &written_blocks)) < 0)
+		goto done;
+
+	/*
+	 * Set the number of block that is written into and write it
+	 * into partition again.
+	 */
+	dump_header.written_blocks += written_blocks;
+	dump_header.status = DUMP_HEADER_COMPLETED;
+	write_header(dump_part);
+
+	dump_err = 0;
+
+done:
+	Dbg("do adapter shutdown.");
+	if (dump_device && dump_device->ops.shutdown)
+		if (dump_device->ops.shutdown(dump_device))
+			Err("adapter shutdown failed.");
+}
+
+static struct disk_dump_partition *find_dump_partition(struct block_device *bdev)
+{
+	struct disk_dump_device *dump_device;
+	struct disk_dump_partition *dump_part;
+
+	list_for_each_entry(dump_device, &disk_dump_devices, list)
+		list_for_each_entry(dump_part, &dump_device->partitions, list)
+			if (dump_part->bdev == bdev)
+				return dump_part;
+	return NULL;
+}
+
+static struct disk_dump_device *find_dump_device(struct disk_dump_device *device)
+{
+	struct disk_dump_device *dump_device;
+
+	list_for_each_entry(dump_device, &disk_dump_devices, list)
+		if (device->device == dump_device->device)
+			return  dump_device;
+	return NULL;
+}
+
+static void *find_real_device(struct device *dev,
+			      struct disk_dump_type **_dump_type)
+{
+	void *real_device;
+	struct disk_dump_type *dump_type;
+
+	list_for_each_entry(dump_type, &disk_dump_types, list)
+		if ((real_device = dump_type->probe(dev)) != NULL) {
+			*_dump_type = dump_type;
+			return real_device;
+		}
+	return NULL;
+}
+
+/*
+ * Add dump partition structure corresponding to file to the dump device
+ * structure.
+ */
+static int add_dump_partition(struct disk_dump_device *dump_device,
+			      struct block_device *bdev)
+{
+	struct disk_dump_partition *dump_part;
+	char buffer[BDEVNAME_SIZE];
+
+	if (!(dump_part = kmalloc(sizeof(*dump_part), GFP_KERNEL)))
+		return -ENOMEM;
+
+	dump_part->device = dump_device;
+	dump_part->bdev = bdev;
+
+	if (!bdev || !bdev->bd_part)
+		return -EINVAL;
+	dump_part->nr_sects   = bdev->bd_part->nr_sects;
+	dump_part->start_sect = bdev->bd_part->start_sect;
+
+	if (SECTOR_BLOCK(dump_part->nr_sects) < total_blocks)
+		Warn("%s is too small to save whole system memory\n",
+			bdevname(bdev, buffer));
+
+	list_add(&dump_part->list, &dump_device->partitions);
+
+	return 0;
+}
+
+/*
+ * Add dump device and partition.
+ * Must be called with disk_dump_mutex held.
+ */
+static int add_dump(struct device *dev, struct block_device *bdev)
+{
+	struct disk_dump_type *dump_type = NULL;
+	struct disk_dump_device *dump_device;
+	void *real_device;
+	int ret;
+
+	if ((ret = blkdev_get(bdev, FMODE_READ, 0)) < 0)
+		return ret;
+
+	/* Check whether this block device is already registered */
+	if (find_dump_partition(bdev)) {
+		blkdev_put(bdev);
+		return -EEXIST;
+	}
+
+	/* find dump_type and real device for this inode */
+	if (!(real_device = find_real_device(dev, &dump_type))) {
+		blkdev_put(bdev);
+		return -ENXIO;
+	}
+
+	/* Check whether this device is already registered */
+	dump_device = find_dump_device(real_device);
+	if (dump_device == NULL) {
+		/* real_device is not registered. create new dump_device */
+		if (!(dump_device = kmalloc(sizeof(*dump_device), GFP_KERNEL))) {
+			blkdev_put(bdev);
+			return -ENOMEM;
+		}
+
+		memset(dump_device, 0, sizeof(*dump_device));
+		INIT_LIST_HEAD(&dump_device->partitions);
+
+		dump_device->dump_type = dump_type;
+		dump_device->device = real_device;
+		if ((ret = dump_type->add_device(dump_device)) < 0) {
+			kfree(dump_device);
+			blkdev_put(bdev);
+			return ret;
+		}
+		if (!try_module_get(dump_type->owner))
+			return -EINVAL;
+		list_add(&dump_device->list, &disk_dump_devices);
+	}
+
+	ret = add_dump_partition(dump_device, bdev);
+	if (ret < 0 && list_empty(&dump_device->list)) {
+		dump_type->remove_device(dump_device);
+		module_put(dump_type->owner);
+		list_del(&dump_device->list);
+		kfree(dump_device);
+	}
+	if (ret < 0)
+		blkdev_put(bdev);
+
+	return ret;
+}
+
+/*
+ * Remove dump partition corresponding to bdev.
+ * Must be called with disk_dump_mutex held.
+ */
+static int remove_dump(struct block_device *bdev)
+{
+	struct disk_dump_device *dump_device;
+	struct disk_dump_partition *dump_part;
+	struct disk_dump_type *dump_type;
+
+	if (!(dump_part = find_dump_partition(bdev))) {
+		bdput(bdev);
+		return -ENOENT;
+	}
+
+	blkdev_put(bdev);
+	dump_device = dump_part->device;
+	list_del(&dump_part->list);
+	kfree(dump_part);
+
+	if (list_empty(&dump_device->partitions)) {
+		dump_type = dump_device->dump_type;
+		dump_type->remove_device(dump_device);
+		module_put(dump_type->owner);
+		list_del(&dump_device->list);
+		kfree(dump_device);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+static struct disk_dump_partition *dump_part_by_pos(struct seq_file *seq,
+						    loff_t pos)
+{
+	struct disk_dump_device *dump_device;
+	struct disk_dump_partition *dump_part;
+
+	list_for_each_entry(dump_device, &disk_dump_devices, list) {
+		seq->private = dump_device;
+		list_for_each_entry(dump_part, &dump_device->partitions, list)
+			if (!pos--)
+				return dump_part;
+	}
+	return NULL;
+}
+
+static void *disk_dump_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	loff_t n = *pos;
+
+	down(&disk_dump_mutex);
+
+	if (!n--)
+		return (void *)1;	/* header */
+
+	return dump_part_by_pos(seq, n);
+}
+
+static void *disk_dump_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct list_head *partition = v;
+	struct list_head *device = seq->private;
+	struct disk_dump_device *dump_device;
+
+	(*pos)++;
+	if (v == (void *)1)
+		return dump_part_by_pos(seq, 0);
+
+	dump_device = list_entry(device, struct disk_dump_device, list);
+
+	partition = partition->next;
+	if (partition != &dump_device->partitions)
+		return partition;
+
+	device = device->next;
+	seq->private = device;
+	if (device == &disk_dump_devices)
+		return NULL;
+
+	dump_device = list_entry(device, struct disk_dump_device, list);
+
+	return dump_device->partitions.next;
+}
+
+static void disk_dump_seq_stop(struct seq_file *seq, void *v)
+{
+	up(&disk_dump_mutex);
+}
+
+static int disk_dump_seq_show(struct seq_file *seq, void *v)
+{
+	struct disk_dump_partition *dump_part = v;
+	char buf[BDEVNAME_SIZE];
+
+	if (v == (void *)1) {	/* header */
+		seq_printf(seq, "# sample_rate: %u\n", sample_rate);
+		seq_printf(seq, "# block_order: %u\n", block_order);
+		seq_printf(seq, "# fallback_on_err: %u\n", fallback_on_err);
+		seq_printf(seq, "# allow_risky_dumps: %u\n", allow_risky_dumps);
+		seq_printf(seq, "# total_blocks: %u\n", total_blocks);
+		seq_printf(seq, "#\n");
+
+		return 0;
+	}
+
+	seq_printf(seq, "%s %lu %lu\n", bdevname(dump_part->bdev, buf),
+			dump_part->start_sect, dump_part->nr_sects);
+	return 0;
+}
+
+static struct seq_operations disk_dump_seq_ops = {
+	.start	= disk_dump_seq_start,
+	.next	= disk_dump_seq_next,
+	.stop	= disk_dump_seq_stop,
+	.show	= disk_dump_seq_show,
+};
+
+static int disk_dump_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &disk_dump_seq_ops);
+}
+
+static struct file_operations disk_dump_fops = {
+	.owner		= THIS_MODULE,
+	.open		= disk_dump_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+#endif
+
+int register_disk_dump_device(struct device *dev, struct block_device *bdev)
+{
+	int ret;
+
+	down(&disk_dump_mutex);
+	ret = add_dump(dev, bdev);
+	set_crc_modules();
+	up(&disk_dump_mutex);
+
+	return ret;
+}
+
+int unregister_disk_dump_device(struct block_device *bdev)
+{
+	int ret;
+
+	down(&disk_dump_mutex);
+	ret = remove_dump(bdev);
+	set_crc_modules();
+	up(&disk_dump_mutex);
+
+	return ret;
+}
+
+int find_disk_dump_device(struct block_device *bdev)
+{
+	int ret;
+
+	down(&disk_dump_mutex);
+	ret = (find_dump_partition(bdev) != NULL);
+	up(&disk_dump_mutex);
+
+	return ret;
+}
+
+int register_disk_dump_type(struct disk_dump_type *dump_type)
+{
+	down(&disk_dump_mutex);
+	list_add(&dump_type->list, &disk_dump_types);
+	set_crc_modules();
+	up(&disk_dump_mutex);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(register_disk_dump_type);
+
+int unregister_disk_dump_type(struct disk_dump_type *dump_type)
+{
+	down(&disk_dump_mutex);
+	list_del(&dump_type->list);
+	set_crc_modules();
+	up(&disk_dump_mutex);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(unregister_disk_dump_type);
+
+static void compute_total_blocks(void)
+{
+	unsigned long nr;
+
+	/*
+	 * the number of block of the common header and the header
+	 * that is depend on the architecture
+	 *
+	 * block 0:		dump partition header
+	 * block 1:		dump header
+	 * block 2:		dump subheader
+	 * block 3..n:		memory bitmap
+	 * block (n + 1)...:	saved memory
+	 *
+	 * We never overwrite block 0
+	 */
+	header_blocks = 2 + size_of_sub_header();
+
+	total_ram_blocks = 0;
+	for (nr = next_ram_page(ULONG_MAX); nr < ULONG_MAX; nr = next_ram_page(nr))
+		total_ram_blocks++;
+
+	bitmap_blocks = ROUNDUP(max_pfn, 8 * PAGE_SIZE);
+
+	/*
+	 * The necessary size of area for dump is:
+	 * 1 block for common header
+	 * m blocks for architecture dependent header
+	 * n blocks for memory bitmap
+	 * and whole memory
+	 */
+	total_blocks = header_blocks + bitmap_blocks + total_ram_blocks;
+
+	Info("total blocks required: %u (header %u + bitmap %u + memory %u)",
+		total_blocks, header_blocks, bitmap_blocks, total_ram_blocks);
+}
+
+struct disk_dump_ops dump_ops = {
+	.add_dump	= register_disk_dump_device,
+	.remove_dump	= unregister_disk_dump_device,
+	.find_dump	= find_disk_dump_device,
+};
+
+static int init_diskdump(void)
+{
+	unsigned long long t0;
+	unsigned long long t1;
+	struct page *page;
+
+	if (!platform_supports_diskdump) {
+		Err("platform does not support diskdump.");
+		return -1;
+	}
+
+	/* Allocate one block that is used temporally */
+	do {
+		page = alloc_pages(GFP_KERNEL, block_order);
+		if (page != NULL)
+			break;
+	} while (--block_order >= 0);
+	if (!page) {
+		Err("alloc_pages failed.");
+		return -1;
+	}
+	scratch = page_address(page);
+	Info("Maximum block size: %lu", PAGE_SIZE << block_order);
+
+	if (diskdump_register_hook(start_disk_dump)) {
+		Err("failed to register hooks.");
+		return -1;
+	}
+
+	if (diskdump_register_ops(&dump_ops)) {
+		Err("failed to register ops.");
+		return -1;
+	}
+
+	compute_total_blocks();
+
+	platform_timestamp(t0);
+	diskdump_mdelay(1);
+	platform_timestamp(t1);
+	timestamp_1sec = (unsigned long)(t1 - t0) * 1000;
+
+	/*
+	 *  Allocate a separate stack for diskdump.
+	 */
+	platform_init_stack(&diskdump_stack);
+
+	down(&disk_dump_mutex);
+	set_crc_modules();
+	up(&disk_dump_mutex);
+
+#ifdef CONFIG_PROC_FS
+	{
+		struct proc_dir_entry *p;
+
+		p = create_proc_entry("diskdump", S_IRUGO|S_IWUSR, NULL);
+		if (p)
+			p->proc_fops = &disk_dump_fops;
+	}
+#endif
+
+	return 0;
+}
+
+static void cleanup_diskdump(void)
+{
+	Info("shut down.");
+	diskdump_unregister_hook();
+	diskdump_unregister_ops();
+	platform_cleanup_stack(diskdump_stack);
+	free_pages((unsigned long)scratch, block_order);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("diskdump", NULL);
+#endif
+}
+
+module_init(init_diskdump);
+module_exit(cleanup_diskdump);
+
+MODULE_LICENSE("GPL");
--- linux-2.6.12/kernel/workqueue.c.diskdump.orig	2005-08-19 16:44:33.085478791 -0400
+++ linux-2.6.12/kernel/workqueue.c	2005-08-19 16:47:34.249258165 -0400
@@ -467,6 +467,37 @@ int current_is_keventd(void)
 
 }
 
+static struct cpu_workqueue_struct saved_cwq;
+
+void dump_clear_workqueue(void)
+{
+	int cpu = smp_processor_id();
+	struct cpu_workqueue_struct *cwq = keventd_wq->cpu_wq + cpu;
+
+	memcpy(&saved_cwq, cwq, sizeof(saved_cwq));
+	spin_lock_init(&cwq->lock);
+	INIT_LIST_HEAD(&cwq->worklist);
+	init_waitqueue_head(&cwq->more_work);
+	init_waitqueue_head(&cwq->work_done);
+}
+
+void dump_run_workqueue(void)
+{
+	struct cpu_workqueue_struct *cwq;
+
+	cwq = keventd_wq->cpu_wq + smp_processor_id();
+	while (!list_empty(&cwq->worklist)) {
+		struct work_struct *work = list_entry(cwq->worklist.next,
+						struct work_struct, entry);
+		void (*f) (void *) = work->func;
+		void *data = work->data;
+
+		list_del_init(cwq->worklist.next);
+		clear_bit(0, &work->pending);
+		f(data);
+	}
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 /* Take the work from this (downed) CPU. */
 static void take_over_work(struct workqueue_struct *wq, unsigned int cpu)
@@ -552,3 +583,6 @@ EXPORT_SYMBOL(schedule_work);
 EXPORT_SYMBOL(schedule_delayed_work);
 EXPORT_SYMBOL(schedule_delayed_work_on);
 EXPORT_SYMBOL(flush_scheduled_work);
+
+EXPORT_SYMBOL_GPL(dump_clear_workqueue);
+EXPORT_SYMBOL_GPL(dump_run_workqueue);
--- linux-2.6.12/kernel/softirq.c.diskdump.orig	2005-06-17 15:48:29.000000000 -0400
+++ linux-2.6.12/kernel/softirq.c	2005-08-19 16:47:34.242259333 -0400
@@ -341,6 +341,38 @@ void tasklet_kill(struct tasklet_struct 
 
 EXPORT_SYMBOL(tasklet_kill);
 
+struct tasklet_head saved_tasklet;
+
+void dump_clear_tasklet(void)
+{
+	saved_tasklet.list = __get_cpu_var(tasklet_vec).list;
+	__get_cpu_var(tasklet_vec).list = NULL;
+}
+
+EXPORT_SYMBOL_GPL(dump_clear_tasklet);
+
+void dump_run_tasklet(void)
+{
+	struct tasklet_struct *list;
+
+	list = __get_cpu_var(tasklet_vec).list;
+	__get_cpu_var(tasklet_vec).list = NULL;
+
+	while (list) {
+		struct tasklet_struct *t = list;
+		list = list->next;
+
+		if (!atomic_read(&t->count) &&
+		    (test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)))
+				t->func(t->data);
+
+		t->next = __get_cpu_var(tasklet_vec).list;
+		__get_cpu_var(tasklet_vec).list = t;
+	}
+}
+
+EXPORT_SYMBOL_GPL(dump_run_tasklet);
+
 void __init softirq_init(void)
 {
 	open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
--- linux-2.6.12/kernel/timer.c.diskdump.orig	2005-08-19 16:44:27.502410144 -0400
+++ linux-2.6.12/kernel/timer.c	2005-08-19 16:49:13.988620772 -0400
@@ -33,6 +33,8 @@
 #include <linux/posix-timers.h>
 #include <linux/cpu.h>
 #include <linux/syscalls.h>
+#include <linux/delay.h>
+#include <linux/diskdump.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -438,8 +438,9 @@ static int cascade(tvec_base_t *base, tv
 static inline void __run_timers(tvec_base_t *base)
 {
 	struct timer_list *timer;
+	unsigned long flags;
 
-	spin_lock_irq(&base->lock);
+	spin_lock_irqsave(&base->lock, flags);
 	while (time_after_eq(jiffies, base->timer_jiffies)) {
 		struct list_head work_list = LIST_HEAD_INIT(work_list);
 		struct list_head *head = &work_list;
@@ -468,7 +469,7 @@ repeat:
 			set_running_timer(base, timer);
 			smp_wmb();
 			timer->base = NULL;
-			spin_unlock_irq(&base->lock);
+			spin_unlock_irqrestore(&base->lock, flags);
 			{
 				u32 preempt_count = preempt_count();
 				fn(data);
@@ -477,12 +478,12 @@ repeat:
 					BUG();
 				}
 			}
-			spin_lock_irq(&base->lock);
+			spin_lock_irqsave(&base->lock, flags);
 			goto repeat;
 		}
 	}
 	set_running_timer(base, NULL);
-	spin_unlock_irq(&base->lock);
+	spin_unlock_irqrestore(&base->lock, flags);
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
@@ -1104,6 +1107,12 @@ fastcall signed long __sched schedule_ti
 	struct timer_list timer;
 	unsigned long expire;
 
+	if (crashdump_mode()) {
+		diskdump_mdelay(timeout);
+		set_current_state(TASK_RUNNING);
+		return timeout;
+	}
+
 	switch (timeout)
 	{
 	case MAX_SCHEDULE_TIMEOUT:
@@ -1306,7 +1315,7 @@ asmlinkage long sys_sysinfo(struct sysin
 	return 0;
 }
 
-static void __devinit init_timers_cpu(int cpu)
+static void /* __devinit */ init_timers_cpu(int cpu)
 {
 	int j;
 	tvec_base_t *base;
@@ -1325,6 +1334,27 @@ static void __devinit init_timers_cpu(in
 	base->timer_jiffies = jiffies;
 }
 
+static tvec_base_t saved_tvec_base;
+
+void dump_clear_timers(void)
+{
+	tvec_base_t *base = &per_cpu(tvec_bases, smp_processor_id());
+
+	memcpy(&saved_tvec_base, base, sizeof(saved_tvec_base));
+	init_timers_cpu(smp_processor_id());
+}
+
+EXPORT_SYMBOL_GPL(dump_clear_timers);
+
+void dump_run_timers(void)
+{
+	tvec_base_t *base = &__get_cpu_var(tvec_bases);
+
+	__run_timers(base);
+}
+
+EXPORT_SYMBOL_GPL(dump_run_timers);
+
 #ifdef CONFIG_HOTPLUG_CPU
 static void migrate_timer_list(tvec_base_t *new_base, struct list_head *head)
 {
@@ -1588,6 +1618,11 @@ void msleep(unsigned int msecs)
 {
 	unsigned long timeout = msecs_to_jiffies(msecs) + 1;
 
+	if (unlikely(crashdump_mode())) {
+		while (msecs--) udelay(1000);
+		return;
+	}
+
 	while (timeout) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		timeout = schedule_timeout(timeout);
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-ia64/diskdump.h	2005-08-19 16:47:34.231261167 -0400
@@ -0,0 +1,63 @@
+#ifndef _ASM_IA64_DISKDUMP_H
+#define _ASM_IA64_DISKDUMP_H
+
+/*
+ * linux/include/asm-ia64/diskdump.h
+ *
+ * Copyright (c) 2004 FUJITSU LIMITED
+ * Copyright (c) 2003 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef __KERNEL__
+
+#include <asm/crashdump.h>
+
+
+const static int platform_supports_diskdump = 1;
+
+struct disk_dump_sub_header {
+	elf_gregset_t		 elf_regs;
+	struct switch_stack	*sw[NR_CPUS];
+};
+
+#define size_of_sub_header()	((sizeof(struct disk_dump_sub_header) + PAGE_SIZE - 1) / DUMP_BLOCK_SIZE)
+
+#define write_sub_header() \
+({								\
+ 	int ret;						\
+	struct unw_frame_info *info = platform_arg;		\
+								\
+	ia64_do_copy_regs(info, &dump_sub_header.elf_regs);	\
+	dump_sub_header.sw[smp_processor_id()] = info->sw;	\
+	clear_page(scratch);					\
+	memcpy(scratch, &dump_sub_header, sizeof(dump_sub_header));\
+ 								\
+	if ((ret = write_blocks(dump_part, 2, scratch, 1)) >= 0)\
+		ret = 1; /* size of sub header in page */;	\
+	ret;							\
+})
+
+#define platform_freeze_cpu() 					\
+{								\
+	unw_init_running(ia64_freeze_cpu,			\
+		&dump_sub_header.sw[smp_processor_id()]);	\
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_IA64_DISKDUMP_H */
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-x86_64/diskdump.h	2005-08-19 16:47:34.234260667 -0400
@@ -0,0 +1,44 @@
+/*
+ * include/asm-x86_64/diskdump.h
+ *
+ * Copyright (C) Hitachi, Ltd. 2004
+ * Written by Satoshi Oshima (oshima at sdl.hitachi.co.jp)
+ *
+ * Derived from include/asm-i386/diskdump.h
+ * Copyright (c) 2004 FUJITSU LIMITED
+ * Copyright (c) 2003 Red Hat, Inc. All rights reserved.
+ *
+ */
+
+#ifndef _ASM_X86_64_DISKDUMP_H
+#define _ASM_X86_64_DISKDUMP_H
+
+#ifdef __KERNEL__
+
+#include <linux/elf.h>
+#include <asm/crashdump.h>
+
+const static int platform_supports_diskdump = 1;
+
+struct disk_dump_sub_header {
+	elf_gregset_t		elf_regs;
+};
+
+#define size_of_sub_header()	((sizeof(struct disk_dump_sub_header) + PAGE_SIZE - 1) / DUMP_BLOCK_SIZE)
+
+#define write_sub_header() 						\
+({									\
+ 	int ret;							\
+									\
+	ELF_CORE_COPY_REGS(dump_sub_header.elf_regs, (&myregs));	\
+	clear_page(scratch);						\
+	memcpy(scratch, &dump_sub_header, sizeof(dump_sub_header));	\
+ 									\
+	if ((ret = write_blocks(dump_part, 2, scratch, 1)) >= 0)	\
+		ret = 1; /* size of sub header in page */;		\
+	ret;								\
+})
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_X86_64_DISKDUMP_H */
--- linux-2.6.12/include/linux/timer.h.diskdump.orig	2005-08-19 16:44:27.131472023 -0400
+++ linux-2.6.12/include/linux/timer.h	2005-08-19 16:47:34.239259833 -0400
@@ -89,4 +89,7 @@ extern void init_timers(void);
 extern void run_local_timers(void);
 extern void it_real_fn(unsigned long);
 
+extern void dump_clear_timers(void);
+extern void dump_run_timers(void);
+
 #endif
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/linux/diskdump.h	2005-08-19 16:47:34.236260333 -0400
@@ -0,0 +1,186 @@
+#ifndef _LINUX_DISKDUMP_H
+#define _LINUX_DISKDUMP_H
+
+/*
+ * linux/include/linux/diskdump.h
+ *
+ * Copyright (c) 2004 FUJITSU LIMITED
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/list.h>
+#include <linux/blkdev.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+
+/* The minimum Dump I/O unit. Must be the same of PAGE_SIZE */
+#define DUMP_BLOCK_SIZE		PAGE_SIZE
+#define DUMP_BLOCK_SHIFT	PAGE_SHIFT
+
+int diskdump_register_hook(void (*dump_func)(struct pt_regs *));
+void diskdump_unregister_hook(void);
+
+/*
+ * The handler of diskdump module
+ */
+struct disk_dump_ops {
+	int (*add_dump)(struct device *, struct block_device *);
+	int (*remove_dump)(struct block_device *);
+	int (*find_dump)(struct block_device *);
+};
+
+int diskdump_register_ops(struct disk_dump_ops* op);
+void diskdump_unregister_ops(void);
+
+
+/*
+ * The handler that adapter driver provides for the common module of
+ * dump
+ */
+struct disk_dump_partition;
+struct disk_dump_device;
+
+struct disk_dump_type {
+	void *(*probe)(struct device *);
+	int (*add_device)(struct disk_dump_device *);
+	void (*remove_device)(struct disk_dump_device *);
+	struct module *owner;
+	struct list_head list;
+};
+
+struct disk_dump_device_ops {
+	int (*sanity_check)(struct disk_dump_device *);
+	int (*quiesce)(struct disk_dump_device *);
+	int (*shutdown)(struct disk_dump_device *);
+	int (*rw_block)(struct disk_dump_partition *, int rw, unsigned long block_nr, void *buf, int len);
+};
+
+/* The data structure for a dump device */
+struct disk_dump_device {
+	struct list_head list;
+	struct disk_dump_device_ops ops;
+	struct disk_dump_type *dump_type;
+	void *device;
+	unsigned int max_blocks;
+	struct list_head partitions;
+};
+
+/* The data structure for a dump partition */
+struct disk_dump_partition {
+	struct list_head list;
+	struct disk_dump_device *device;
+	struct block_device *bdev;
+	unsigned long start_sect;
+	unsigned long nr_sects;
+};
+
+int register_disk_dump_type(struct disk_dump_type *);
+int unregister_disk_dump_type(struct disk_dump_type *);
+
+
+/*
+ * sysfs interface
+ */
+ssize_t diskdump_sysfs_store(struct device *dev, const char *buf, size_t count);
+ssize_t diskdump_sysfs_show(struct device *dev, char *buf);
+
+
+void diskdump_update(void);
+void diskdump_setup_timestamp(void);
+
+/* mdelay() is trapped by WARN_ON if we are in the interrupt context. */
+#define diskdump_mdelay(n) \
+({unsigned long __ms=(n); while (__ms--) udelay(1000);})
+
+
+/*
+ * Architecture-independent dump header
+ */
+
+/* The signature which is written in each block in the dump partition */
+#define DISK_DUMP_SIGNATURE		"DISKDUMP"
+#define DISK_DUMP_HEADER_VERSION	1
+
+#define DUMP_PARTITION_SIGNATURE	"diskdump"
+
+#define DUMP_HEADER_COMPLETED	0
+#define DUMP_HEADER_INCOMPLETED	1
+
+struct disk_dump_header {
+	char			signature[8];	/* = "DISKDUMP" */
+	int			header_version;	/* Dump header version */
+	struct new_utsname	utsname;	/* copy of system_utsname */
+	struct timespec		timestamp;	/* Time stamp */
+	unsigned int		status;		/* Above flags */
+	int			block_size;	/* Size of a block in byte */
+	int			sub_hdr_size;	/* Size of arch dependent
+						   header in blocks */
+	unsigned int		bitmap_blocks;	/* Size of Memory bitmap in
+						   block */
+	unsigned int		max_mapnr;	/* = max_mapnr */
+	unsigned int		total_ram_blocks;/* Size of Memory in block */
+	unsigned int		device_blocks;	/* Number of total blocks in
+						 * the dump device */
+	unsigned int		written_blocks;	/* Number of written blocks */
+	unsigned int		current_cpu;	/* CPU# which handles dump */
+	int			nr_cpus;	/* Number of CPUs */
+	struct task_struct	*tasks[NR_CPUS];
+};
+
+/* Diskdump state */
+extern enum disk_dump_states {
+	DISK_DUMP_INITIAL,
+	DISK_DUMP_RUNNING,
+	DISK_DUMP_SUCCESS,
+	DISK_DUMP_FAILURE,
+}  disk_dump_state;
+
+/*
+ * Calculate the check sum of the whole module
+ */
+#define get_crc_module()						\
+({									\
+	struct module *module = &__this_module;				\
+	crc32_le(0, (char *)(module->module_core),			\
+	  ((unsigned long)module - (unsigned long)(module->module_core))); \
+})
+
+/* Calculate the checksum of the whole module */
+#define set_crc_modules()						\
+({									\
+	module_crc = 0;							\
+	module_crc = get_crc_module();					\
+})
+
+/*
+ * Compare the checksum value that is stored in module_crc to the check
+ * sum of current whole module. Must be called with holding disk_dump_lock.
+ * Return TRUE if they are the same, else return FALSE
+ *
+ */
+#define check_crc_module()						\
+({									\
+	uint32_t orig_crc, cur_crc;					\
+									\
+	orig_crc = module_crc; module_crc = 0;				\
+	cur_crc = get_crc_module();					\
+	module_crc = orig_crc;						\
+	orig_crc == cur_crc;						\
+})
+
+
+#endif /* _LINUX_DISKDUMP_H */
--- linux-2.6.12/include/linux/interrupt.h.diskdump.orig	2005-06-17 15:48:29.000000000 -0400
+++ linux-2.6.12/include/linux/interrupt.h	2005-08-19 16:47:34.237260167 -0400
@@ -286,4 +286,8 @@ extern int probe_irq_off(unsigned long);
 extern unsigned int probe_irq_mask(unsigned long);	/* returns mask of ISA interrupts */
 #endif
 
+
+extern void dump_clear_tasklet(void);
+extern void dump_run_tasklet(void);
+
 #endif
--- linux-2.6.12/include/linux/workqueue.h.diskdump.orig	2005-06-17 15:48:29.000000000 -0400
+++ linux-2.6.12/include/linux/workqueue.h	2005-08-19 16:47:34.240259666 -0400
@@ -89,4 +89,7 @@ static inline int cancel_delayed_work(st
 	return ret;
 }
 
+extern void dump_clear_workqueue(void);
+extern void dump_run_workqueue(void);
+
 #endif
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-ppc/diskdump.h	2005-08-19 16:47:34.232261001 -0400
@@ -0,0 +1,6 @@
+#ifndef _ASM_PPC64_DISKDUMP_H_
+#define _ASM_PPC64_DISKDUMP_H_
+
+#include <asm-generic/diskdump.h>
+
+#endif /* _ASM_PPC64_DISKDUMP_H_ */
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-generic/diskdump.h	2005-08-19 16:47:34.229261501 -0400
@@ -0,0 +1,13 @@
+#ifndef _ASM_GENERIC_DISKDUMP_H_
+#define _ASM_GENERIC_DISKDUMP_H_
+
+#include <asm-generic/crashdump.h>
+
+const static int platform_supports_diskdump = 0;
+
+struct disk_dump_sub_header {};
+
+#define size_of_sub_header()	1
+#define write_sub_header() 	1
+
+#endif /* _ASM_GENERIC_DISKDUMP_H */
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-ppc64/diskdump.h	2005-08-19 16:47:34.233260834 -0400
@@ -0,0 +1,55 @@
+#ifndef _ASM_PPC64_DISKDUMP_H_
+#define _ASM_PPC64_DISKDUMP_H_
+
+/*
+ * linux/include/asm-ppc64/diskdump.h
+ *
+ * Copyright (c) 2004 FUJITSU LIMITED
+ * Copyright (c) 2003 Red Hat, Inc. All rights reserved.
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef __KERNEL__
+
+#include <linux/elf.h>
+#include <asm/crashdump.h>
+
+const static int platform_supports_diskdump = 1;
+
+struct disk_dump_sub_header {
+	elf_gregset_t		elf_regs;
+};
+
+#define size_of_sub_header()	((sizeof(struct disk_dump_sub_header) + PAGE_SIZE - 1) / DUMP_BLOCK_SIZE)
+
+#define write_sub_header() \
+({								\
+	int ret;						\
+	struct disk_dump_sub_header *header;			\
+								\
+	header = (struct disk_dump_sub_header *)scratch;	\
+	ELF_CORE_COPY_REGS(header->elf_regs, (&myregs));	\
+	clear_page(scratch);					\
+	if ((ret = write_blocks(dump_part, 2, scratch, 1)) >= 0)\
+		ret = 1; /* size of sub header in page */;	\
+	ret;							\
+})
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_PPC64_DISKDUMP_H_ */
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-i386/diskdump.h	2005-08-19 16:47:34.230261334 -0400
@@ -0,0 +1,55 @@
+#ifndef _ASM_I386_DISKDUMP_H
+#define _ASM_I386_DISKDUMP_H
+
+/*
+ * linux/include/asm-i386/diskdump.h
+ *
+ * Copyright (c) 2004 FUJITSU LIMITED
+ * Copyright (c) 2003 Red Hat, Inc. All rights reserved.
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef __KERNEL__
+
+#include <linux/elf.h>
+#include <asm/crashdump.h>
+
+const static int platform_supports_diskdump = 1;
+
+struct disk_dump_sub_header {
+	elf_gregset_t		elf_regs;
+};
+
+#define size_of_sub_header()	((sizeof(struct disk_dump_sub_header) + PAGE_SIZE - 1) / DUMP_BLOCK_SIZE)
+
+#define write_sub_header() 						\
+({									\
+ 	int ret;							\
+									\
+	ELF_CORE_COPY_REGS(dump_sub_header.elf_regs, (&myregs));	\
+	clear_page(scratch);						\
+	memcpy(scratch, &dump_sub_header, sizeof(dump_sub_header));	\
+ 									\
+	if ((ret = write_blocks(dump_part, 2, scratch, 1)) >= 0)	\
+		ret = 1; /* size of sub header in page */;		\
+	ret;								\
+})
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_I386_DISKDUMP_H */
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-s390/diskdump.h	2005-08-19 16:47:34.234260667 -0400
@@ -0,0 +1,6 @@
+#ifndef _ASM_S390_DISKDUMP_H_
+#define _ASM_S390_DISKDUMP_H_
+
+#include <asm-generic/diskdump.h>
+
+#endif /* _ASM_S390_DISKDUMP_H_ */

linux-2.6-dump_smp_call_function.patch:
 arch/i386/kernel/smp.c   |   44 ++++++++++++++++++++++++++++++++++++++++++++
 arch/ia64/kernel/smp.c   |   44 ++++++++++++++++++++++++++++++++++++++++++++
 arch/ppc64/kernel/smp.c  |   45 ++++++++++++++++++++++++++++++++++++++++++++-
 arch/x86_64/kernel/smp.c |   43 +++++++++++++++++++++++++++++++++++++++++++
 drivers/block/diskdump.c |    2 +-
 drivers/net/netdump.c    |    2 +-
 include/linux/smp.h      |    2 ++
 7 files changed, 179 insertions(+), 3 deletions(-)

--- NEW FILE linux-2.6-dump_smp_call_function.patch ---
--- linux-2.6.12/arch/ia64/kernel/smp.c.orig	2005-08-23 10:49:52.398379464 -0400
+++ linux-2.6.12/arch/ia64/kernel/smp.c	2005-08-23 10:51:04.769473645 -0400
@@ -53,6 +53,7 @@
  * requirements. It also looks cleaner.
  */
 static  __cacheline_aligned DEFINE_SPINLOCK(call_lock);
+static spinlock_t dump_call_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
 
 struct call_data_struct {
 	void (*func) (void *info);
@@ -63,6 +64,7 @@ struct call_data_struct {
 };
 
 static volatile struct call_data_struct *call_data;
+static volatile struct call_data_struct *saved_call_data;
 
 #define IPI_CALL_FUNC		0
 #define IPI_CPU_STOP		1
@@ -306,6 +308,48 @@ smp_call_function_single (int cpuid, voi
 EXPORT_SYMBOL(smp_call_function_single);
 
 /*
+ * dump version of smp_call_function to avoid deadlock in call_lock
+ */
+void dump_smp_call_function (void (*func) (void *info), void *info)
+{
+	static struct call_data_struct dumpdata;
+	int waitcount;
+
+	spin_lock(&dump_call_lock);
+	/* if another cpu beat us, they win! */
+	if (dumpdata.func) {
+		spin_unlock(&dump_call_lock);
+		func(info);
+		/* NOTREACHED */
+	}
+
+	/* freeze call_lock or wait for on-going IPIs to settle down */
+	waitcount = 0;
+	while (!spin_trylock(&call_lock)) {
+		if (waitcount++ > 1000) {
+			/* save original for dump analysis */
+			saved_call_data = call_data;
+			break;
+		}
+		udelay(1000);
+		cpu_relax();
+	}
+
+	dumpdata.func = func;
+	dumpdata.info = info;
+	dumpdata.wait = 0; /* not used */
+	atomic_set(&dumpdata.started, 0); /* not used */
+	atomic_set(&dumpdata.finished, 0); /* not used */
+
+	call_data = &dumpdata;
+	mb();
+	send_IPI_allbutself(IPI_CALL_FUNC);
+	/* Don't wait */
+	spin_unlock(&dump_call_lock);
+}
+EXPORT_SYMBOL(dump_smp_call_function);
+
+/*
  * this function sends a 'generic call function' IPI to all other CPUs
  * in the system.
  */
--- linux-2.6.12/arch/ppc64/kernel/smp.c.orig	2005-08-23 10:49:53.005279633 -0400
+++ linux-2.6.12/arch/ppc64/kernel/smp.c	2005-08-23 10:51:04.770473481 -0400
@@ -200,6 +200,7 @@ void smp_send_stop(void)
  * Stolen from the i386 version.
  */
 static  __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
+static  __cacheline_aligned_in_smp DEFINE_SPINLOCK(dump_call_lock);
 
 static struct call_data_struct {
 	void (*func) (void *info);
@@ -207,12 +208,54 @@ static struct call_data_struct {
 	atomic_t started;
 	atomic_t finished;
 	int wait;
-} *call_data;
+} *call_data, *saved_call_data;
 
 /* delay of at least 8 seconds on 1GHz cpu */
 #define SMP_CALL_TIMEOUT (1UL << (30 + 3))
 
 /*
+ * dump version of smp_call_function to avoid deadlock in call_lock
+ */
+void dump_smp_call_function (void (*func) (void *info), void *info)
+{
+	static struct call_data_struct dumpdata;
+	int waitcount;
+
+	spin_lock(&dump_call_lock);
+	/* if another cpu beat us, they win! */
+	if (dumpdata.func) {
+		spin_unlock(&dump_call_lock);
+		func(info);
+		/* NOTREACHED */
+	}
+
+	/* freeze call_lock or wait for on-going IPIs to settle down */
+	waitcount = 0;
+	while (!spin_trylock(&call_lock)) {
+		if (waitcount++ > 1000) {
+			/* save original for dump analysis */
+			saved_call_data = call_data;
+			break;
+		}
+		udelay(1000);
+		barrier();
+	}
+	dumpdata.func = func;
+	dumpdata.info = info;
+	dumpdata.wait = 0; /* not used */
+	atomic_set(&dumpdata.started, 0); /* not used */
+	atomic_set(&dumpdata.finished, 0); /* not used */
+
+	call_data = &dumpdata;
+	wmb();
+	smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION);
+	/* Don't wait */
+	spin_unlock(&dump_call_lock);
+}
+
+EXPORT_SYMBOL(dump_smp_call_function);
+
+/*
  * This function sends a 'generic call function' IPI to all other CPUs
  * in the system.
  *
--- linux-2.6.12/arch/i386/kernel/smp.c.orig	2005-08-23 10:50:15.380598925 -0400
+++ linux-2.6.12/arch/i386/kernel/smp.c	2005-08-23 10:53:29.712621271 -0400
@@ -489,6 +489,7 @@ void smp_send_reschedule(int cpu)
  * static memory requirements. It also looks cleaner.
  */
 static DEFINE_SPINLOCK(call_lock);
+static DEFINE_SPINLOCK(dump_call_lock);
 
 struct call_data_struct {
 	void (*func) (void *info);
@@ -509,6 +510,49 @@ void unlock_ipi_call_lock(void)
 }
 
 static struct call_data_struct * call_data;
+static struct call_data_struct * saved_call_data;
+
+/*
+ * dump version of smp_call_function to avoid deadlock in call_lock
+ */
+void dump_smp_call_function (void (*func) (void *info), void *info)
+{
+	static struct call_data_struct dumpdata;
+	int waitcount;
+
+	spin_lock(&dump_call_lock);
+	/* if another cpu beat us, they win! */
+	if (dumpdata.func) {
+		spin_unlock(&dump_call_lock);
+		func(info);
+		/* NOTREACHED */
+	}
+	/* freeze call_lock or wait for on-going IPIs to settle down */
+	waitcount = 0;
+	while (!spin_trylock(&call_lock)) {
+		if (waitcount++ > 1000) {
+			/* save original for dump analysis */
+			saved_call_data = call_data;
+			break;
+		}
+		udelay(1000);
+		barrier();
+	}
+
+	dumpdata.func = func;
+	dumpdata.info = info;
+	dumpdata.wait = 0; /* not used */
+	atomic_set(&dumpdata.started, 0); /* not used */
+	atomic_set(&dumpdata.finished, 0); /* not used */
+
+	call_data = &dumpdata;
+	mb();
+	send_IPI_allbutself(CALL_FUNCTION_VECTOR);
+	/* Don't wait */
+	spin_unlock(&dump_call_lock);
+}
+
+EXPORT_SYMBOL(dump_smp_call_function);
 
 /*
  * this function sends a 'generic call function' IPI to all other CPUs
--- linux-2.6.12/arch/x86_64/kernel/smp.c.orig	2005-08-23 10:49:53.421211215 -0400
+++ linux-2.6.12/arch/x86_64/kernel/smp.c	2005-08-23 10:51:04.771473316 -0400
@@ -271,6 +271,7 @@ void smp_send_reschedule(int cpu)
  * static memory requirements. It also looks cleaner.
  */
 static DEFINE_SPINLOCK(call_lock);
+static DEFINE_SPINLOCK(dump_call_lock);
 
 struct call_data_struct {
 	void (*func) (void *info);
@@ -281,6 +282,48 @@ struct call_data_struct {
 };
 
 static struct call_data_struct * call_data;
+static struct call_data_struct * saved_call_data;
+
+/*
+ * dump version of smp_call_function to avoid deadlock in call_lock
+ */
+void dump_smp_call_function (void (*func) (void *info), void *info)
+{
+	static struct call_data_struct dumpdata;
+	int waitcount;
+
+	spin_lock(&dump_call_lock);
+	/* if another cpu beat us, they win! */
+	if (dumpdata.func) {
+		spin_unlock(&dump_call_lock);
+		func(info);
+		/* NOTREACHED */
+	}
+
+ 	/* freeze call_lock or wait for on-going IPIs to settle down */
+	waitcount = 0;
+	while (!spin_trylock(&call_lock)) {
+		if (waitcount++ > 1000) {
+			/* save original for dump analysis */
+			saved_call_data = call_data;
+			break;
+		}
+		udelay(1000);
+		barrier();
+	}
+
+	dumpdata.func = func;
+	dumpdata.info = info;
+	dumpdata.wait = 0; /* not used */
+	atomic_set(&dumpdata.started, 0); /* not used */
+	atomic_set(&dumpdata.finished, 0); /* not used */
+
+ 	call_data = &dumpdata;
+	wmb();
+	send_IPI_allbutself(CALL_FUNCTION_VECTOR);
+	/* Don't wait */
+	spin_unlock(&dump_call_lock);
+}
 
 void lock_ipi_call_lock(void)
 {
--- linux-2.6.12/drivers/block/diskdump.c.orig	2005-08-23 10:50:16.489416520 -0400
+++ linux-2.6.12/drivers/block/diskdump.c	2005-08-23 10:51:04.773472987 -0400
@@ -456,7 +456,7 @@ static void freeze_other_cpus(void)
 #if CONFIG_SMP
 	int	i;
 
-	smp_call_function(freeze_cpu, NULL, 1, -1);
+	dump_smp_call_function(freeze_cpu, NULL);
 	diskdump_mdelay(3000);
 	printk("CPU frozen: ");
 	for (i = 0; i < NR_CPUS; i++) {
--- linux-2.6.12/drivers/net/netdump.c.orig	2005-08-23 10:50:16.449423099 -0400
+++ linux-2.6.12/drivers/net/netdump.c	2005-08-23 10:51:04.774472823 -0400
@@ -356,7 +356,7 @@ static void netpoll_start_netdump(struct
 	local_irq_save(flags);
 	preempt_disable();
 
-	smp_call_function(freeze_cpu, NULL, 1, -1);
+	dump_smp_call_function(freeze_cpu, NULL);
 	netdump_mdelay(3000);
 	for (i = 0; i < NR_CPUS; i++) {
 		if (cpus_frozen[i])
--- linux-2.6.12/include/linux/smp.h.orig	2005-08-23 10:50:08.023809136 -0400
+++ linux-2.6.12/include/linux/smp.h	2005-08-23 10:51:04.775472658 -0400
@@ -55,6 +55,7 @@ extern void smp_cpus_done(unsigned int m
  */
 extern int smp_call_function (void (*func) (void *info), void *info,
 			      int retry, int wait);
+extern void dump_smp_call_function (void (*func) (void *info), void *info);
 
 /*
  * Call a function on all processors
@@ -95,6 +96,7 @@ void smp_prepare_boot_cpu(void);
 #define raw_smp_processor_id()			0
 #define hard_smp_processor_id()			0
 #define smp_call_function(func,info,retry,wait)	({ 0; })
+static inline void dump_smp_call_function(void (*func) (void *info), void *info) { }
 #define on_each_cpu(func,info,retry,wait)	({ func(info); 0; })
 static inline void smp_send_reschedule(int cpu) { }
 #define num_booting_cpus()			1

linux-2.6-netconsole.patch:
 netconsole.c |  121 +++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 106 insertions(+), 15 deletions(-)

--- NEW FILE linux-2.6-netconsole.patch ---
diff -urNp --exclude-from=/home/davej/.exclude linux-1501/drivers/net/netconsole.c linux-1502/drivers/net/netconsole.c
--- linux-1501/drivers/net/netconsole.c
+++ linux-1502/drivers/net/netconsole.c
@@ -45,6 +45,9 @@
 #include <linux/sysrq.h>
 #include <linux/smp.h>
 #include <linux/netpoll.h>
+#include <asm/unaligned.h>
+
+#include "netdump.h"
 
 MODULE_AUTHOR("Maintainer: Matt Mackall <mpm at selenic.com>");
 MODULE_DESCRIPTION("Console driver for network interfaces");
@@ -61,29 +61,100 @@ static struct netpoll np = {
 	.name = "netconsole",
 	.dev_name = "eth0",
 	.local_port = 6665,
-	.remote_port = 6666,
+	.remote_port = 514,
 	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
 	.drop = netpoll_queue,
 };
 static int configured = 0;
 
+static char netlog_config[256];
+module_param_string(netlog, netlog_config, 256, 0);
+MODULE_PARM_DESC(netlog, " netlog=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]\n");
+static struct netpoll netlog_np = {
+	.name = "netlog",
+	.dev_name = "eth0",
+	.local_port = 6664,
+	.remote_port = 6666,
+	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+};
+static int netlog_configured = 0;
+
 #define MAX_PRINT_CHUNK 1000
 
+#define SYSLOG_HEADER_LEN 4
+
+static int syslog_chars = SYSLOG_HEADER_LEN;
+static unsigned char syslog_line [MAX_PRINT_CHUNK + 10] = {
+	'<',
+	'5',
+	'>',
+	' ',
+	[4 ... MAX_PRINT_CHUNK+5] = '\0',
+};
+static unsigned char netlog_line[MAX_PRINT_CHUNK + HEADER_LEN];
+static unsigned int log_offset;
+
+/*
+ * We feed kernel messages char by char, and send the UDP packet
+ * one linefeed. We buffer all characters received.
+ */
+static inline void feed_syslog_char(const unsigned char c)
+{
+	if (syslog_chars == MAX_PRINT_CHUNK)
+		syslog_chars--;
+	syslog_line[syslog_chars] = c;
+	syslog_chars++;
+	if (c == '\n') {
+		netpoll_send_udp(&np, syslog_line, syslog_chars);
+		syslog_chars = SYSLOG_HEADER_LEN;
+	}
+}
+
 static void write_msg(struct console *con, const char *msg, unsigned int len)
 {
-	int frag, left;
+	int left, i;
 	unsigned long flags;
+	reply_t reply;
+	char *netlog_buf = &netlog_line[HEADER_LEN];
 
-	if (!np.dev)
+	if (!np.dev && !netlog_np.dev)
+		return;
+	if (unlikely(crashdump_mode()))
 		return;
 
 	local_irq_save(flags);
-
-	for(left = len; left; ) {
-		frag = min(left, MAX_PRINT_CHUNK);
-		netpoll_send_udp(&np, msg, frag);
-		msg += frag;
-		left -= frag;
+	if (np.dev)
+		for (i = 0; i < len; i++)
+			feed_syslog_char(msg[i]);
+
+	if (netlog_np.dev) {
+		left = len;
+		while (left) {
+			if (left > MAX_PRINT_CHUNK)
+				len = MAX_PRINT_CHUNK;
+			else
+				len = left;
+			netlog_line[0] = NETDUMP_VERSION;
+
+			reply.nr = 0;
+			reply.code = REPLY_LOG;
+			reply.info = log_offset;
+
+			put_unaligned(htonl(reply.nr), 
+				      (u32 *)(netlog_line + 1));
+			put_unaligned(htonl(reply.code),
+				      (u32 *)(netlog_line + 5));
+			put_unaligned(htonl(reply.info),
+				      (u32 *)(netlog_line + 9));
+
+			log_offset += len;
+			memcpy(netlog_buf, msg, len);
+
+			netpoll_send_udp(&netlog_np, 
+					 netlog_line, len + HEADER_LEN);
+			msg += len;
+			left -= len;
+		}
 	}
 
 	local_irq_restore(flags);
@@ -98,17 +173,29 @@ static int option_setup(char *opt)
 
 __setup("netconsole=", option_setup);
 
+static int netlog_option_setup(char *opt)
+{
+	netlog_configured = !netpoll_parse_options(&netlog_np, opt);
+	return 0;
+}
+
+__setup("netlog=", netlog_option_setup);
+
 static int init_netconsole(void)
 {
 	if(strlen(config))
 		option_setup(config);
 
-	if(!configured) {
-		printk("netconsole: not configured, aborting\n");
-		return -EINVAL;
-	}
+	if (strlen(netlog_config))
+		netlog_option_setup(netlog_config);
+
+	if (configured && netpoll_setup(&np))
+		printk("netconsole: failed to configure syslog service\n");
 
-	if(netpoll_setup(&np))
+	if (netlog_configured && netpoll_setup(&netlog_np))
+		printk("netconsole: failed to configured netlog service.\n");
+
+	if (!configured && !netlog_configured)
 		return -EINVAL;
 
 	register_console(&netconsole);
@@ -119,7 +206,12 @@ static int init_netconsole(void)
 static void cleanup_netconsole(void)
 {
 	unregister_console(&netconsole);
-	netpoll_cleanup(&np);
+
+	if (configured)
+		netpoll_cleanup(&np);
+
+	if (netlog_configured)
+		netpoll_cleanup(&netlog_np);
 }
 
 module_init(init_netconsole);

linux-2.6-netdump.patch:
 drivers/net/Makefile          |    1 
 drivers/net/netdump.c         |  550 ++++++++++++++++++++++++++++++++++++++++++
 drivers/net/netdump.h         |   90 ++++++
 include/asm-generic/netdump.h |   48 +++
 include/asm-i386/netdump.h    |   79 ++++++
 include/asm-ia64/netdump.h    |   82 ++++++
 include/asm-ppc64/netdump.h   |   79 ++++++
 include/asm-s390/netdump.h    |    6 
 include/asm-x86_64/netdump.h  |   79 ++++++
 include/linux/netdevice.h     |    8 
 include/linux/netpoll.h       |    4 
 net/Kconfig                   |    7 
 net/core/netpoll.c            |   17 +
 13 files changed, 1039 insertions(+), 11 deletions(-)

--- NEW FILE linux-2.6-netdump.patch ---
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/drivers/net/netdump.h	2005-08-19 17:47:33.033202480 -0400
@@ -0,0 +1,90 @@
+/*
+ *  linux/drivers/net/netdump.h
+ *
+ *  Copyright (C) 2001  Ingo Molnar <mingo at redhat.com>
+ *
+ *  This file contains the implementation of an IRQ-safe, crash-safe
+ *  kernel console implementation that outputs kernel messages to the
+ *  network.
+ *
+ * Modification history:
+ *
+ * 2001-09-17    started by Ingo Molnar.
+ */
+
+/****************************************************************
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************/
+
+#define NETDUMP_VERSION 0x04
+
+#define NETDUMP_VERSION_MAX 0x5
+
+enum netdump_commands {
+	COMM_NONE = 0,
+	COMM_SEND_MEM = 1,
+	COMM_EXIT = 2,
+	COMM_REBOOT = 3,
+	COMM_HELLO = 4,
+	COMM_GET_NR_PAGES = 5,
+	COMM_GET_PAGE_SIZE = 6,
+	COMM_START_NETDUMP_ACK = 7,
+	COMM_GET_REGS = 8,
+	COMM_SHOW_STATE = 9,
+};
+
+#define NETDUMP_REQ_SIZE (8+4*4)
+
+typedef struct netdump_req_s {
+	u64 magic;
+	u32 nr;
+	u32 command;
+	u32 from;
+	u32 to;
+	struct list_head list; 
+} req_t;
+
+enum netdump_replies {
+	REPLY_NONE = 0,
+	REPLY_ERROR = 1,
+	REPLY_LOG = 2,
+	REPLY_MEM = 3,
+	REPLY_RESERVED = 4,
+	REPLY_HELLO = 5,
+	REPLY_NR_PAGES = 6,
+	REPLY_PAGE_SIZE = 7,
+	REPLY_START_NETDUMP = 8,
+	REPLY_END_NETDUMP = 9,
+	REPLY_REGS = 10,
+	REPLY_MAGIC = 11,
+	REPLY_SHOW_STATE = 12,
+};
+
+typedef struct netdump_reply_s {
+	u32 nr;
+	u32 code;
+	u32 info;
+} reply_t;
+
+#define HEADER_LEN (1 + sizeof(reply_t))
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+#define netdump_mdelay(n) (                             \
+        {                                               \
+                unsigned long __ms=(n);                 \
+                while (__ms--) udelay(1000);            \
+        })
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/drivers/net/netdump.c	2005-08-19 17:47:33.024203976 -0400
@@ -0,0 +1,550 @@
+/*
+ *  linux/drivers/net/netdump.c
+ *
+ *  Copyright (C) 2001  Ingo Molnar <mingo at redhat.com>
+ *  Copyright (C) 2002  Red Hat, Inc.
+ *  Copyright (C) 2004  Red Hat, Inc.
+ *
+ *  This file contains the implementation of an IRQ-safe, crash-safe
+ *  kernel console implementation that outputs kernel messages to the
+ *  network.
+ *
+ * Modification history:
+ *
+ * 2001-09-17    started by Ingo Molnar.
+ * 2002-03-14    simultaneous syslog packet option by Michael K. Johnson
+ * 2004-04-07    port to 2.6 netpoll facility by Dave Anderson and Jeff Moyer.
+ */
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <asm/unaligned.h>
+#include <asm/pgtable.h>
+#include <linux/console.h>
+#include <linux/smp_lock.h>
+#include <linux/elf.h>
+#include <linux/preempt.h>
+
+#include "netdump.h"
+#include <linux/netpoll.h>
+
+/*
+ *  prototypes.
+ */
+void netdump_rx(struct netpoll *np, short source, char *data, int dlen);
+static void send_netdump_msg(struct netpoll *np, const char *msg, unsigned int msg_len, reply_t *reply);
+static void send_netdump_mem(struct netpoll *np, req_t *req);
+static void netdump_startup_handshake(struct netpoll *np);
+static asmlinkage void netpoll_netdump(struct pt_regs *regs, void *arg);
+static void netpoll_start_netdump(struct pt_regs *regs);
+
+
+#include <asm/netdump.h>
+
+
+#undef Dprintk
+#define DEBUG 0
+#if DEBUG
+# define Dprintk(x...) printk(KERN_INFO x)
+#else
+# define Dprintk(x...)
+#endif
+
+MODULE_AUTHOR("Maintainer: Dave Anderson <anderson at redhat.com>");
+MODULE_DESCRIPTION("Network kernel crash dump module");
+MODULE_LICENSE("GPL");
+
+static char config[256];
+module_param_string(netdump, config, 256, 0);
+MODULE_PARM_DESC(netdump, 
+     " netdump=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]\n");
+
+static u32 magic1, magic2;
+module_param(magic1, uint, 000);
+module_param(magic2, uint, 000);
+
+static struct netpoll np = {
+	.name = "netdump",
+	.dev_name = "eth0",
+	.local_port = 6666,
+	.remote_port = 6666,
+	.remote_mac = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	.rx_hook = netdump_rx,
+	.dump_func = netpoll_start_netdump,
+};
+
+
+/*
+ * NOTE: security depends on the trusted path between the netconsole
+ *       server and netconsole client, since none of the packets are
+ *       encrypted. The random magic number protects the protocol
+ *       against spoofing.
+ */
+static u64 netdump_magic;
+
+static spinlock_t req_lock = SPIN_LOCK_UNLOCKED;
+static int nr_req = 0;
+static LIST_HEAD(request_list);
+
+static unsigned long long t0, jiffy_cycles = 1000 * (1000000/HZ);
+void *netdump_stack;
+
+
+static void update_jiffies(void)
+{
+	static unsigned long long prev_tick;
+	platform_timestamp(t0);
+
+	/* maintain jiffies in a polling fashion, based on rdtsc. */
+	if (t0 - prev_tick >= jiffy_cycles) {
+		prev_tick += jiffy_cycles;
+		jiffies++;
+	}
+}
+
+static void add_new_req(req_t *req)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&req_lock, flags);
+	list_add_tail(&req->list, &request_list);
+	nr_req++;
+	Dprintk("pending requests: %d.\n", nr_req);
+	spin_unlock_irqrestore(&req_lock, flags);
+}
+
+static req_t *get_new_req(void)
+{
+	req_t *req = NULL;
+	unsigned long flags;
+
+	update_jiffies();
+
+	spin_lock_irqsave(&req_lock, flags);
+	if (nr_req) {
+		req = list_entry(request_list.next, req_t, list);
+		list_del(&req->list);
+		nr_req--;
+	}
+	spin_unlock_irqrestore(&req_lock, flags);
+
+	return req;
+}
+
+static req_t *alloc_req(void)
+{
+	req_t *req;
+
+	req = (req_t *) kmalloc(sizeof(*req), GFP_ATOMIC);
+	return req;
+}
+
+static inline void print_status (req_t *req)
+{
+	static int count = 0;
+	static unsigned long prev_jiffies = 0;
+
+	if (jiffies/HZ != prev_jiffies/HZ) {
+		prev_jiffies = jiffies;
+		count++;
+		switch (count & 3) {
+			case 0: printk("%d(%lu)/\r", nr_req, jiffies); break;
+			case 1: printk("%d(%lu)|\r", nr_req, jiffies); break;
+			case 2: printk("%d(%lu)\\\r", nr_req, jiffies); break;
+			case 3: printk("%d(%lu)-\r", nr_req, jiffies); break;
+		}
+	}
+}
+
+void netdump_rx(struct netpoll *np, short source, char *data, int dlen)
+{
+	req_t *req, *__req = (req_t *)data;
+
+	if (!netdump_mode)
+		return;
+#if DEBUG
+	{
+		static int packet_count;
+		Dprintk("        %d\r", ++packet_count);
+	}
+#endif
+
+	if (dlen < NETDUMP_REQ_SIZE) {
+		Dprintk("... netdump_rx: len not ok.\n");
+		return;
+	}
+
+	req = alloc_req();
+	if (!req) {
+		printk("no more RAM to allocate request - dropping it.\n");
+		return;
+	}
+
+	req->command = ntohl(__req->command);
+	req->from = ntohl(__req->from);
+	req->to = ntohl(__req->to);
+	req->nr = ntohl(__req->nr);
+
+	Dprintk("... netdump command: %08x.\n", req->command);
+	Dprintk("... netdump from:    %08x.\n", req->from);
+	Dprintk("... netdump to:      %08x.\n", req->to);
+
+	add_new_req(req);
+	return;
+}
+
+#define MAX_MSG_LEN HEADER_LEN + 1024
+
+static unsigned char effective_version = NETDUMP_VERSION;
+
+static void send_netdump_msg(struct netpoll *np, const char *msg, unsigned int msg_len, reply_t *reply)
+{
+	/* max len should be 1024 + HEADER_LEN */
+	static unsigned char netpoll_msg[MAX_MSG_LEN + 1];
+
+	if (msg_len + HEADER_LEN > MAX_MSG_LEN + 1) {
+		printk("CODER ERROR!!! msg_len %ud too big for send msg\n",
+		       msg_len);
+		for (;;) local_irq_disable();
+		/* NOTREACHED */
+	}
+
+	netpoll_msg[0] = effective_version;
+	put_unaligned(htonl(reply->nr), (u32 *) (&netpoll_msg[1]));
+	put_unaligned(htonl(reply->code), (u32 *) (&netpoll_msg[5]));
+	put_unaligned(htonl(reply->info), (u32 *) (&netpoll_msg[9]));
+	memcpy(&netpoll_msg[HEADER_LEN], msg, msg_len);
+
+	netpoll_send_udp(np, netpoll_msg, HEADER_LEN + msg_len);
+}
+
+static void send_netdump_mem(struct netpoll *np, req_t *req)
+{
+	int i;
+	char *kaddr;
+	char str[1024];
+	struct page *page = NULL;
+	unsigned long nr = req->from;
+	int nr_chunks = PAGE_SIZE/1024;
+	reply_t reply;
+	
+	Dprintk(" ... send_netdump_mem\n");
+	reply.nr = req->nr;
+	reply.info = 0;
+	if (req->from >= platform_max_pfn()) {
+		sprintf(str, "page %08lx is bigger than max page # %08lx!\n", 
+			nr, platform_max_pfn());
+		reply.code = REPLY_ERROR;
+		send_netdump_msg(np, str, strlen(str), &reply);
+		return;
+	}
+	if (platform_page_is_ram(nr)) {
+		page = pfn_to_page(nr);
+		if (page_to_pfn(page) != nr)
+			page = NULL;
+	}
+	if (!page) {
+		reply.code = REPLY_RESERVED;
+		reply.info = platform_next_available(nr);
+		send_netdump_msg(np, str, 0, &reply);
+		return;
+	}
+
+	kaddr = (char *)kmap_atomic(page, KM_CRASHDUMP);
+
+	for (i = 0; i < nr_chunks; i++) {
+		unsigned int offset = i*1024;
+		reply.code = REPLY_MEM;
+		reply.info = offset;
+		Dprintk(" ... send_netdump_mem: sending message\n");
+		send_netdump_msg(np, kaddr + offset, 1024, &reply);
+		Dprintk(" ... send_netdump_mem: sent message\n");
+	}
+
+	kunmap_atomic(kaddr, KM_CRASHDUMP);
+	Dprintk(" ... send_netdump_mem: returning\n");
+}
+
+/*
+ * This function waits for the client to acknowledge the receipt
+ * of the netdump startup reply, with the possibility of packets
+ * getting lost. We resend the startup packet if no ACK is received,
+ * after a 1 second delay.
+ *
+ * (The client can test the success of the handshake via the HELLO
+ * command, and send ACKs until we enter netdump mode.)
+ */
+static void netdump_startup_handshake(struct netpoll *np)
+{
+	char tmp[200];
+	reply_t reply;
+	req_t *req = NULL;
+	int i;
+
+repeat:
+	sprintf(tmp,
+   	    "task_struct:0x%lx page_offset:0x%llx netdump_magic:0x%llx\n",
+		(unsigned long)current, (unsigned long long)PAGE_OFFSET, 
+		(unsigned long long)netdump_magic);
+	reply.code = REPLY_START_NETDUMP;
+	reply.nr = platform_machine_type();
+	reply.info = NETDUMP_VERSION_MAX;
+
+	send_netdump_msg(np, tmp, strlen(tmp), &reply);
+
+	for (i = 0; i < 10000; i++) {
+		// wait 1 sec.
+		udelay(100);
+		Dprintk("handshake: polling controller ...\n");
+		netpoll_poll(np);
+		req = get_new_req();
+		if (req)
+			break;
+	}
+	if (!req)
+		goto repeat;
+	if (req->command != COMM_START_NETDUMP_ACK) {
+		kfree(req);
+		goto repeat;
+	}
+
+	/*
+	 *  Negotiate an effective version that works with the server. 
+	 */
+	if ((effective_version = platform_effective_version(req)) == 0) {
+		printk(KERN_ERR
+			"netdump: server cannot handle this client -- rebooting.\n");
+		netdump_mdelay(3000);
+		machine_restart(NULL);
+	}
+
+	kfree(req);
+
+	printk("NETDUMP START!\n");
+}
+
+static char cpus_frozen[NR_CPUS] = { 0 }; 
+
+static void freeze_cpu (void * dummy)
+{
+	cpus_frozen[smp_processor_id()] = 1;
+	platform_freeze_cpu();
+}
+
+static void netpoll_start_netdump(struct pt_regs *regs)
+{
+	int i;
+	unsigned long flags;
+
+	/*
+	 *  The netdump code is not re-entrant for several reasons.  Most
+	 *  immediately, we will switch to the base of our stack and 
+	 *  overwrite all of our call history.
+	 */
+	if (netdump_mode) {
+		printk(KERN_ERR
+		"netpoll_start_netdump: called recursively.  rebooting.\n");
+		netdump_mdelay(3000);
+		machine_restart(NULL);
+	}
+	netdump_mode = 1;
+
+	local_irq_save(flags);
+	preempt_disable();
+
+	smp_call_function(freeze_cpu, NULL, 1, -1);
+	netdump_mdelay(3000);
+	for (i = 0; i < NR_CPUS; i++) {
+		if (cpus_frozen[i])
+			printk("CPU#%d is frozen.\n", i);
+		else if (i == smp_processor_id())
+			printk("CPU#%d is executing netdump.\n", i);
+	}
+
+	/*
+	 *  Some platforms may want to execute netdump on its own stack.
+	 */
+	platform_start_crashdump(netdump_stack, netpoll_netdump, regs);
+
+	preempt_enable_no_resched();
+	local_irq_restore(flags);
+	return;
+}
+
+static char command_tmp[1024];
+
+static asmlinkage void netpoll_netdump(struct pt_regs *regs, void *platform_arg)
+{
+	reply_t reply;
+	char *tmp = command_tmp;
+	extern unsigned long totalram_pages;
+	struct pt_regs myregs;
+	req_t *req;
+
+	/*
+	 * Just in case we are crashing within the networking code
+	 * ... attempt to fix up.
+	 */
+	netpoll_reset_locks(&np);
+	platform_fix_regs();
+	platform_timestamp(t0);
+	netpoll_set_trap(1); /* bypass networking stack */
+
+	printk("< netdump activated - performing handshake with the server. >\n");
+	netdump_startup_handshake(&np);
+
+	printk("< handshake completed - listening for dump requests. >\n");
+
+	while (netdump_mode) {
+		local_irq_disable();
+		Dprintk("main netdump loop: polling controller ...\n");
+		netpoll_poll(&np);
+
+		req = get_new_req();
+		if (!req)
+			continue;
+
+		Dprintk("got new req, command %d.\n", req->command);
+		print_status(req);
+		switch (req->command) {
+		case COMM_NONE:
+			Dprintk("got NO command.\n");
+			break;
+
+		case COMM_SEND_MEM:
+			Dprintk("got MEM command.\n");
+			send_netdump_mem(&np, req);
+			break;
+
+		case COMM_EXIT:
+			Dprintk("got EXIT command.\n");
+			netdump_mode = 0;
+			netpoll_set_trap(0);
+			break;
+
+		case COMM_REBOOT:
+			Dprintk("got REBOOT command.\n");
+			printk("netdump: rebooting in 3 seconds.\n");
+			netdump_mdelay(3000);
+			machine_restart(NULL);
+			break;
+
+		case COMM_HELLO:
+			sprintf(tmp, "Hello, this is netdump version 0.%02d\n",
+				NETDUMP_VERSION);
+			reply.code = REPLY_HELLO;
+			reply.nr = req->nr;
+			reply.info = NETDUMP_VERSION;
+			send_netdump_msg(&np, tmp, strlen(tmp), &reply);
+			break;
+
+		case COMM_GET_PAGE_SIZE:
+			sprintf(tmp, "PAGE_SIZE: %ld\n", PAGE_SIZE);
+			reply.code = REPLY_PAGE_SIZE;
+			reply.nr = req->nr;
+			reply.info = PAGE_SIZE;
+			send_netdump_msg(&np, tmp, strlen(tmp), &reply);
+			break;
+
+		case COMM_GET_REGS:
+			reply.code = REPLY_REGS;
+			reply.nr = req->nr;
+			reply.info = (u32)totalram_pages;
+        		send_netdump_msg(&np, tmp,
+				platform_get_regs(tmp, &myregs), &reply);
+			break;
+
+		case COMM_GET_NR_PAGES:
+			reply.code = REPLY_NR_PAGES;
+			reply.nr = req->nr;
+			reply.info = platform_max_pfn();
+			sprintf(tmp, 
+				"Number of pages: %ld\n", platform_max_pfn());
+			send_netdump_msg(&np, tmp, strlen(tmp), &reply);
+			break;
+
+		case COMM_SHOW_STATE:
+			/* send response first */
+			reply.code = REPLY_SHOW_STATE;
+			reply.nr = req->nr;
+			reply.info = 0;
+
+			send_netdump_msg(&np, tmp, strlen(tmp), &reply);
+
+			netdump_mode = 0;
+			if (regs)
+				show_regs(regs);
+			show_state();
+			show_mem();
+			netdump_mode = 1;
+			break;
+
+		default:
+			reply.code = REPLY_ERROR;
+			reply.nr = req->nr;
+			reply.info = req->command;
+			Dprintk("got UNKNOWN command!\n");
+			sprintf(tmp, "Got unknown command code %d!\n", 
+				req->command);
+			send_netdump_msg(&np, tmp, strlen(tmp), &reply);
+			break;
+		}
+		kfree(req);
+		req = NULL;
+	}
+	sprintf(tmp, "NETDUMP end.\n");
+	reply.code = REPLY_END_NETDUMP;
+	reply.nr = 0;
+	reply.info = 0;
+	send_netdump_msg(&np, tmp, strlen(tmp), &reply);
+	printk("NETDUMP END!\n");
+}
+
+static int option_setup(char *opt)
+{
+	return !netpoll_parse_options(&np, opt);
+}
+
+__setup("netdump=", option_setup);
+
+static int init_netdump(void)
+{
+	int configured = 0;
+
+	if (strlen(config))
+		configured = option_setup(config);
+
+	if (!configured) {
+		printk(KERN_ERR "netdump: not configured, aborting\n");
+		return -EINVAL;
+	}
+
+	if (netpoll_setup(&np))
+		return -EINVAL;
+
+	if (magic1 || magic2)
+		netdump_magic = magic1 + (((u64)magic2)<<32);
+
+	/*
+	 *  Allocate a separate stack for netdump.
+	 */
+	platform_init_stack(&netdump_stack);
+
+	platform_jiffy_cycles(&jiffy_cycles);
+
+	printk(KERN_INFO "netdump: network crash dump enabled\n");
+	return 0;
+}
+
+static void cleanup_netdump(void)
+{
+	netpoll_cleanup(&np);
+	platform_cleanup_stack(netdump_stack);
+}
+
+module_init(init_netdump);
+module_exit(cleanup_netdump);
--- linux-2.6.12/net/Kconfig~	2005-08-26 02:41:34.000000000 -0400
+++ linux-2.6.12/net/Kconfig	2005-08-26 02:41:54.000000000 -0400
@@ -618,6 +618,13 @@ endmenu
 
 endmenu
 
+config NETDUMP
+  tristate "Network kernel crash dump support"
+  depends on NETPOLL && NETPOLL_TRAP && (X86 || PPC_PSERIES || IA64)
+  ---help---
+  Enable this option if you have a netdump server and you would like
+  to collect kernel crash dumps.
+
 config NETPOLL
 	def_bool NETCONSOLE
 
--- linux-2.6.12/drivers/net/Makefile.netdump.orig	2005-08-19 17:45:43.053483367 -0400
+++ linux-2.6.12/drivers/net/Makefile	2005-08-19 17:47:33.025203810 -0400
@@ -195,3 +195,4 @@ obj-$(CONFIG_IRDA) += irda/
 obj-$(CONFIG_ETRAX_ETHERNET) += cris/
 
 obj-$(CONFIG_NETCONSOLE) += netconsole.o
+obj-$(CONFIG_NETDUMP) += netdump.o
--- linux-2.6.12/net/core/netpoll.c.netdump.orig	2005-08-19 17:46:01.104483015 -0400
+++ linux-2.6.12/net/core/netpoll.c	2005-08-19 17:47:33.034202314 -0400
@@ -20,10 +20,12 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/rcupdate.h>
+#include <linux/nmi.h>
 #include <linux/workqueue.h>
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <asm/unaligned.h>
+#include <asm/byteorder.h>
 
 /*
  * We maintain a small pool of fully-sized skbs, to make sure the
@@ -132,7 +132,7 @@ static int checksum_udp(struct sk_buff *
  */
 static void poll_napi(struct netpoll *np)
 {
-	int budget = 16;
+	int budget = netdump_mode ? 64 : 16;
 
 	if (test_bit(__LINK_STATE_RX_SCHED, &np->dev->state) &&
 	    np->poll_owner != smp_processor_id() &&
@@ -203,6 +205,7 @@ static void zap_completion_queue(void)
 	}
 
 	put_cpu_var(softnet_data);
+	touch_nmi_watchdog();
 }
 
 static struct sk_buff * find_skb(struct netpoll *np, int len, int reserve)
@@ -337,7 +340,7 @@ void netpoll_send_udp(struct netpoll *np
 	iph->check    = 0;
 	put_unaligned(htonl(np->local_ip), &(iph->saddr));
 	put_unaligned(htonl(np->remote_ip), &(iph->daddr));
-	iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
+	iph->check    = ip_fast_csum((unsigned char *)iph, 5);
 
 	eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
 
@@ -614,6 +617,9 @@ int netpoll_parse_options(struct netpoll
 	       np->remote_mac[4],
 	       np->remote_mac[5]);
 
+	if(np->dump_func)
+		netdump_func = np->dump_func;
+
 	return 0;
 
  parse_failed:
@@ -776,6 +782,12 @@ void netpoll_set_trap(int trap)
 		atomic_dec(&trapped);
 }
 
+void netpoll_reset_locks(struct netpoll *np)
+{
+	spin_lock_init(&skb_list_lock);
+	spin_lock_init(&np->dev->xmit_lock);
+}
+
 EXPORT_SYMBOL(netpoll_set_trap);
 EXPORT_SYMBOL(netpoll_trap);
 EXPORT_SYMBOL(netpoll_parse_options);
@@ -784,3 +796,4 @@ EXPORT_SYMBOL(netpoll_cleanup);
 EXPORT_SYMBOL(netpoll_send_udp);
 EXPORT_SYMBOL(netpoll_poll);
 EXPORT_SYMBOL(netpoll_queue);
+EXPORT_SYMBOL_GPL(netpoll_reset_locks);
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-ia64/netdump.h	2005-08-19 17:47:33.035202148 -0400
@@ -0,0 +1,82 @@
+#ifndef _ASM_IA64_NETDUMP_H_
+#define _ASM_IA64_NETDUMP_H_
+
+/*
+ * linux/include/asm-ia64/netdump.h
+ *
+ * Copyright (c) 2003, 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __KERNEL__
+
+#include <asm/crashdump.h>
+
+const static int platform_supports_netdump = 1;
+
+#define platform_machine_type() (EM_IA_64)
+
+#define platform_page_is_ram(x) page_is_ram(x)
+
+static inline unsigned char platform_effective_version(req_t *req)
+{
+	if (req->from > 0)
+		return min_t(unsigned char, req->from, NETDUMP_VERSION_MAX);
+	else
+		return 0;
+}
+
+extern void *high_memory;
+#define platform_max_pfn() ((__pa(high_memory)) / PAGE_SIZE)
+
+static inline u32 platform_next_available(unsigned long pfn)
+{
+	unsigned long pgnum = next_ram_page(pfn);
+
+	if (pgnum < platform_max_pfn()) {
+		return (u32)pgnum;
+	}
+	return 0;
+}
+
+static inline void platform_jiffy_cycles(unsigned long long *jcp)
+{
+        unsigned long long t0, t1;
+
+        platform_timestamp(t0);
+        netdump_mdelay(1);
+        platform_timestamp(t1);
+        if (t1 > t0)
+                *jcp = t1 - t0;
+}
+
+#define platform_freeze_cpu()                                  \
+{                                                              \
+       unw_init_running(ia64_freeze_cpu, 0);                   \
+}
+
+static inline unsigned int platform_get_regs(char *tmp, struct pt_regs *myregs)
+{
+	char *tmp2;
+
+	tmp2 = tmp + sprintf(tmp, "Sending register info.\n");
+	memcpy(tmp2, myregs, sizeof(struct pt_regs));
+
+	return(strlen(tmp) + sizeof(struct pt_regs));
+}
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_IA64_NETDUMP_H */
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-x86_64/netdump.h	2005-08-19 17:47:33.036201981 -0400
@@ -0,0 +1,79 @@
+#ifndef _ASM_X86_64_NETDUMP_H_
+#define _ASM_X86_64_NETDUMP_H_
+
+/*
+ * linux/include/asm-x86_64/netdump.h
+ *
+ * Copyright (c) 2003, 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __KERNEL__
+
+#include <asm/crashdump.h>
+
+const static int platform_supports_netdump = 1;
+
+#define platform_machine_type() (EM_X86_64)
+
+#define platform_page_is_ram(x) (page_is_ram(x) && \
+                kern_addr_valid((unsigned long)pfn_to_kaddr(x)))
+
+static inline unsigned char platform_effective_version(req_t *req)
+{
+	if (req->from > 0)
+		return min_t(unsigned char, req->from, NETDUMP_VERSION_MAX);
+	else
+		return 0;
+}
+
+#define platform_max_pfn() (num_physpages)
+
+static inline u32 platform_next_available(unsigned long pfn)
+{
+	unsigned long pgnum = next_ram_page(pfn);
+
+	if (pgnum < platform_max_pfn()) {
+		return (u32)pgnum;
+	}
+	return 0;
+}
+
+static inline void platform_jiffy_cycles(unsigned long long *jcp)
+{
+        unsigned long long t0, t1;
+
+        platform_timestamp(t0);
+        netdump_mdelay(1);
+        platform_timestamp(t1);
+        if (t1 > t0)
+                *jcp = t1 - t0;
+}
+
+static inline unsigned int platform_get_regs(char *tmp, struct pt_regs *myregs)
+{
+	elf_gregset_t elf_regs;
+	char *tmp2;
+
+	tmp2 = tmp + sprintf(tmp, "Sending register info.\n");
+	ELF_CORE_COPY_REGS(elf_regs, myregs);
+	memcpy(tmp2, &elf_regs, sizeof(elf_regs));
+
+	return(strlen(tmp) + sizeof(elf_regs));
+}
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_X86_64_NETDUMP_H */
--- linux-2.6.12/include/linux/netdevice.h.netdump.orig	2005-08-19 17:45:54.528576035 -0400
+++ linux-2.6.12/include/linux/netdevice.h	2005-08-19 17:47:33.040201316 -0400
@@ -596,20 +596,12 @@ static inline void netif_start_queue(str
 
 static inline void netif_wake_queue(struct net_device *dev)
 {
-#ifdef CONFIG_NETPOLL_TRAP
-	if (netpoll_trap())
-		return;
-#endif
 	if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
 		__netif_schedule(dev);
 }
 
 static inline void netif_stop_queue(struct net_device *dev)
 {
-#ifdef CONFIG_NETPOLL_TRAP
-	if (netpoll_trap())
-		return;
-#endif
 	set_bit(__LINK_STATE_XOFF, &dev->state);
 }
 
--- linux-2.6.12/include/linux/netpoll.h.netdump.orig	2005-08-19 17:46:01.045492820 -0400
+++ linux-2.6.12/include/linux/netpoll.h	2005-08-19 17:47:33.041201150 -0400
@@ -17,7 +17,8 @@ struct netpoll {
 	struct net_device *dev;
 	char dev_name[16], *name;
 	int rx_flags;
-	void (*rx_hook)(struct netpoll *, int, char *, int);
+	void (*rx_hook)(struct netpoll *, short, char *, int);
+	void (*dump_func)(struct pt_regs *);
 	void (*drop)(struct sk_buff *skb);
 	u32 local_ip, remote_ip;
 	u16 local_port, remote_port;
@@ -42,6 +43,7 @@ void netpoll_set_trap(int trap);
 void netpoll_cleanup(struct netpoll *np);
 int __netpoll_rx(struct sk_buff *skb);
 void netpoll_queue(struct sk_buff *skb);
+void netpoll_reset_locks(struct netpoll *np);
 
 #ifdef CONFIG_NETPOLL
 static inline int netpoll_rx(struct sk_buff *skb)
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-generic/netdump.h	2005-08-19 17:47:33.042200984 -0400
@@ -0,0 +1,48 @@
+#ifndef _ASM_GENERIC_NETDUMP_H_
+#define _ASM_GENERIC_NETDUMP_H_
+
+/*
+ * linux/include/asm-generic/netdump.h
+ *
+ * Copyright (c) 2003, 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm-generic/crashdump.h>
+
+#ifdef __KERNEL__
+
+#warning netdump is not supported on this platform
+const static int platform_supports_netdump = 0;
+
+static inline int page_is_ram(unsigned long x) { return 0; }
+
+#define platform_machine_type() (EM_NONE)
+#define platform_effective_version(x) (0)
+#define platform_next_available(x) ((u32)0)
+#define platform_freeze_cpu()  do { } while (0)
+#define platform_jiffy_cycles(x)  do { } while (0)
+#define platform_max_pfn() (0)
+#define platform_get_regs(x,y) (0)
+
+#undef kmap_atomic
+#undef kunmap_atomic
+static inline char *kmap_atomic(void *page, int idx)  { return NULL; }
+#define kunmap_atomic(addr, idx)  do { } while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_GENERIC_NETDUMP_H */
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-ppc64/netdump.h	2005-08-19 17:47:33.036201981 -0400
@@ -0,0 +1,79 @@
+#ifndef _ASM_PPC64_NETDUMP_H_
+#define _ASM_PPC64_NETDUMP_H_
+
+/*
+ * linux/include/asm-ppc64/netdump.h
+ *
+ * Copyright (c) 2003, 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef __KERNEL__
+
+#include <asm/crashdump.h>
+
+const static int platform_supports_netdump = 1;
+
+#define platform_page_is_ram(x) (page_is_ram(x))
+#define platform_machine_type() (EM_PPC64)
+
+static inline unsigned char platform_effective_version(req_t *req)
+{
+	if (req->from > 0)
+		return min_t(unsigned char, req->from, NETDUMP_VERSION_MAX);
+	else
+		return 0;
+}
+
+#define platform_max_pfn() (num_physpages)
+
+static inline u32 platform_next_available(unsigned long pfn)
+{
+	unsigned long pgnum = next_ram_page(pfn);
+
+	if (pgnum < platform_max_pfn()) {
+		return (u32)pgnum;
+	}
+	return 0;
+}
+
+static inline void platform_jiffy_cycles(unsigned long long *jcp)
+{
+       unsigned long long t0, t1;
+
+       platform_timestamp(t0);
+       netdump_mdelay(1);
+       platform_timestamp(t1);
+       if (t1 > t0)
+               *jcp = t1 - t0;
+}
+
+static inline unsigned int platform_get_regs(char *tmp, struct pt_regs *myregs)
+{
+	elf_gregset_t elf_regs;
+	char *tmp2;
+
+	tmp2 = tmp + sprintf(tmp, "Sending register info.\n");
+	ELF_CORE_COPY_REGS(elf_regs, myregs);
+	memcpy(tmp2, &elf_regs, sizeof(elf_regs));
+
+	return(strlen(tmp) + sizeof(elf_regs));
+}
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_PPC64_NETDUMP_H_ */
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-i386/netdump.h	2005-08-19 17:47:33.037201815 -0400
@@ -0,0 +1,79 @@
+#ifndef _ASM_I386_NETDUMP_H_
+#define _ASM_I386_NETDUMP_H_
+
+/*
+ * linux/include/asm-i386/netdump.h
+ *
+ * Copyright (c) 2003, 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef __KERNEL__
+
+#include <asm/irq.h>
+#include <asm/crashdump.h>
+
+const static int platform_supports_netdump = 1;
+
+#define platform_page_is_ram(x) (page_is_ram(x))
+#define platform_machine_type() (EM_386)
+
+static inline unsigned char platform_effective_version(req_t *req)
+{
+        if (req->from == 0)
+                return NETDUMP_VERSION;
+        else
+                return min_t(unsigned char, req->from, NETDUMP_VERSION_MAX);
+}
+
+#define platform_max_pfn() (num_physpages)
+
+static inline u32 platform_next_available(unsigned long pfn)
+{
+	unsigned long pgnum = next_ram_page(pfn);
+
+	if (pgnum < platform_max_pfn()) {
+		return (u32)pgnum;
+	}
+	return 0;
+}
+
+static inline void platform_jiffy_cycles(unsigned long long *jcp)
+{
+        unsigned long long t0, t1;
+
+        platform_timestamp(t0);
+        netdump_mdelay(1);
+        platform_timestamp(t1);
+        if (t1 > t0)
+                *jcp = t1 - t0;
+}
+
+static inline unsigned int platform_get_regs(char *tmp, struct pt_regs *myregs)
+{
+	elf_gregset_t elf_regs;
+	char *tmp2;
+
+	tmp2 = tmp + sprintf(tmp, "Sending register info.\n");
+	ELF_CORE_COPY_REGS(elf_regs, myregs);
+	memcpy(tmp2, &elf_regs, sizeof(elf_regs));
+
+	return(strlen(tmp) + sizeof(elf_regs));
+}
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_I386_NETDUMP_H_ */
--- /dev/null	2005-07-20 12:00:41.186496416 -0400
+++ linux-2.6.12/include/asm-s390/netdump.h	2005-08-19 17:47:33.043200818 -0400
@@ -0,0 +1,6 @@
+#ifndef _ASM_S390_NETDUMP_H_
+#define _ASM_S390_NETDUMP_H_
+
+#include <asm-generic/netdump.h>
+
+#endif /* _ASM_S390_NETDUMP_H_ */

linux-2.6-scsi-sym2-alloc_lcb_tags-atomic.patch:
 sym_hipd.c |    2 +-
 1 files changed, 1 insertion(+), 1 deletion(-)

--- NEW FILE linux-2.6-scsi-sym2-alloc_lcb_tags-atomic.patch ---
--- linux-2.6.12/drivers/scsi/sym53c8xx_2/sym_hipd.c~	2005-08-26 02:27:35.000000000 -0400
+++ linux-2.6.12/drivers/scsi/sym53c8xx_2/sym_hipd.c	2005-08-26 02:28:02.000000000 -0400
@@ -5104,7 +5104,7 @@ static void sym_alloc_lcb_tags (struct s
 	lp->itlq_tbl = sym_calloc_dma(SYM_CONF_MAX_TASK*4, "ITLQ_TBL");
 	if (!lp->itlq_tbl)
 		goto fail;
-	lp->cb_tags = kcalloc(SYM_CONF_MAX_TASK, 1, GFP_KERNEL);
+	lp->cb_tags = kcalloc(SYM_CONF_MAX_TASK, 1, GFP_ATOMIC);
 	if (!lp->cb_tags) {
 		sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL");
 		lp->itlq_tbl = NULL;


Index: kernel-2.6.spec
===================================================================
RCS file: /cvs/dist/rpms/kernel/FC-3/kernel-2.6.spec,v
retrieving revision 1.868
retrieving revision 1.869
diff -u -r1.868 -r1.869
--- kernel-2.6.spec	26 Aug 2005 05:16:15 -0000	1.868
+++ kernel-2.6.spec	26 Aug 2005 08:26:20 -0000	1.869
@@ -283,10 +283,12 @@
 Patch1404: linux-2.6-usbhid-wireless-security-lock.patch
 
 # Netdump and Diskdump bits.
-Patch1500: linux-2.6.10-crashdump-common.patch
-Patch1501: linux-2.6.10-netdump.patch
-Patch1502: linux-2.6.8-netconsole.patch
-Patch1503: linux-2.6.10-diskdump.patch
+Patch1500: linux-2.6-crashdump-common.patch
+Patch1501: linux-2.6-netdump.patch
+Patch1502: linux-2.6-netconsole.patch
+Patch1503: linux-2.6-diskdump.patch
+Patch1504: linux-2.6-crashdump-reboot-exports.patch
+Patch1505: linux-2.6-dump_smp_call_function.patch
 
 # Misc bits.
 Patch1600: linux-2.6.11-i2c-config.patch
@@ -581,10 +583,11 @@
 
 # netdump bits
 %patch1500 -p1
-# Netdump is broken right now. It applies, but not with -F1. Its h0rked. Leave it off.
-#%patch1501 -p1
-#%patch1502 -p1
+%patch1501 -p1
+%patch1502 -p1
 %patch1503 -p1
+%patch1504 -p1
+%patch1505 -p1
 
 #
 # Various SELinux fixes from 2.6.10rc
@@ -978,6 +981,10 @@
 %changelog
 * Fri Aug 26 2005 Dave Jones <davej at redhat.com>
 - Better identify local builds. (#159696)
+- Fix disk/net dump & netconsole. (#152586)
+- Fix up sleeping in invalid context in sym2 driver. (#164995)
+- Fix 'semaphore is not ready' error in snd-intel8x0m.
+- Restore hwclock functionality on some systems. (#144894)
 
 * Tue Aug 23 2005 Dave Jones <davej at redhat.com> [2.6.12-1.1375_FC3]
 - Work around AMD x86-64 errata 122.

linux-2.6-compile-fixes.patch:
 linux-10001/arch/ppc/Makefile               |    1 +
 linux-10001/arch/ppc/kernel/head.S          |    2 +-
 linux-10001/arch/ppc/kernel/misc.S          |    2 +-
 linux-10001/arch/ppc/mm/hashtable.S         |    4 ++--
 linux-10001/arch/ppc/platforms/pmac_sleep.S |    2 +-
 linux-10001/arch/ppc64/Makefile             |    2 +-
 linux-10001/arch/ppc64/boot/main.c          |    1 +
 linux-10001/crypto/Makefile                 |    2 ++
 linux-10001/drivers/md/Makefile             |    2 ++
 linux-10001/include/asm-ppc/ppc_asm.h       |    2 +-
 linux-10001/include/linux/config.h          |    2 +-
 linux-10001/scripts/kconfig/Makefile        |    2 +-
 linux-10001/scripts/reference_discarded.pl  |    1 +
 linux-10001/sound/core/oss/Makefile         |    1 +
 linux-2.6.11/drivers/char/agp/hp-agp.c      |    3 +--
 linux-2.6.11/drivers/firmware/pcdp.c        |    1 +
 linux-2.6.12/drivers/net/sk98lin/skge.c     |    2 ++
 17 files changed, 21 insertions(+), 11 deletions(-)

Index: linux-2.6-compile-fixes.patch
===================================================================
RCS file: /cvs/dist/rpms/kernel/FC-3/linux-2.6-compile-fixes.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- linux-2.6-compile-fixes.patch	5 Aug 2005 23:17:02 -0000	1.1
+++ linux-2.6-compile-fixes.patch	26 Aug 2005 08:26:20 -0000	1.2
@@ -204,3 +204,4 @@
  };
  
  static int __init skge_init(void)
+

linux-2.6.11-panic-stackdump.patch:
 panic.c |    1 +
 1 files changed, 1 insertion(+)

Index: linux-2.6.11-panic-stackdump.patch
===================================================================
RCS file: /cvs/dist/rpms/kernel/FC-3/linux-2.6.11-panic-stackdump.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- linux-2.6.11-panic-stackdump.patch	20 Apr 2005 06:31:21 -0000	1.1
+++ linux-2.6.11-panic-stackdump.patch	26 Aug 2005 08:26:20 -0000	1.2
@@ -1,10 +1,10 @@
---- linux-2.6.11/kernel/panic.c~	2005-04-19 22:09:50.000000000 -0400
-+++ linux-2.6.11/kernel/panic.c	2005-04-19 22:09:57.000000000 -0400
-@@ -68,6 +68,7 @@ NORET_TYPE void panic(const char * fmt, 
+--- linux-2.6.12/kernel/panic.c~	2005-06-27 01:31:30.000000000 -0400
++++ linux-2.6.12/kernel/panic.c	2005-06-27 01:31:40.000000000 -0400
+@@ -76,6 +76,7 @@ NORET_TYPE void panic(const char * fmt, 
  	vsnprintf(buf, sizeof(buf), fmt, args);
  	va_end(args);
  	printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
-+	dump_stack();
- 	if (crashdump_func())
- 		BUG();
++ 	dump_stack();
  	bust_spinlocks(0);
+ 
+ 	/*




More information about the fedora-cvs-commits mailing list