Whamcloud - gitweb
delete lkcd-cvs-2.6.0-test5.patch
authorwangdi <wangdi>
Thu, 9 Oct 2003 15:02:59 +0000 (15:02 +0000)
committerwangdi <wangdi>
Thu, 9 Oct 2003 15:02:59 +0000 (15:02 +0000)
lustre/kernel_patches/patches/lkcd-cvs-2.6.0-test5.patch [deleted file]

diff --git a/lustre/kernel_patches/patches/lkcd-cvs-2.6.0-test5.patch b/lustre/kernel_patches/patches/lkcd-cvs-2.6.0-test5.patch
deleted file mode 100644 (file)
index d9f7145..0000000
+++ /dev/null
@@ -1,6496 +0,0 @@
- 0 files changed
-
-Index: linux-2.6.0-test5/drivers/dump/Makefile
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/Makefile       2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/Makefile    2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,14 @@
-+#
-+# Makefile for the dump device drivers.
-+#
-+
-+dump-y                                        := dump_setup.o dump_fmt.o dump_filters.o dump_scheme.o dump_execute.o
-+dump-$(CONFIG_X86)                    += dump_i386.o
-+dump-$(CONFIG_CRASH_DUMP_MEMDEV)      += dump_memdev.o dump_overlay.o
-+dump-objs                             += $(dump-y)
-+
-+obj-$(CONFIG_CRASH_DUMP)              += dump.o
-+obj-$(CONFIG_CRASH_DUMP_BLOCKDEV)     += dump_blockdev.o
-+obj-$(CONFIG_CRASH_DUMP_NETDEV)       += dump_netdev.o
-+obj-$(CONFIG_CRASH_DUMP_COMPRESS_RLE) += dump_rle.o
-+obj-$(CONFIG_CRASH_DUMP_COMPRESS_GZIP)        += dump_gzip.o
-Index: linux-2.6.0-test5/drivers/dump/dump_blockdev.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_blockdev.c        2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_blockdev.c     2003-09-26 14:29:10.000000000 +0800
-@@ -0,0 +1,461 @@
-+/*
-+ * Implements the dump driver interface for saving a dump to 
-+ * a block device through the kernel's generic low level block i/o
-+ * routines.
-+ *
-+ * Started: June 2002 - Mohamed Abbas <mohamed.abbas@intel.com>
-+ *    Moved original lkcd kiobuf dump i/o code from dump_base.c
-+ *    to use generic dump device interfaces
-+ *
-+ * Sept 2002 - Bharata B. Rao <bharata@in.ibm.com>
-+ *    Convert dump i/o to directly use bio instead of kiobuf for 2.5
-+ *
-+ * Oct 2002  - Suparna Bhattacharya <suparna@in.ibm.com>
-+ *    Rework to new dumpdev.h structures, implement open/close/
-+ *    silence, misc fixes (blocknr removal, bio_add_page usage)  
-+ *
-+ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
-+ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
-+ * Copyright (C) 2002 International Business Machines Corp. 
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/proc_fs.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/blkdev.h>
-+#include <linux/bio.h>
-+#include <asm/hardirq.h>
-+#include <linux/dump.h>
-+#include "dump_methods.h"
-+
-+extern void *dump_page_buf;
-+
-+/* The end_io callback for dump i/o completion */
-+static int
-+dump_bio_end_io(struct bio *bio, unsigned int bytes_done, int error)
-+{
-+      struct dump_blockdev *dump_bdev;
-+
-+      if (bio->bi_size) {
-+              /* some bytes still left to transfer */
-+              return 1; /* not complete */
-+      }
-+
-+      dump_bdev = (struct dump_blockdev *)bio->bi_private;
-+      if (error) {
-+              printk("IO error while writing the dump, aborting\n");
-+      }
-+
-+      dump_bdev->err = error;
-+
-+      /* no wakeup needed, since caller polls for completion */
-+      return 0;
-+}
-+
-+/* Check if the dump bio is already mapped to the specified buffer */
-+static int
-+dump_block_map_valid(struct dump_blockdev *dev, struct page *page, 
-+      int len) 
-+{
-+      struct bio *bio = dev->bio;
-+      unsigned long bsize = 0;
-+
-+      if (!bio->bi_vcnt)
-+              return 0; /* first time, not mapped */
-+
-+
-+      if ((bio_page(bio) != page) || (len > bio->bi_vcnt << PAGE_SHIFT))
-+              return 0; /* buffer not mapped */
-+
-+      bsize = bdev_hardsect_size(bio->bi_bdev);
-+      if ((len & (PAGE_SIZE - 1)) || (len & bsize))
-+              return 0; /* alignment checks needed */
-+
-+      /* quick check to decide if we need to redo bio_add_page */
-+      if (bdev_get_queue(bio->bi_bdev)->merge_bvec_fn)
-+              return 0; /* device may have other restrictions */
-+
-+      return 1; /* already mapped */
-+}
-+
-+/* 
-+ * Set up the dump bio for i/o from the specified buffer 
-+ * Return value indicates whether the full buffer could be mapped or not
-+ */
-+static int
-+dump_block_map(struct dump_blockdev *dev, void *buf, int len)
-+{
-+      struct page *page = virt_to_page(buf);
-+      struct bio *bio = dev->bio;
-+      unsigned long bsize = 0;
-+
-+      bio->bi_bdev = dev->bdev;
-+      bio->bi_sector = (dev->start_offset + dev->ddev.curr_offset) >> 9;
-+      bio->bi_idx = 0; /* reset index to the beginning */
-+
-+      if (dump_block_map_valid(dev, page, len)) {
-+              /* already mapped and usable rightaway */
-+              bio->bi_size = len; /* reset size to the whole bio */
-+      } else {
-+              /* need to map the bio */
-+              bio->bi_size = 0;
-+              bio->bi_vcnt = 0;
-+              bsize = bdev_hardsect_size(bio->bi_bdev);
-+
-+              /* first a few sanity checks */
-+              if (len < bsize) {
-+                      printk("map: len less than hardsect size \n");
-+                      return -EINVAL;
-+              }
-+
-+              if ((unsigned long)buf & bsize) {
-+                      printk("map: not aligned \n");
-+                      return -EINVAL;
-+              }
-+
-+              /* assume contig. page aligned low mem buffer( no vmalloc) */
-+              if ((page_address(page) != buf) || (len & (PAGE_SIZE - 1))) {
-+                      printk("map: invalid buffer alignment!\n");
-+                      return -EINVAL; 
-+              }
-+              /* finally we can go ahead and map it */
-+              while (bio->bi_size < len)
-+                      if (bio_add_page(bio, page++, PAGE_SIZE, 0) == 0) {
-+                              break;
-+                      }
-+
-+              bio->bi_end_io = dump_bio_end_io;
-+              bio->bi_private = dev;
-+      }
-+
-+      if (bio->bi_size != len) {
-+              printk("map: bio size = %d not enough for len = %d!\n",
-+                      bio->bi_size, len);
-+              return -E2BIG;
-+      }
-+      return 0;
-+}
-+
-+static void
-+dump_free_bio(struct bio *bio)
-+{
-+      if (bio)
-+              kfree(bio->bi_io_vec);
-+      kfree(bio);
-+}
-+
-+/*
-+ * Prepares the dump device so we can take a dump later. 
-+ * The caller is expected to have filled up the kdev_id field in the 
-+ * block dump dev structure.
-+ *
-+ * At dump time when dump_block_write() is invoked it will be too 
-+ * late to recover, so as far as possible make sure obvious errors 
-+ * get caught right here and reported back to the caller.
-+ */
-+static int
-+dump_block_open(struct dump_dev *dev, unsigned long arg)
-+{
-+      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
-+      struct block_device *bdev;
-+      int retval = 0;
-+      struct bio_vec *bvec;
-+
-+      /* make sure this is a valid block device */
-+      if (!arg) {
-+              retval = -EINVAL;
-+              goto err;
-+      }
-+
-+      /* get a corresponding block_dev struct for this */
-+      bdev = bdget((dev_t)arg);
-+      if (!bdev) {
-+              retval = -ENODEV;
-+              goto err;
-+      }
-+
-+      /* get the block device opened */
-+      if ((retval = blkdev_get(bdev, O_RDWR | O_LARGEFILE, 0, BDEV_RAW))) {
-+              goto err1;
-+      }
-+
-+      if ((dump_bdev->bio = kmalloc(sizeof(struct bio), GFP_KERNEL)) 
-+              == NULL) {
-+              printk("Cannot allocate bio\n");
-+              retval = -ENOMEM;
-+              goto err2;
-+      }
-+
-+      bio_init(dump_bdev->bio);
-+
-+      if ((bvec = kmalloc(sizeof(struct bio_vec) * 
-+              (DUMP_BUFFER_SIZE >> PAGE_SHIFT), GFP_KERNEL)) == NULL) {
-+              retval = -ENOMEM;
-+              goto err3;
-+      }
-+
-+      /* assign the new dump dev structure */
-+      dump_bdev->kdev_id = new_decode_dev((dev_t)arg);
-+      dump_bdev->bdev = bdev;
-+
-+      /* make a note of the limit */
-+      dump_bdev->limit = bdev->bd_inode->i_size;
-+      
-+      /* now make sure we can map the dump buffer */
-+      dump_bdev->bio->bi_io_vec = bvec;
-+      dump_bdev->bio->bi_max_vecs = DUMP_BUFFER_SIZE >> PAGE_SHIFT;
-+
-+      retval = dump_block_map(dump_bdev, dump_config.dumper->dump_buf, 
-+              DUMP_BUFFER_SIZE);
-+              
-+      if (retval) {
-+              printk("open: dump_block_map failed, ret %d\n", retval);
-+              goto err3;
-+      }
-+
-+      printk("Block device (%d,%d) successfully configured for dumping\n",
-+             MAJOR(dump_bdev->kdev_id),
-+             MINOR(dump_bdev->kdev_id));
-+
-+
-+      /* after opening the block device, return */
-+      return retval;
-+
-+err3: dump_free_bio(dump_bdev->bio);
-+      dump_bdev->bio = NULL;
-+err2: if (bdev) blkdev_put(bdev, BDEV_RAW);
-+              goto err;
-+err1: if (bdev) bdput(bdev);
-+      dump_bdev->bdev = NULL;
-+err:  return retval;
-+}
-+
-+/*
-+ * Close the dump device and release associated resources
-+ * Invoked when unconfiguring the dump device.
-+ */
-+static int
-+dump_block_release(struct dump_dev *dev)
-+{
-+      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
-+
-+      /* release earlier bdev if present */
-+      if (dump_bdev->bdev) {
-+              blkdev_put(dump_bdev->bdev, BDEV_RAW);
-+              dump_bdev->bdev = NULL;
-+      }
-+
-+      dump_free_bio(dump_bdev->bio);
-+      dump_bdev->bio = NULL;
-+
-+      return 0;
-+}
-+
-+
-+/*
-+ * Prepare the dump device for use (silence any ongoing activity
-+ * and quiesce state) when the system crashes.
-+ */
-+static int
-+dump_block_silence(struct dump_dev *dev)
-+{
-+      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
-+      struct request_queue *q = bdev_get_queue(dump_bdev->bdev);
-+      int ret;
-+
-+      /* If we can't get request queue lock, refuse to take the dump */
-+      if (!spin_trylock(q->queue_lock))
-+              return -EBUSY;
-+
-+      ret = elv_queue_empty(q);
-+      spin_unlock(q->queue_lock);
-+
-+      /* For now we assume we have the device to ourselves */
-+      /* Just a quick sanity check */
-+      if (!ret) {
-+              /* i/o in flight - safer to quit */
-+              return -EBUSY;
-+      }
-+
-+      /* 
-+       * Move to a softer level of silencing where no spin_lock_irqs 
-+       * are held on other cpus
-+       */
-+      dump_silence_level = DUMP_SOFT_SPIN_CPUS;       
-+
-+      __dump_irq_enable();
-+
-+      printk("Dumping to block device (%d,%d) on CPU %d ...\n",
-+             MAJOR(dump_bdev->kdev_id), MINOR(dump_bdev->kdev_id),
-+             smp_processor_id());
-+      
-+      return 0;
-+}
-+
-+/*
-+ * Invoked when dumping is done. This is the time to put things back 
-+ * (i.e. undo the effects of dump_block_silence) so the device is 
-+ * available for normal use.
-+ */
-+static int
-+dump_block_resume(struct dump_dev *dev)
-+{
-+      __dump_irq_restore();
-+      return 0;
-+}
-+
-+
-+/*
-+ * Seek to the specified offset in the dump device.
-+ * Makes sure this is a valid offset, otherwise returns an error.
-+ */
-+static int
-+dump_block_seek(struct dump_dev *dev, loff_t off)
-+{
-+      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
-+      loff_t offset = off + dump_bdev->start_offset;
-+      
-+      if (offset & ( PAGE_SIZE - 1)) {
-+              printk("seek: non-page aligned\n");
-+              return -EINVAL;
-+      }
-+
-+      if (offset & (bdev_hardsect_size(dump_bdev->bdev) - 1)) {
-+              printk("seek: not sector aligned \n");
-+              return -EINVAL;
-+      }
-+
-+      if (offset > dump_bdev->limit) {
-+              printk("seek: not enough space left on device!\n");
-+              return -ENOSPC; 
-+      }
-+      dev->curr_offset = off;
-+      return 0;
-+}
-+
-+/*
-+ * Write out a buffer after checking the device limitations, 
-+ * sector sizes, etc. Assumes the buffer is in directly mapped 
-+ * kernel address space (not vmalloc'ed).
-+ *
-+ * Returns: number of bytes written or -ERRNO. 
-+ */
-+static int
-+dump_block_write(struct dump_dev *dev, void *buf, 
-+      unsigned long len)
-+{
-+      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
-+      loff_t offset = dev->curr_offset + dump_bdev->start_offset;
-+      int retval = -ENOSPC;
-+
-+      if (offset >= dump_bdev->limit) {
-+              printk("write: not enough space left on device!\n");
-+              goto out;
-+      }
-+
-+      /* don't write more blocks than our max limit */
-+      if (offset + len > dump_bdev->limit) 
-+              len = dump_bdev->limit - offset;
-+
-+
-+      retval = dump_block_map(dump_bdev, buf, len);
-+      if (retval){
-+              printk("write: dump_block_map failed! err %d\n", retval);
-+              goto out;
-+      }
-+
-+      /*
-+       * Write out the data to disk.
-+       * Assumes the entire buffer mapped to a single bio, which we can
-+       * submit and wait for io completion. In the future, may consider
-+       * increasing the dump buffer size and submitting multiple bio s 
-+       * for better throughput.
-+       */
-+      dump_bdev->err = -EAGAIN;
-+      submit_bio(WRITE, dump_bdev->bio);
-+
-+      dump_bdev->ddev.curr_offset += len;
-+      retval = len;
-+ out:
-+      return retval;
-+}
-+
-+/*
-+ * Name: dump_block_ready()
-+ * Func: check if the last dump i/o is over and ready for next request
-+ */
-+static int
-+dump_block_ready(struct dump_dev *dev, void *buf)
-+{
-+      struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
-+      request_queue_t *q = bdev_get_queue(dump_bdev->bio->bi_bdev);
-+
-+      /* check for io completion */
-+      if (dump_bdev->err == -EAGAIN) {
-+              q->unplug_fn(q);
-+              return -EAGAIN;
-+      }
-+
-+      if (dump_bdev->err) {
-+              printk("dump i/o err\n");
-+              return dump_bdev->err;
-+      }
-+
-+      return 0;
-+}
-+
-+
-+struct dump_dev_ops dump_blockdev_ops = {
-+      .open           = dump_block_open,
-+      .release        = dump_block_release,
-+      .silence        = dump_block_silence,
-+      .resume         = dump_block_resume,
-+      .seek           = dump_block_seek,
-+      .write          = dump_block_write,
-+      /* .read not implemented */
-+      .ready          = dump_block_ready
-+};
-+
-+static struct dump_blockdev default_dump_blockdev = {
-+      .ddev = {.type_name = "blockdev", .ops = &dump_blockdev_ops, 
-+                      .curr_offset = 0},
-+      /* 
-+       * leave enough room for the longest swap header possibly written 
-+       * written by mkswap (likely the largest page size supported by
-+       * the arch
-+       */
-+      .start_offset   = DUMP_HEADER_OFFSET,
-+      .err            = 0
-+      /* assume the rest of the fields are zeroed by default */
-+};    
-+      
-+struct dump_blockdev *dump_blockdev = &default_dump_blockdev;
-+
-+static int __init
-+dump_blockdev_init(void)
-+{
-+      if (dump_register_device(&dump_blockdev->ddev) < 0) {
-+              printk("block device driver registration failed\n");
-+              return -1;
-+      }
-+              
-+      printk("block device driver for LKCD registered\n");
-+      return 0;
-+}
-+
-+static void __exit
-+dump_blockdev_cleanup(void)
-+{
-+      dump_unregister_device(&dump_blockdev->ddev);
-+      printk("block device driver for LKCD unregistered\n");
-+}
-+
-+MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
-+MODULE_DESCRIPTION("Block Dump Driver for Linux Kernel Crash Dump (LKCD)");
-+MODULE_LICENSE("GPL");
-+
-+module_init(dump_blockdev_init);
-+module_exit(dump_blockdev_cleanup);
-Index: linux-2.6.0-test5/drivers/dump/dump_execute.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_execute.c 2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_execute.c      2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,126 @@
-+/*
-+ * The file has the common/generic dump execution code 
-+ *
-+ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
-+ *    Split and rewrote high level dump execute code to make use 
-+ *    of dump method interfaces.
-+ *
-+ * Derived from original code in dump_base.c created by 
-+ *    Matt Robinson <yakker@sourceforge.net>)
-+ *    
-+ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
-+ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
-+ * Copyright (C) 2002 International Business Machines Corp. 
-+ *
-+ * Assumes dumper and dump config settings are in place
-+ * (invokes corresponding dumper specific routines as applicable)
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+#include <linux/kernel.h>
-+#include <linux/notifier.h>
-+#include <linux/dump.h>
-+#include "dump_methods.h"
-+
-+struct notifier_block *dump_notifier_list; /* dump started/ended callback */
-+
-+/* Dump progress indicator */
-+void 
-+dump_speedo(int i)
-+{
-+      static const char twiddle[4] =  { '|', '\\', '-', '/' };
-+      printk("%c\b", twiddle[i&3]);
-+}
-+
-+/* Make the device ready and write out the header */
-+int dump_begin(void)
-+{
-+      int err = 0;
-+
-+      /* dump_dev = dump_config.dumper->dev; */
-+      dumper_reset();
-+      if ((err = dump_dev_silence())) {
-+              /* quiesce failed, can't risk continuing */
-+              /* Todo/Future: switch to alternate dump scheme if possible */
-+              printk("dump silence dev failed ! error %d\n", err);
-+              return err;
-+      }
-+
-+      pr_debug("Writing dump header\n");
-+      if ((err = dump_update_header())) {
-+              printk("dump update header failed ! error %d\n", err);
-+              dump_dev_resume();
-+              return err;
-+      }
-+
-+      dump_config.dumper->curr_offset = DUMP_BUFFER_SIZE;
-+
-+      return 0;
-+}
-+
-+/* 
-+ * Write the dump terminator, a final header update and let go of 
-+ * exclusive use of the device for dump.
-+ */
-+int dump_complete(void)
-+{
-+      int ret = 0;
-+
-+      if (dump_config.level != DUMP_LEVEL_HEADER) {
-+              if ((ret = dump_update_end_marker())) {
-+                      printk("dump update end marker error %d\n", ret);
-+              }
-+              if ((ret = dump_update_header())) {
-+                      printk("dump update header error %d\n", ret);
-+              }
-+      }
-+      ret = dump_dev_resume();
-+
-+      return ret;
-+}
-+
-+/* Saves all dump data */
-+int dump_execute_savedump(void)
-+{
-+      int ret = 0, err = 0;
-+
-+      if ((ret = dump_begin()))  {
-+              return ret;
-+      }
-+
-+      if (dump_config.level != DUMP_LEVEL_HEADER) { 
-+              ret = dump_sequencer();
-+      }
-+      if ((err = dump_complete())) {
-+              printk("Dump complete failed. Error %d\n", err);
-+      }
-+
-+      return ret;
-+}
-+
-+/* Does all the real work:  Capture and save state */
-+int dump_generic_execute(const char *panic_str, const struct pt_regs *regs)
-+{
-+      int ret = 0;
-+
-+      if ((ret = dump_configure_header(panic_str, regs))) {
-+              printk("dump config header failed ! error %d\n", ret);
-+              return ret;     
-+      }
-+
-+      /* tell interested parties that a dump is about to start */
-+      notifier_call_chain(&dump_notifier_list, DUMP_BEGIN, 
-+              &dump_config.dump_device);
-+
-+      if (dump_config.level != DUMP_LEVEL_NONE)
-+              ret = dump_execute_savedump();
-+
-+      pr_debug("dumped %ld blocks of %d bytes each\n", 
-+              dump_config.dumper->count, DUMP_BUFFER_SIZE);
-+      
-+      /* tell interested parties that a dump has completed */
-+      notifier_call_chain(&dump_notifier_list, DUMP_END, 
-+              &dump_config.dump_device);
-+
-+      return ret;
-+}
-Index: linux-2.6.0-test5/drivers/dump/dump_filters.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_filters.c 2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_filters.c      2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,143 @@
-+/*
-+ * Default filters to select data to dump for various passes.
-+ *
-+ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
-+ *    Split and rewrote default dump selection logic to generic dump 
-+ *    method interfaces 
-+ * Derived from a portion of dump_base.c created by 
-+ *    Matt Robinson <yakker@sourceforge.net>)
-+ *
-+ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
-+ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
-+ * Copyright (C) 2002 International Business Machines Corp. 
-+ *
-+ * Used during single-stage dumping and during stage 1 of the 2-stage scheme
-+ * (Stage 2 of the 2-stage scheme uses the fully transparent filters
-+ * i.e. passthru filters in dump_overlay.c)
-+ *
-+ * Future: Custom selective dump may involve a different set of filters.
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/bootmem.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/dump.h>
-+#include "dump_methods.h"
-+
-+
-+/* Copied from mm/bootmem.c - FIXME */
-+/* return the number of _pages_ that will be allocated for the boot bitmap */
-+unsigned long dump_calc_bootmap_pages (void)
-+{
-+      unsigned long mapsize;
-+      unsigned long pages = num_physpages;
-+
-+      mapsize = (pages+7)/8;
-+      mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK;
-+      mapsize >>= PAGE_SHIFT;
-+
-+      return mapsize;
-+}
-+
-+
-+#define DUMP_PFN_SAFETY_MARGIN        1024  /* 4 MB */
-+/* temporary */
-+extern unsigned long min_low_pfn;
-+
-+
-+int dump_low_page(struct page *p)
-+{
-+      return page_to_pfn(p) < min_low_pfn + dump_calc_bootmap_pages() 
-+                      + 1 + DUMP_PFN_SAFETY_MARGIN;
-+}
-+
-+static inline int kernel_page(struct page *p)
-+{
-+      /* FIXME: Need to exclude hugetlb pages. Clue: reserved but inuse */
-+      return PageReserved(p) || (!PageLRU(p) && PageInuse(p));
-+}
-+
-+static inline int user_page(struct page *p)
-+{
-+      return PageInuse(p) && (!PageReserved(p) && PageLRU(p));
-+}
-+
-+static inline int unreferenced_page(struct page *p)
-+{
-+      return !PageInuse(p) && !PageReserved(p);
-+}
-+
-+
-+/* loc marks the beginning of a range of pages */
-+int dump_filter_kernpages(int pass, unsigned long loc, unsigned long sz)
-+{
-+      struct page *page = (struct page *)loc;
-+      /* if any of the pages is a kernel page, select this set */     
-+      while (sz) {
-+              if (dump_low_page(page) || kernel_page(page))
-+                      return 1;
-+              sz -= PAGE_SIZE;
-+              page++;
-+      }       
-+      return 0;
-+}
-+
-+
-+/* loc marks the beginning of a range of pages */
-+int dump_filter_userpages(int pass, unsigned long loc, unsigned long sz)
-+{
-+      struct page *page = (struct page *)loc;
-+      int ret = 0;
-+      /* select if the set has any user page, and no kernel pages  */ 
-+      while (sz) {
-+              if (user_page(page) && !dump_low_page(page)) {
-+                      ret = 1;
-+              } else if (kernel_page(page) || dump_low_page(page)) {
-+                      return 0;
-+              }
-+              page++;
-+              sz -= PAGE_SIZE;
-+      }       
-+      return ret;
-+}
-+
-+
-+
-+/* loc marks the beginning of a range of pages */
-+int dump_filter_unusedpages(int pass, unsigned long loc, unsigned long sz)
-+{
-+      struct page *page = (struct page *)loc;
-+
-+      /* select if the set does not have any used pages  */   
-+      while (sz) {
-+              if (!unreferenced_page(page) || dump_low_page(page)) {
-+                      return 0;
-+              }
-+              page++;
-+              sz -= PAGE_SIZE;
-+      }       
-+      return 1;
-+}
-+
-+/* dummy: last (non-existent) pass */
-+int dump_filter_none(int pass, unsigned long loc, unsigned long sz)
-+{
-+      return 0;
-+}
-+
-+/* TBD: resolve level bitmask ? */
-+struct dump_data_filter dump_filter_table[] = {
-+      { .name = "kern", .selector = dump_filter_kernpages, 
-+              .level_mask = DUMP_MASK_KERN},
-+      { .name = "user", .selector = dump_filter_userpages, 
-+              .level_mask = DUMP_MASK_USED},
-+      { .name = "unused", .selector = dump_filter_unusedpages, 
-+              .level_mask = DUMP_MASK_UNUSED},
-+      { .name = "none", .selector = dump_filter_none, 
-+              .level_mask = DUMP_MASK_REST},
-+      { .name = "", .selector = NULL, .level_mask = 0}
-+};
-+
-Index: linux-2.6.0-test5/drivers/dump/dump_fmt.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_fmt.c     2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_fmt.c  2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,399 @@
-+/*
-+ * Implements the routines which handle the format specific
-+ * aspects of dump for the default dump format.
-+ *
-+ * Used in single stage dumping and stage 1 of soft-boot based dumping 
-+ * Saves data in LKCD (lcrash) format 
-+ *
-+ * Previously a part of dump_base.c
-+ *
-+ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
-+ *    Split off and reshuffled LKCD dump format code around generic
-+ *    dump method interfaces.
-+ *
-+ * Derived from original code created by 
-+ *    Matt Robinson <yakker@sourceforge.net>)
-+ *
-+ * Contributions from SGI, IBM, HP, MCL, and others.
-+ *
-+ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
-+ * Copyright (C) 2000 - 2002 TurboLinux, Inc.  All rights reserved.
-+ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
-+ * Copyright (C) 2002 International Business Machines Corp. 
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/time.h>
-+#include <linux/sched.h>
-+#include <linux/ptrace.h>
-+#include <linux/utsname.h>
-+#include <asm/dump.h>
-+#include <linux/dump.h>
-+#include "dump_methods.h"
-+
-+/*
-+ * SYSTEM DUMP LAYOUT
-+ * 
-+ * System dumps are currently the combination of a dump header and a set
-+ * of data pages which contain the system memory.  The layout of the dump
-+ * (for full dumps) is as follows:
-+ *
-+ *             +-----------------------------+
-+ *             |     generic dump header     |
-+ *             +-----------------------------+
-+ *             |   architecture dump header  |
-+ *             +-----------------------------+
-+ *             |         page header         |
-+ *             +-----------------------------+
-+ *             |          page data          |
-+ *             +-----------------------------+
-+ *             |         page header         |
-+ *             +-----------------------------+
-+ *             |          page data          |
-+ *             +-----------------------------+
-+ *             |              |              |
-+ *             |              |              |
-+ *             |              |              |
-+ *             |              |              |
-+ *             |              V              |
-+ *             +-----------------------------+
-+ *             |        PAGE_END header      |
-+ *             +-----------------------------+
-+ *
-+ * There are two dump headers, the first which is architecture
-+ * independent, and the other which is architecture dependent.  This
-+ * allows different architectures to dump different data structures
-+ * which are specific to their chipset, CPU, etc.
-+ *
-+ * After the dump headers come a succession of dump page headers along
-+ * with dump pages.  The page header contains information about the page
-+ * size, any flags associated with the page (whether it's compressed or
-+ * not), and the address of the page.  After the page header is the page
-+ * data, which is either compressed (or not).  Each page of data is
-+ * dumped in succession, until the final dump header (PAGE_END) is
-+ * placed at the end of the dump, assuming the dump device isn't out
-+ * of space.
-+ *
-+ * This mechanism allows for multiple compression types, different
-+ * types of data structures, different page ordering, etc., etc., etc.
-+ * It's a very straightforward mechanism for dumping system memory.
-+ */
-+
-+struct __dump_header dump_header;  /* the primary dump header              */
-+struct __dump_header_asm dump_header_asm; /* the arch-specific dump header */
-+
-+/*
-+ *  Set up common header fields (mainly the arch indep section) 
-+ *  Per-cpu state is handled by lcrash_save_context
-+ *  Returns the size of the header in bytes.
-+ */
-+static int lcrash_init_dump_header(const char *panic_str)
-+{
-+      struct timeval dh_time;
-+      struct sysinfo info;
-+
-+      /* make sure the dump header isn't TOO big */
-+      if ((sizeof(struct __dump_header) +
-+              sizeof(struct __dump_header_asm)) > DUMP_BUFFER_SIZE) {
-+                      printk("lcrash_init_header(): combined "
-+                              "headers larger than DUMP_BUFFER_SIZE!\n");
-+                      return -E2BIG;
-+      }
-+
-+      /* initialize the dump headers to zero */
-+      memset(&dump_header, 0, sizeof(dump_header));
-+      memset(&dump_header_asm, 0, sizeof(dump_header_asm));
-+
-+      /* configure dump header values */
-+      dump_header.dh_magic_number = DUMP_MAGIC_NUMBER;
-+      dump_header.dh_version = DUMP_VERSION_NUMBER;
-+      dump_header.dh_memory_start = PAGE_OFFSET;
-+      dump_header.dh_memory_end = DUMP_MAGIC_NUMBER;
-+      dump_header.dh_header_size = sizeof(struct __dump_header);
-+      si_meminfo(&info);
-+      dump_header.dh_memory_size = (u64)info.totalram;
-+      dump_header.dh_page_size = PAGE_SIZE;
-+      dump_header.dh_dump_level = dump_config.level;
-+      dump_header.dh_current_task = (unsigned long) current;
-+      dump_header.dh_dump_compress = dump_config.dumper->compress->
-+              compress_type;
-+      dump_header.dh_dump_flags = dump_config.flags;
-+      dump_header.dh_dump_device = dump_config.dumper->dev->device_id; 
-+      
-+#if DUMP_DEBUG >= 6
-+      dump_header.dh_num_bytes = 0;
-+#endif
-+      dump_header.dh_num_dump_pages = 0;
-+      do_gettimeofday(&dh_time);
-+      dump_header.dh_time.tv_sec = dh_time.tv_sec;
-+      dump_header.dh_time.tv_usec = dh_time.tv_usec;
-+
-+      memcpy((void *)&(dump_header.dh_utsname_sysname), 
-+              (const void *)&(system_utsname.sysname), __NEW_UTS_LEN + 1);
-+      memcpy((void *)&(dump_header.dh_utsname_nodename), 
-+              (const void *)&(system_utsname.nodename), __NEW_UTS_LEN + 1);
-+      memcpy((void *)&(dump_header.dh_utsname_release), 
-+              (const void *)&(system_utsname.release), __NEW_UTS_LEN + 1);
-+      memcpy((void *)&(dump_header.dh_utsname_version), 
-+              (const void *)&(system_utsname.version), __NEW_UTS_LEN + 1);
-+      memcpy((void *)&(dump_header.dh_utsname_machine), 
-+              (const void *)&(system_utsname.machine), __NEW_UTS_LEN + 1);
-+      memcpy((void *)&(dump_header.dh_utsname_domainname), 
-+              (const void *)&(system_utsname.domainname), __NEW_UTS_LEN + 1);
-+
-+      if (panic_str) {
-+              memcpy((void *)&(dump_header.dh_panic_string),
-+                      (const void *)panic_str, DUMP_PANIC_LEN);
-+      }
-+
-+        dump_header_asm.dha_magic_number = DUMP_ASM_MAGIC_NUMBER;
-+        dump_header_asm.dha_version = DUMP_ASM_VERSION_NUMBER;
-+        dump_header_asm.dha_header_size = sizeof(dump_header_asm);
-+
-+      dump_header_asm.dha_smp_num_cpus = num_online_cpus();
-+      pr_debug("smp_num_cpus in header %d\n", 
-+              dump_header_asm.dha_smp_num_cpus);
-+
-+      dump_header_asm.dha_dumping_cpu = smp_processor_id();
-+      
-+      return sizeof(dump_header) + sizeof(dump_header_asm);
-+}
-+
-+
-+int dump_lcrash_configure_header(const char *panic_str, 
-+      const struct pt_regs *regs)
-+{
-+      int retval = 0;
-+
-+      dump_config.dumper->header_len = lcrash_init_dump_header(panic_str);
-+
-+      /* capture register states for all processors */
-+      dump_save_this_cpu(regs);
-+      __dump_save_other_cpus(); /* side effect:silence cpus */
-+
-+      /* configure architecture-specific dump header values */
-+      if ((retval = __dump_configure_header(regs))) 
-+              return retval;
-+
-+      dump_config.dumper->header_dirty++;
-+      return 0;
-+}
-+
-+/* save register and task context */
-+void dump_lcrash_save_context(int cpu, const struct pt_regs *regs, 
-+      struct task_struct *tsk)
-+{
-+      dump_header_asm.dha_smp_current_task[cpu] = (uint32_t) tsk;
-+
-+      __dump_save_regs(&dump_header_asm.dha_smp_regs[cpu], regs);
-+
-+      /* take a snapshot of the stack */
-+      /* doing this enables us to tolerate slight drifts on this cpu */
-+      if (dump_header_asm.dha_stack[cpu]) {
-+              memcpy((void *)dump_header_asm.dha_stack[cpu],
-+                              tsk->thread_info, THREAD_SIZE);
-+      }
-+      dump_header_asm.dha_stack_ptr[cpu] = (uint32_t)(tsk->thread_info);
-+}
-+
-+/* write out the header */
-+int dump_write_header(void)
-+{
-+      int retval = 0, size;
-+      void *buf = dump_config.dumper->dump_buf;
-+
-+      /* accounts for DUMP_HEADER_OFFSET if applicable */
-+      if ((retval = dump_dev_seek(0))) {
-+              printk("Unable to seek to dump header offset: %d\n", 
-+                      retval);
-+              return retval;
-+      }
-+
-+      memcpy(buf, (void *)&dump_header, sizeof(dump_header));
-+      size = sizeof(dump_header);
-+      memcpy(buf + size, (void *)&dump_header_asm, sizeof(dump_header_asm));
-+      size += sizeof(dump_header_asm);
-+      size = PAGE_ALIGN(size);
-+      retval = dump_ll_write(buf , size);
-+
-+      if (retval < size) 
-+              return (retval >= 0) ? ENOSPC : retval;
-+
-+      return 0;
-+}
-+
-+int dump_generic_update_header(void)
-+{
-+      int err = 0;
-+
-+      if (dump_config.dumper->header_dirty) {
-+              if ((err = dump_write_header())) {
-+                      printk("dump write header failed !err %d\n", err);
-+              } else {
-+                      dump_config.dumper->header_dirty = 0;
-+              }
-+      }
-+
-+      return err;
-+}
-+
-+static inline int is_curr_stack_page(struct page *page, unsigned long size)
-+{
-+      unsigned long thread_addr = (unsigned long)current_thread_info();
-+      unsigned long addr = (unsigned long)page_address(page);
-+
-+      return !PageHighMem(page) && (addr < thread_addr + THREAD_SIZE)
-+              && (addr + size > thread_addr);
-+}
-+
-+static inline int is_dump_page(struct page *page, unsigned long size)
-+{
-+      unsigned long addr = (unsigned long)page_address(page);
-+      unsigned long dump_buf = (unsigned long)dump_config.dumper->dump_buf;
-+
-+      return !PageHighMem(page) && (addr < dump_buf + DUMP_BUFFER_SIZE)
-+              && (addr + size > dump_buf);
-+}
-+
-+int dump_allow_compress(struct page *page, unsigned long size)
-+{
-+      /*
-+       * Don't compress the page if any part of it overlaps
-+       * with the current stack or dump buffer (since the contents
-+       * in these could be changing while compression is going on)
-+       */
-+      return !is_curr_stack_page(page, size) && !is_dump_page(page, size);
-+}
-+
-+void lcrash_init_pageheader(struct __dump_page *dp, struct page *page, 
-+      unsigned long sz)
-+{
-+      memset(dp, sizeof(struct __dump_page), 0);
-+      dp->dp_flags = 0; 
-+      dp->dp_size = 0;
-+      if (sz > 0)
-+              dp->dp_address = page_to_pfn(page) << PAGE_SHIFT;
-+
-+#if DUMP_DEBUG > 6
-+      dp->dp_page_index = dump_header.dh_num_dump_pages;
-+      dp->dp_byte_offset = dump_header.dh_num_bytes + DUMP_BUFFER_SIZE
-+              + DUMP_HEADER_OFFSET; /* ?? */
-+#endif /* DUMP_DEBUG */
-+}
-+
-+int dump_lcrash_add_data(unsigned long loc, unsigned long len)
-+{
-+      struct page *page = (struct page *)loc;
-+      void *addr, *buf = dump_config.dumper->curr_buf;
-+      struct __dump_page *dp = (struct __dump_page *)buf; 
-+      int bytes, size;
-+
-+      if (buf > dump_config.dumper->dump_buf + DUMP_BUFFER_SIZE)
-+              return -ENOMEM;
-+
-+      lcrash_init_pageheader(dp, page, len);
-+      buf += sizeof(struct __dump_page);
-+
-+      while (len) {
-+              addr = kmap_atomic(page, KM_DUMP);
-+              size = bytes = (len > PAGE_SIZE) ? PAGE_SIZE : len;     
-+              /* check for compression */
-+              if (dump_allow_compress(page, bytes)) {
-+                      size = dump_compress_data((char *)addr, bytes, (char *)buf);
-+              }
-+              /* set the compressed flag if the page did compress */
-+              if (size && (size < bytes)) {
-+                      dp->dp_flags |= DUMP_DH_COMPRESSED;
-+              } else {
-+                      /* compression failed -- default to raw mode */
-+                      dp->dp_flags |= DUMP_DH_RAW;
-+                      memcpy(buf, addr, bytes);
-+                      size = bytes;
-+              }
-+              /* memset(buf, 'A', size); temporary: testing only !! */
-+              kunmap_atomic(addr, KM_DUMP);
-+              dp->dp_size += size;
-+              buf += size;
-+              len -= bytes;
-+              page++;
-+      }
-+
-+      /* now update the header */
-+#if DUMP_DEBUG > 6
-+      dump_header.dh_num_bytes += dp->dp_size + sizeof(*dp);
-+#endif
-+      dump_header.dh_num_dump_pages++;
-+      dump_config.dumper->header_dirty++;
-+
-+      dump_config.dumper->curr_buf = buf;     
-+
-+      return len;
-+}
-+
-+int dump_lcrash_update_end_marker(void)
-+{
-+      struct __dump_page *dp = 
-+              (struct __dump_page *)dump_config.dumper->curr_buf;
-+      unsigned long left;
-+      int ret = 0;
-+              
-+      lcrash_init_pageheader(dp, NULL, 0);
-+      dp->dp_flags |= DUMP_DH_END; /* tbd: truncation test ? */
-+      
-+      /* now update the header */
-+#if DUMP_DEBUG > 6
-+      dump_header.dh_num_bytes += sizeof(*dp);
-+#endif
-+      dump_config.dumper->curr_buf += sizeof(*dp);
-+      left = dump_config.dumper->curr_buf - dump_config.dumper->dump_buf;
-+
-+      printk("\n");
-+
-+      while (left) {
-+              if ((ret = dump_dev_seek(dump_config.dumper->curr_offset))) {
-+                      printk("Seek failed at offset 0x%llx\n", 
-+                      dump_config.dumper->curr_offset);
-+                      return ret;
-+              }
-+
-+              if (DUMP_BUFFER_SIZE > left) 
-+                      memset(dump_config.dumper->curr_buf, 'm', 
-+                              DUMP_BUFFER_SIZE - left);
-+
-+              if ((ret = dump_ll_write(dump_config.dumper->dump_buf, 
-+                      DUMP_BUFFER_SIZE)) < DUMP_BUFFER_SIZE) {
-+                      return (ret < 0) ? ret : -ENOSPC;
-+              }
-+
-+              dump_config.dumper->curr_offset += DUMP_BUFFER_SIZE;
-+      
-+              if (left > DUMP_BUFFER_SIZE) {
-+                      left -= DUMP_BUFFER_SIZE;
-+                      memcpy(dump_config.dumper->dump_buf, 
-+                      dump_config.dumper->dump_buf + DUMP_BUFFER_SIZE, left);
-+                      dump_config.dumper->curr_buf -= DUMP_BUFFER_SIZE;
-+              } else {
-+                      left = 0;
-+              }
-+      }
-+      return 0;
-+}
-+
-+
-+/* Default Formatter (lcrash) */
-+struct dump_fmt_ops dump_fmt_lcrash_ops = {
-+      .configure_header       = dump_lcrash_configure_header,
-+      .update_header          = dump_generic_update_header,
-+      .save_context           = dump_lcrash_save_context,
-+      .add_data               = dump_lcrash_add_data,
-+      .update_end_marker      = dump_lcrash_update_end_marker
-+};
-+
-+struct dump_fmt dump_fmt_lcrash = {
-+      .name   = "lcrash",
-+      .ops    = &dump_fmt_lcrash_ops
-+};
-+
-Index: linux-2.6.0-test5/drivers/dump/dump_gzip.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_gzip.c    2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_gzip.c 2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,118 @@
-+/*
-+ * GZIP Compression functions for kernel crash dumps.
-+ *
-+ * Created by: Matt Robinson (yakker@sourceforge.net)
-+ * Copyright 2001 Matt D. Robinson.  All rights reserved.
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+/* header files */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/file.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/dump.h>
-+#include <linux/zlib.h>
-+#include <linux/vmalloc.h>
-+
-+static void *deflate_workspace;
-+
-+/*
-+ * Name: dump_compress_gzip()
-+ * Func: Compress a DUMP_PAGE_SIZE page using gzip-style algorithms (the.
-+ *       deflate functions similar to what's used in PPP).
-+ */
-+static u16
-+dump_compress_gzip(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
-+{
-+      /* error code and dump stream */
-+      int err;
-+      z_stream dump_stream;
-+      
-+      dump_stream.workspace = deflate_workspace;
-+      
-+      if ((err = zlib_deflateInit(&dump_stream, Z_BEST_COMPRESSION)) != Z_OK) {
-+              /* fall back to RLE compression */
-+              printk("dump_compress_gzip(): zlib_deflateInit() "
-+                      "failed (%d)!\n", err);
-+              return 0;
-+      }
-+
-+      /* use old (page of memory) and size (DUMP_PAGE_SIZE) as in-streams */
-+      dump_stream.next_in = (u8 *) old;
-+      dump_stream.avail_in = oldsize;
-+
-+      /* out streams are new (dpcpage) and new size (DUMP_DPC_PAGE_SIZE) */
-+      dump_stream.next_out = new;
-+      dump_stream.avail_out = newsize;
-+
-+      /* deflate the page -- check for error */
-+      err = zlib_deflate(&dump_stream, Z_FINISH);
-+      if (err != Z_STREAM_END) {
-+              /* zero is return code here */
-+              (void)zlib_deflateEnd(&dump_stream);
-+              printk("dump_compress_gzip(): zlib_deflate() failed (%d)!\n",
-+                      err);
-+              return 0;
-+      }
-+
-+      /* let's end the deflated compression stream */
-+      if ((err = zlib_deflateEnd(&dump_stream)) != Z_OK) {
-+              printk("dump_compress_gzip(): zlib_deflateEnd() "
-+                      "failed (%d)!\n", err);
-+      }
-+
-+      /* return the compressed byte total (if it's smaller) */
-+      if (dump_stream.total_out >= oldsize) {
-+              return oldsize;
-+      }
-+      return dump_stream.total_out;
-+}
-+
-+/* setup the gzip compression functionality */
-+static struct __dump_compress dump_gzip_compression = {
-+      .compress_type = DUMP_COMPRESS_GZIP,
-+      .compress_func = dump_compress_gzip,
-+      .compress_name = "GZIP",
-+};
-+
-+/*
-+ * Name: dump_compress_gzip_init()
-+ * Func: Initialize gzip as a compression mechanism.
-+ */
-+static int __init
-+dump_compress_gzip_init(void)
-+{
-+      deflate_workspace = vmalloc(zlib_deflate_workspacesize());
-+      if (!deflate_workspace) {
-+              printk("dump_compress_gzip_init(): Failed to "
-+                      "alloc %d bytes for deflate workspace\n",
-+                      zlib_deflate_workspacesize());
-+              return -ENOMEM;
-+      }
-+      dump_register_compression(&dump_gzip_compression);
-+      return 0;
-+}
-+
-+/*
-+ * Name: dump_compress_gzip_cleanup()
-+ * Func: Remove gzip as a compression mechanism.
-+ */
-+static void __exit
-+dump_compress_gzip_cleanup(void)
-+{
-+      vfree(deflate_workspace);
-+      dump_unregister_compression(DUMP_COMPRESS_GZIP);
-+}
-+
-+/* module initialization */
-+module_init(dump_compress_gzip_init);
-+module_exit(dump_compress_gzip_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
-+MODULE_DESCRIPTION("Gzip compression module for crash dump driver");
-Index: linux-2.6.0-test5/drivers/dump/dump_i386.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_i386.c    2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_i386.c 2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,329 @@
-+/*
-+ * Architecture specific (i386) functions for Linux crash dumps.
-+ *
-+ * Created by: Matt Robinson (yakker@sgi.com)
-+ *
-+ * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
-+ *
-+ * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com)
-+ * Copyright 2000 TurboLinux, Inc.  All rights reserved.
-+ * 
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+/*
-+ * The hooks for dumping the kernel virtual memory to disk are in this
-+ * file.  Any time a modification is made to the virtual memory mechanism,
-+ * these routines must be changed to use the new mechanisms.
-+ */
-+#include <linux/init.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/smp.h>
-+#include <linux/fs.h>
-+#include <linux/vmalloc.h>
-+#include <linux/mm.h>
-+#include <linux/dump.h>
-+#include "dump_methods.h"
-+#include <linux/irq.h>
-+
-+#include <asm/processor.h>
-+#include <asm/e820.h>
-+#include <asm/hardirq.h>
-+#include <asm/nmi.h>
-+
-+static __s32       saved_irq_count;   /* saved preempt_count() flags */
-+
-+static int
-+alloc_dha_stack(void)
-+{
-+      int i;
-+      void *ptr;
-+      
-+      if (dump_header_asm.dha_stack[0])
-+              return 0;
-+
-+      ptr = vmalloc(THREAD_SIZE * num_online_cpus());
-+      if (!ptr) {
-+              printk("vmalloc for dha_stacks failed\n");
-+              return -ENOMEM;
-+      }
-+
-+      for (i = 0; i < num_online_cpus(); i++) {
-+              dump_header_asm.dha_stack[i] = (u32)((unsigned long)ptr +
-+                              (i * THREAD_SIZE));
-+      }
-+      return 0;
-+}
-+
-+static int
-+free_dha_stack(void) 
-+{
-+      if (dump_header_asm.dha_stack[0]) {
-+              vfree((void *)dump_header_asm.dha_stack[0]);    
-+              dump_header_asm.dha_stack[0] = 0;
-+      }
-+      return 0;
-+}
-+
-+
-+void 
-+__dump_save_regs(struct pt_regs *dest_regs, const struct pt_regs *regs)
-+{
-+      *dest_regs = *regs;
-+
-+      /* In case of panic dumps, we collects regs on entry to panic.
-+       * so, we shouldn't 'fix' ssesp here again. But it is hard to
-+       * tell just looking at regs whether ssesp need fixing. We make
-+       * this decision by looking at xss in regs. If we have better
-+       * means to determine that ssesp are valid (by some flag which
-+       * tells that we are here due to panic dump), then we can use
-+       * that instead of this kludge.
-+       */
-+      if (!user_mode(regs)) {
-+              if ((0xffff & regs->xss) == __KERNEL_DS) 
-+                      /* already fixed up */
-+                      return;
-+              dest_regs->esp = (unsigned long)&(regs->esp);
-+              __asm__ __volatile__ ("movw %%ss, %%ax;"
-+                      :"=a"(dest_regs->xss));
-+      }
-+}
-+
-+
-+#ifdef CONFIG_SMP
-+extern cpumask_t irq_affinity[];
-+extern irq_desc_t irq_desc[];
-+extern void dump_send_ipi(void);
-+
-+static int dump_expect_ipi[NR_CPUS];
-+static atomic_t waiting_for_dump_ipi;
-+static cpumask_t saved_affinity[NR_IRQS];
-+
-+extern void stop_this_cpu(void *); /* exported by i386 kernel */
-+
-+static int
-+dump_nmi_callback(struct pt_regs *regs, int cpu) 
-+{
-+      if (!dump_expect_ipi[cpu])
-+              return 0;
-+
-+      dump_expect_ipi[cpu] = 0;
-+      
-+      dump_save_this_cpu(regs);
-+      atomic_dec(&waiting_for_dump_ipi);
-+
-+ level_changed:
-+      switch (dump_silence_level) {
-+      case DUMP_HARD_SPIN_CPUS:       /* Spin until dump is complete */
-+              while (dump_oncpu) {
-+                      barrier();      /* paranoia */
-+                      if (dump_silence_level != DUMP_HARD_SPIN_CPUS)
-+                              goto level_changed;
-+
-+                      cpu_relax();    /* kill time nicely */
-+              }
-+              break;
-+
-+      case DUMP_HALT_CPUS:            /* Execute halt */
-+              stop_this_cpu(NULL);
-+              break;
-+              
-+      case DUMP_SOFT_SPIN_CPUS:
-+              /* Mark the task so it spins in schedule */
-+              set_tsk_thread_flag(current, TIF_NEED_RESCHED);
-+              break;
-+      }
-+
-+      return 1;
-+}
-+
-+/* save registers on other processors */
-+void 
-+__dump_save_other_cpus(void)
-+{
-+      int i, cpu = smp_processor_id();
-+      int other_cpus = num_online_cpus()-1;
-+      
-+      if (other_cpus > 0) {
-+              atomic_set(&waiting_for_dump_ipi, other_cpus);
-+
-+              for (i = 0; i < NR_CPUS; i++) {
-+                      dump_expect_ipi[i] = (i != cpu && cpu_online(i));
-+              }
-+
-+              /* short circuit normal NMI handling temporarily */
-+              set_nmi_callback(dump_nmi_callback);
-+              wmb();
-+
-+              dump_send_ipi();
-+              /* may be we dont need to wait for NMI to be processed. 
-+                 just write out the header at the end of dumping, if
-+                 this IPI is not processed until then, there probably
-+                 is a problem and we just fail to capture state of 
-+                 other cpus. */
-+              while(atomic_read(&waiting_for_dump_ipi) > 0) {
-+                      cpu_relax();
-+              }
-+
-+              unset_nmi_callback();
-+      }
-+}
-+
-+/*
-+ * Routine to save the old irq affinities and change affinities of all irqs to
-+ * the dumping cpu.
-+ */
-+static void 
-+set_irq_affinity(void)
-+{
-+      int i;
-+      int cpu = smp_processor_id();
-+
-+      memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(cpumask_t));
-+      for (i = 0; i < NR_IRQS; i++) {
-+              if (irq_desc[i].handler == NULL)
-+                      continue;
-+              irq_affinity[i] = cpumask_of_cpu(cpu);
-+              if (irq_desc[i].handler->set_affinity != NULL)
-+                      irq_desc[i].handler->set_affinity(i, irq_affinity[i]);
-+      }
-+}
-+
-+/*
-+ * Restore old irq affinities.
-+ */
-+static void 
-+reset_irq_affinity(void)
-+{
-+      int i;
-+
-+      memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long));
-+      for (i = 0; i < NR_IRQS; i++) {
-+              if (irq_desc[i].handler == NULL)
-+                      continue;
-+              if (irq_desc[i].handler->set_affinity != NULL)
-+                      irq_desc[i].handler->set_affinity(i, saved_affinity[i]);
-+      }
-+}
-+
-+#else /* !CONFIG_SMP */
-+#define set_irq_affinity()    do { } while (0)
-+#define reset_irq_affinity()  do { } while (0)
-+#define save_other_cpu_states() do { } while (0)
-+#endif /* !CONFIG_SMP */
-+
-+/* 
-+ * Kludge - dump from interrupt context is unreliable (Fixme)
-+ *
-+ * We do this so that softirqs initiated for dump i/o 
-+ * get processed and we don't hang while waiting for i/o
-+ * to complete or in any irq synchronization attempt.
-+ *
-+ * This is not quite legal of course, as it has the side 
-+ * effect of making all interrupts & softirqs triggered 
-+ * while dump is in progress complete before currently 
-+ * pending softirqs and the currently executing interrupt 
-+ * code. 
-+ */
-+static inline void
-+irq_bh_save(void)
-+{
-+      saved_irq_count = irq_count();
-+      preempt_count() &= ~(HARDIRQ_MASK|SOFTIRQ_MASK);
-+}
-+
-+static inline void
-+irq_bh_restore(void)
-+{
-+      preempt_count() |= saved_irq_count;
-+}
-+
-+/*
-+ * Name: __dump_irq_enable
-+ * Func: Reset system so interrupts are enabled.
-+ *     This is used for dump methods that require interrupts
-+ *     Eventually, all methods will have interrupts disabled
-+ *     and this code can be removed.
-+ *
-+ *     Change irq affinities
-+ *     Re-enable interrupts
-+ */
-+void 
-+__dump_irq_enable(void)
-+{
-+      set_irq_affinity();
-+      irq_bh_save();
-+      local_irq_enable();
-+}
-+
-+/*
-+ * Name: __dump_irq_restore
-+ * Func: Resume the system state in an architecture-specific way.
-+
-+ */
-+void 
-+__dump_irq_restore(void)
-+{
-+      local_irq_disable();
-+      reset_irq_affinity();
-+      irq_bh_restore();
-+}
-+
-+/*
-+ * Name: __dump_configure_header()
-+ * Func: Meant to fill in arch specific header fields except per-cpu state
-+ * already captured via __dump_save_context for all CPUs.
-+ */
-+int
-+__dump_configure_header(const struct pt_regs *regs)
-+{
-+      return (0);
-+}
-+
-+/*
-+ * Name: __dump_init()
-+ * Func: Initialize the dumping routine process.
-+ */
-+void
-+__dump_init(uint64_t local_memory_start)
-+{
-+      return;
-+}
-+
-+/*
-+ * Name: __dump_open()
-+ * Func: Open the dump device (architecture specific).
-+ */
-+void
-+__dump_open(void)
-+{
-+      alloc_dha_stack();
-+}
-+
-+/*
-+ * Name: __dump_cleanup()
-+ * Func: Free any architecture specific data structures. This is called
-+ *       when the dump module is being removed.
-+ */
-+void
-+__dump_cleanup(void)
-+{
-+      free_dha_stack();
-+}
-+
-+extern int pfn_is_ram(unsigned long);
-+
-+/*
-+ * Name: __dump_page_valid()
-+ * Func: Check if page is valid to dump.
-+ */ 
-+int 
-+__dump_page_valid(unsigned long index)
-+{
-+      if (!pfn_valid(index))
-+              return 0;
-+
-+      return pfn_is_ram(index);
-+}
-+
-Index: linux-2.6.0-test5/drivers/dump/dump_memdev.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_memdev.c  2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_memdev.c       2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,640 @@
-+/*
-+ * Implements the dump driver interface for saving a dump in available
-+ * memory areas. The saved pages may be written out to persistent storage  
-+ * after a soft reboot.
-+ *
-+ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
-+ *
-+ * Copyright (C) 2002 International Business Machines Corp. 
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ *
-+ * The approach of tracking pages containing saved dump using map pages 
-+ * allocated as needed has been derived from the Mission Critical Linux 
-+ * mcore dump implementation. 
-+ *
-+ * Credits and a big thanks for letting the lkcd project make use of 
-+ * the excellent piece of work and also helping with clarifications 
-+ * and tips along the way are due to:
-+ *    Dave Winchell <winchell@mclx.com> (primary author of mcore)
-+ *    Jeff Moyer <moyer@mclx.com>
-+ *    Josh Huber <huber@mclx.com>
-+ *
-+ * For those familiar with the mcore code, the main differences worth
-+ * noting here (besides the dump device abstraction) result from enabling 
-+ * "high" memory pages (pages not permanently mapped in the kernel 
-+ * address space) to be used for saving dump data (because of which a 
-+ * simple virtual address based linked list cannot be used anymore for 
-+ * managing free pages), an added level of indirection for faster 
-+ * lookups during the post-boot stage, and the idea of pages being 
-+ * made available as they get freed up while dump to memory progresses 
-+ * rather than one time before starting the dump. The last point enables 
-+ * a full memory snapshot to be saved starting with an initial set of 
-+ * bootstrap pages given a good compression ratio. (See dump_overlay.c)
-+ *
-+ */
-+
-+/*
-+ * -----------------MEMORY LAYOUT ------------------
-+ * The memory space consists of a set of discontiguous pages, and
-+ * discontiguous map pages as well, rooted in a chain of indirect
-+ * map pages (also discontiguous). Except for the indirect maps 
-+ * (which must be preallocated in advance), the rest of the pages 
-+ * could be in high memory.
-+ *
-+ * root
-+ *  |    ---------    --------        --------
-+ *  -->  | .  . +|--->|  .  +|------->| . .  |       indirect 
-+ *       --|--|---    ---|----        --|-|---             maps
-+ *         |  |          |                    | |     
-+ *    ------  ------   -------     ------ -------
-+ *    | .  |  | .  |   | .  . |    | .  | |  . . |   maps 
-+ *    --|---  --|---   --|--|--    --|--- ---|-|--
-+ *     page    page    page page   page   page page  data
-+ *                                                   pages
-+ *
-+ * Writes to the dump device happen sequentially in append mode.
-+ * The main reason for the existence of the indirect map is
-+ * to enable a quick way to lookup a specific logical offset in
-+ * the saved data post-soft-boot, e.g. to writeout pages
-+ * with more critical data first, even though such pages
-+ * would have been compressed and copied last, being the lowest
-+ * ranked candidates for reuse due to their criticality.
-+ * (See dump_overlay.c)
-+ */
-+#include <linux/mm.h>
-+#include <linux/highmem.h>
-+#include <linux/bootmem.h>
-+#include <linux/dump.h>
-+#include "dump_methods.h"
-+
-+#define DUMP_MAP_SZ (PAGE_SIZE / sizeof(unsigned long)) /* direct map size */
-+#define DUMP_IND_MAP_SZ       DUMP_MAP_SZ - 1  /* indirect map size */
-+#define DUMP_NR_BOOTSTRAP     64  /* no of bootstrap pages */
-+
-+extern int dump_low_page(struct page *);
-+
-+/* check if the next entry crosses a page boundary */
-+static inline int is_last_map_entry(unsigned long *map)
-+{
-+      unsigned long addr = (unsigned long)(map + 1);
-+
-+      return (!(addr & (PAGE_SIZE - 1)));
-+}
-+
-+/* Todo: should have some validation checks */
-+/* The last entry in the indirect map points to the next indirect map */
-+/* Indirect maps are referred to directly by virtual address */
-+static inline unsigned long *next_indirect_map(unsigned long *map)
-+{
-+      return (unsigned long *)map[DUMP_IND_MAP_SZ];
-+}
-+
-+#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
-+/* Called during early bootup - fixme: make this __init */
-+void dump_early_reserve_map(struct dump_memdev *dev)
-+{
-+      unsigned long *map1, *map2;
-+      loff_t off = 0, last = dev->last_used_offset >> PAGE_SHIFT;
-+      int i, j;
-+      
-+      printk("Reserve bootmap space holding previous dump of %lld pages\n",
-+                      last);
-+      map1= (unsigned long *)dev->indirect_map_root;
-+
-+      while (map1 && (off < last)) {
-+              reserve_bootmem(virt_to_phys((void *)map1), PAGE_SIZE);
-+              for (i=0;  (i < DUMP_MAP_SZ - 1) && map1[i] && (off < last); 
-+                      i++, off += DUMP_MAP_SZ) {
-+                      pr_debug("indirect map[%d] = 0x%lx\n", i, map1[i]);
-+                      if (map1[i] >= max_low_pfn)
-+                              continue;
-+                      reserve_bootmem(map1[i] << PAGE_SHIFT, PAGE_SIZE);
-+                      map2 = pfn_to_kaddr(map1[i]);
-+                      for (j = 0 ; (j < DUMP_MAP_SZ) && map2[j] && 
-+                              (off + j < last); j++) {
-+                              pr_debug("\t map[%d][%d] = 0x%lx\n", i, j, 
-+                                      map2[j]);
-+                              if (map2[j] < max_low_pfn) {
-+                                      reserve_bootmem(map2[j] << PAGE_SHIFT,
-+                                              PAGE_SIZE);
-+                              }
-+                      }
-+              }
-+              map1 = next_indirect_map(map1);
-+      }
-+      dev->nr_free = 0; /* these pages don't belong to this boot */
-+}
-+#endif
-+
-+/* mark dump pages so that they aren't used by this kernel */
-+void dump_mark_map(struct dump_memdev *dev)
-+{
-+      unsigned long *map1, *map2;
-+      loff_t off = 0, last = dev->last_used_offset >> PAGE_SHIFT;
-+      struct page *page;
-+      int i, j;
-+      
-+      printk("Dump: marking pages in use by previous dump\n");
-+      map1= (unsigned long *)dev->indirect_map_root;
-+
-+      while (map1 && (off < last)) {
-+              page = virt_to_page(map1);      
-+              set_page_count(page, 1);
-+              for (i=0;  (i < DUMP_MAP_SZ - 1) && map1[i] && (off < last); 
-+                      i++, off += DUMP_MAP_SZ) {
-+                      pr_debug("indirect map[%d] = 0x%lx\n", i, map1[i]);
-+                      page = pfn_to_page(map1[i]);
-+                      set_page_count(page, 1);
-+                      map2 = kmap_atomic(page, KM_DUMP);
-+                      for (j = 0 ; (j < DUMP_MAP_SZ) && map2[j] && 
-+                              (off + j < last); j++) {
-+                              pr_debug("\t map[%d][%d] = 0x%lx\n", i, j, 
-+                                      map2[j]);
-+                              page = pfn_to_page(map2[j]);
-+                              set_page_count(page, 1);
-+                      }
-+              }
-+              map1 = next_indirect_map(map1);
-+      }
-+}
-+      
-+
-+/* 
-+ * Given a logical offset into the mem device lookup the 
-+ * corresponding page 
-+ *    loc is specified in units of pages 
-+ * Note: affects curr_map (even in the case where lookup fails)
-+ */
-+struct page *dump_mem_lookup(struct dump_memdev *dump_mdev, unsigned long loc)
-+{
-+      unsigned long *map;
-+      unsigned long i, index = loc / DUMP_MAP_SZ;
-+      struct page *page = NULL;
-+      unsigned long curr_pfn, curr_map, *curr_map_ptr = NULL;
-+
-+      map = (unsigned long *)dump_mdev->indirect_map_root;
-+      if (!map)
-+              return NULL;
-+
-+      if (loc > dump_mdev->last_offset >> PAGE_SHIFT)
-+              return NULL;
-+
-+      /* 
-+       * first locate the right indirect map 
-+       * in the chain of indirect maps 
-+       */
-+      for (i = 0; i + DUMP_IND_MAP_SZ < index ; i += DUMP_IND_MAP_SZ) {
-+              if (!(map = next_indirect_map(map)))
-+                      return NULL;
-+      }
-+      /* then the right direct map */
-+      /* map entries are referred to by page index */
-+      if ((curr_map = map[index - i])) {
-+              page = pfn_to_page(curr_map);
-+              /* update the current traversal index */
-+              /* dump_mdev->curr_map = &map[index - i];*/
-+              curr_map_ptr = &map[index - i];
-+      }
-+
-+      if (page)
-+              map = kmap_atomic(page, KM_DUMP);
-+      else 
-+              return NULL;
-+
-+      /* and finally the right entry therein */
-+      /* data pages are referred to by page index */
-+      i = index * DUMP_MAP_SZ;
-+      if ((curr_pfn = map[loc - i])) {
-+              page = pfn_to_page(curr_pfn);
-+              dump_mdev->curr_map = curr_map_ptr;
-+              dump_mdev->curr_map_offset = loc - i;
-+              dump_mdev->ddev.curr_offset = loc << PAGE_SHIFT;
-+      } else {
-+              page = NULL;
-+      }
-+      kunmap_atomic(map, KM_DUMP);
-+
-+      return page;
-+}
-+                      
-+/* 
-+ * Retrieves a pointer to the next page in the dump device 
-+ * Used during the lookup pass post-soft-reboot 
-+ */
-+struct page *dump_mem_next_page(struct dump_memdev *dev)
-+{
-+      unsigned long i; 
-+      unsigned long *map;     
-+      struct page *page = NULL;
-+
-+      if (dev->ddev.curr_offset + PAGE_SIZE >= dev->last_offset) {
-+              return NULL;
-+      }
-+
-+      if ((i = (unsigned long)(++dev->curr_map_offset)) >= DUMP_MAP_SZ) {
-+              /* move to next map */  
-+              if (is_last_map_entry(++dev->curr_map)) {
-+                      /* move to the next indirect map page */
-+                      printk("dump_mem_next_page: go to next indirect map\n");
-+                      dev->curr_map = (unsigned long *)*dev->curr_map;
-+                      if (!dev->curr_map)
-+                              return NULL;
-+              }
-+              i = dev->curr_map_offset = 0;
-+              pr_debug("dump_mem_next_page: next map 0x%lx, entry 0x%lx\n",
-+                              dev->curr_map, *dev->curr_map);
-+
-+      };
-+      
-+      if (*dev->curr_map) {
-+              map = kmap_atomic(pfn_to_page(*dev->curr_map), KM_DUMP);
-+              if (map[i])
-+                      page = pfn_to_page(map[i]);
-+              kunmap_atomic(map, KM_DUMP);
-+              dev->ddev.curr_offset += PAGE_SIZE;
-+      };
-+
-+      return page;
-+}
-+
-+/* Copied from dump_filters.c */
-+static inline int kernel_page(struct page *p)
-+{
-+      /* FIXME: Need to exclude hugetlb pages. Clue: reserved but inuse */
-+      return PageReserved(p) || (!PageLRU(p) && PageInuse(p));
-+}
-+
-+static inline int user_page(struct page *p)
-+{
-+      return PageInuse(p) && (!PageReserved(p) && PageLRU(p));
-+}
-+
-+int dump_reused_by_boot(struct page *page)
-+{
-+      /* Todo
-+       * Checks:
-+       * if PageReserved 
-+       * if < __end + bootmem_bootmap_pages for this boot + allowance 
-+       * if overwritten by initrd (how to check ?)
-+       * Also, add more checks in early boot code
-+       * e.g. bootmem bootmap alloc verify not overwriting dump, and if
-+       * so then realloc or move the dump pages out accordingly.
-+       */
-+
-+      /* Temporary proof of concept hack, avoid overwriting kern pages */
-+
-+      return (kernel_page(page) || dump_low_page(page) || user_page(page));
-+}
-+
-+
-+/* Uses the free page passed in to expand available space */
-+int dump_mem_add_space(struct dump_memdev *dev, struct page *page)
-+{
-+      struct page *map_page;
-+      unsigned long *map;     
-+      unsigned long i; 
-+
-+      if (!dev->curr_map)
-+              return -ENOMEM; /* must've exhausted indirect map */
-+
-+      if (!*dev->curr_map || dev->curr_map_offset >= DUMP_MAP_SZ) {
-+              /* add map space */
-+              *dev->curr_map = page_to_pfn(page);
-+              dev->curr_map_offset = 0;
-+              return 0;
-+      }
-+
-+      /* add data space */
-+      i = dev->curr_map_offset;
-+      map_page = pfn_to_page(*dev->curr_map);
-+      map = (unsigned long *)kmap_atomic(map_page, KM_DUMP);
-+      map[i] = page_to_pfn(page);
-+      kunmap_atomic(map, KM_DUMP);
-+      dev->curr_map_offset = ++i;
-+      dev->last_offset += PAGE_SIZE;
-+      if (i >= DUMP_MAP_SZ) {
-+              /* move to next map */
-+              if (is_last_map_entry(++dev->curr_map)) {
-+                      /* move to the next indirect map page */
-+                      pr_debug("dump_mem_add_space: using next"
-+                      "indirect map\n");
-+                      dev->curr_map = (unsigned long *)*dev->curr_map;
-+              }
-+      }               
-+      return 0;
-+}
-+
-+
-+/* Caution: making a dest page invalidates existing contents of the page */
-+int dump_check_and_free_page(struct dump_memdev *dev, struct page *page)
-+{
-+      int err = 0;
-+
-+      /* 
-+       * the page can be used as a destination only if we are sure
-+       * it won't get overwritten by the soft-boot, and is not
-+       * critical for us right now.
-+       */
-+      if (dump_reused_by_boot(page))
-+              return 0;
-+
-+      if ((err = dump_mem_add_space(dev, page))) {
-+              printk("Warning: Unable to extend memdev space. Err %d\n",
-+              err);
-+              return 0;
-+      }
-+
-+      dev->nr_free++;
-+      return 1;
-+}
-+
-+
-+/* Set up the initial maps and bootstrap space  */
-+/* Must be called only after any previous dump is written out */
-+int dump_mem_open(struct dump_dev *dev, unsigned long devid)
-+{
-+      struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
-+      unsigned long nr_maps, *map, *prev_map = &dump_mdev->indirect_map_root;
-+      void *addr;
-+      struct page *page;
-+      unsigned long i = 0;
-+      int err = 0;
-+
-+      /* Todo: sanity check for unwritten previous dump */
-+
-+      /* allocate pages for indirect map (non highmem area) */
-+      nr_maps = num_physpages / DUMP_MAP_SZ; /* maps to cover entire mem */
-+      for (i = 0; i < nr_maps; i += DUMP_IND_MAP_SZ) {
-+              if (!(map = (unsigned long *)dump_alloc_mem(PAGE_SIZE))) {
-+                      printk("Unable to alloc indirect map %ld\n", 
-+                              i / DUMP_IND_MAP_SZ);
-+                      return -ENOMEM;
-+              }
-+              clear_page(map);
-+              *prev_map = (unsigned long)map;
-+              prev_map = &map[DUMP_IND_MAP_SZ];
-+      };
-+              
-+      dump_mdev->curr_map = (unsigned long *)dump_mdev->indirect_map_root;
-+      dump_mdev->curr_map_offset = 0; 
-+
-+      /* 
-+       * allocate a few bootstrap pages: at least 1 map and 1 data page
-+       * plus enough to save the dump header
-+       */
-+      i = 0;
-+      do {
-+              if (!(addr = dump_alloc_mem(PAGE_SIZE))) {
-+                      printk("Unable to alloc bootstrap page %ld\n", i);
-+                      return -ENOMEM;
-+              }
-+
-+              page = virt_to_page(addr);
-+              if (dump_low_page(page)) {
-+                      dump_free_mem(addr);
-+                      continue;
-+              }
-+
-+              if (dump_mem_add_space(dump_mdev, page)) {
-+                      printk("Warning: Unable to extend memdev "
-+                                      "space. Err %d\n", err);
-+                      dump_free_mem(addr);
-+                      continue;
-+              }
-+              i++;
-+      } while (i < DUMP_NR_BOOTSTRAP);
-+
-+      printk("dump memdev init: %ld maps, %ld bootstrap pgs, %ld free pgs\n",
-+              nr_maps, i, dump_mdev->last_offset >> PAGE_SHIFT);
-+      
-+      dump_mdev->last_bs_offset = dump_mdev->last_offset;
-+
-+      return 0;
-+}
-+
-+/* Releases all pre-alloc'd pages */
-+int dump_mem_release(struct dump_dev *dev)
-+{
-+      struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
-+      struct page *page, *map_page;
-+      unsigned long *map, *prev_map;
-+      void *addr;
-+      int i;
-+
-+      if (!dump_mdev->nr_free)
-+              return 0;
-+
-+      pr_debug("dump_mem_release\n");
-+      page = dump_mem_lookup(dump_mdev, 0);
-+      for (i = 0; page && (i < DUMP_NR_BOOTSTRAP - 1); i++) {
-+              if (PageHighMem(page))
-+                      break;
-+              addr = page_address(page);
-+              if (!addr) {
-+                      printk("page_address(%p) = NULL\n", page);
-+                      break;
-+              }
-+              pr_debug("Freeing page at 0x%lx\n", addr); 
-+              dump_free_mem(addr);
-+              if (dump_mdev->curr_map_offset >= DUMP_MAP_SZ - 1) {
-+                      map_page = pfn_to_page(*dump_mdev->curr_map);
-+                      if (PageHighMem(map_page))
-+                              break;
-+                      page = dump_mem_next_page(dump_mdev);
-+                      addr = page_address(map_page);
-+                      if (!addr) {
-+                              printk("page_address(%p) = NULL\n", 
-+                                      map_page);
-+                              break;
-+                      }
-+                      pr_debug("Freeing map page at 0x%lx\n", addr);
-+                      dump_free_mem(addr);
-+                      i++;
-+              } else {
-+                      page = dump_mem_next_page(dump_mdev);
-+              }
-+      }
-+
-+      /* now for the last used bootstrap page used as a map page */
-+      if ((i < DUMP_NR_BOOTSTRAP) && (*dump_mdev->curr_map)) {
-+              map_page = pfn_to_page(*dump_mdev->curr_map);
-+              if ((map_page) && !PageHighMem(map_page)) {
-+                      addr = page_address(map_page);
-+                      if (!addr) {
-+                              printk("page_address(%p) = NULL\n", map_page);
-+                      } else {
-+                              pr_debug("Freeing map page at 0x%lx\n", addr);
-+                              dump_free_mem(addr);
-+                              i++;
-+                      }
-+              }
-+      }
-+
-+      printk("Freed %d bootstrap pages\n", i);
-+
-+      /* free the indirect maps */
-+      map = (unsigned long *)dump_mdev->indirect_map_root;
-+
-+      i = 0;
-+      while (map) {
-+              prev_map = map;
-+              map = next_indirect_map(map);
-+              dump_free_mem(prev_map);
-+              i++;
-+      }
-+
-+      printk("Freed %d indirect map(s)\n", i);
-+
-+      /* Reset the indirect map */
-+      dump_mdev->indirect_map_root = 0;
-+      dump_mdev->curr_map = 0;
-+
-+      /* Reset the free list */
-+      dump_mdev->nr_free = 0;
-+
-+      dump_mdev->last_offset = dump_mdev->ddev.curr_offset = 0;
-+      dump_mdev->last_used_offset = 0;
-+      dump_mdev->curr_map = NULL;
-+      dump_mdev->curr_map_offset = 0;
-+      return 0;
-+}
-+
-+/*
-+ * Long term:
-+ * It is critical for this to be very strict. Cannot afford
-+ * to have anything running and accessing memory while we overwrite 
-+ * memory (potential risk of data corruption).
-+ * If in doubt (e.g if a cpu is hung and not responding) just give
-+ * up and refuse to proceed with this scheme.
-+ *
-+ * Note: I/O will only happen after soft-boot/switchover, so we can 
-+ * safely disable interrupts and force stop other CPUs if this is
-+ * going to be a disruptive dump, no matter what they
-+ * are in the middle of.
-+ */
-+/* 
-+ * ATM Most of this is already taken care of in the nmi handler 
-+ * We may halt the cpus rightaway if we know this is going to be disruptive 
-+ * For now, since we've limited ourselves to overwriting free pages we
-+ * aren't doing much here. Eventually, we'd have to wait to make sure other
-+ * cpus aren't using memory we could be overwriting
-+ */
-+int dump_mem_silence(struct dump_dev *dev)
-+{
-+      struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
-+
-+      if (dump_mdev->last_offset > dump_mdev->last_bs_offset) {
-+              /* prefer to run lkcd config & start with a clean slate */
-+              return -EEXIST;
-+      }
-+      return 0;
-+}
-+
-+extern int dump_overlay_resume(void);
-+
-+/* Trigger the next stage of dumping */
-+int dump_mem_resume(struct dump_dev *dev)
-+{
-+      dump_overlay_resume(); 
-+      return 0;
-+}
-+
-+/* 
-+ * Allocate mem dev pages as required and copy buffer contents into it.
-+ * Fails if the no free pages are available
-+ * Keeping it simple and limited for starters (can modify this over time)
-+ *  Does not handle holes or a sparse layout
-+ *  Data must be in multiples of PAGE_SIZE
-+ */
-+int dump_mem_write(struct dump_dev *dev, void *buf, unsigned long len)
-+{
-+      struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
-+      struct page *page;
-+      unsigned long n = 0;
-+      void *addr;
-+      unsigned long *saved_curr_map, saved_map_offset;
-+      int ret = 0;
-+
-+      pr_debug("dump_mem_write: offset 0x%llx, size %ld\n", 
-+              dev->curr_offset, len);
-+
-+      if (dev->curr_offset + len > dump_mdev->last_offset)  {
-+              printk("Out of space to write\n");
-+              return -ENOSPC;
-+      }
-+      
-+      if ((len & (PAGE_SIZE - 1)) || (dev->curr_offset & (PAGE_SIZE - 1)))
-+              return -EINVAL; /* not aligned in units of page size */
-+
-+      saved_curr_map = dump_mdev->curr_map;
-+      saved_map_offset = dump_mdev->curr_map_offset;
-+      page = dump_mem_lookup(dump_mdev, dev->curr_offset >> PAGE_SHIFT);
-+
-+      for (n = len; (n > 0) && page; n -= PAGE_SIZE, buf += PAGE_SIZE ) {
-+              addr = kmap_atomic(page, KM_DUMP);
-+              /* memset(addr, 'x', PAGE_SIZE); */
-+              memcpy(addr, buf, PAGE_SIZE);
-+              kunmap_atomic(addr, KM_DUMP);
-+              /* dev->curr_offset += PAGE_SIZE; */
-+              page = dump_mem_next_page(dump_mdev);
-+      }
-+
-+      dump_mdev->curr_map = saved_curr_map;
-+      dump_mdev->curr_map_offset = saved_map_offset;
-+
-+      if (dump_mdev->last_used_offset < dev->curr_offset)
-+              dump_mdev->last_used_offset = dev->curr_offset;
-+
-+      return (len - n) ? (len - n) : ret ;
-+}
-+
-+/* dummy - always ready */
-+int dump_mem_ready(struct dump_dev *dev, void *buf)
-+{
-+      return 0;
-+}
-+
-+/* 
-+ * Should check for availability of space to write upto the offset 
-+ * affects only the curr_offset; last_offset untouched 
-+ * Keep it simple: Only allow multiples of PAGE_SIZE for now 
-+ */
-+int dump_mem_seek(struct dump_dev *dev, loff_t offset)
-+{
-+      struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
-+
-+      if (offset & (PAGE_SIZE - 1))
-+              return -EINVAL; /* allow page size units only for now */
-+      
-+      /* Are we exceeding available space ? */
-+      if (offset > dump_mdev->last_offset) {
-+              printk("dump_mem_seek failed for offset 0x%llx\n",
-+                      offset);
-+              return -ENOSPC; 
-+      }
-+
-+      dump_mdev->ddev.curr_offset = offset;
-+      return 0;
-+}
-+
-+struct dump_dev_ops dump_memdev_ops = {
-+      .open           = dump_mem_open,
-+      .release        = dump_mem_release,
-+      .silence        = dump_mem_silence,
-+      .resume         = dump_mem_resume,
-+      .seek           = dump_mem_seek,
-+      .write          = dump_mem_write,
-+      .read           = NULL, /* not implemented at the moment */
-+      .ready          = dump_mem_ready
-+};
-+
-+static struct dump_memdev default_dump_memdev = {
-+      .ddev = {.type_name = "memdev", .ops = &dump_memdev_ops,
-+               .device_id = 0x14}
-+      /* assume the rest of the fields are zeroed by default */
-+};    
-+      
-+/* may be overwritten if a previous dump exists */
-+struct dump_memdev *dump_memdev = &default_dump_memdev;
-+
-Index: linux-2.6.0-test5/drivers/dump/dump_netdev.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_netdev.c  2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_netdev.c       2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,880 @@
-+/*
-+ * Implements the dump driver interface for saving a dump via network
-+ * interface. 
-+ *
-+ * Some of this code has been taken/adapted from Ingo Molnar's netconsole
-+ * code. LKCD team expresses its thanks to Ingo.
-+ *
-+ * Started: June 2002 - Mohamed Abbas <mohamed.abbas@intel.com>
-+ *    Adapted netconsole code to implement LKCD dump over the network.
-+ *
-+ * Nov 2002 - Bharata B. Rao <bharata@in.ibm.com>
-+ *    Innumerable code cleanups, simplification and some fixes.
-+ *    Netdump configuration done by ioctl instead of using module parameters.
-+ *
-+ * Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
-+ * Copyright (C) 2002 International Business Machines Corp. 
-+ *
-+ *  This code is released under version 2 of the GNU GPL.
-+ */
-+
-+#include <net/tcp.h>
-+#include <net/udp.h>
-+#include <linux/delay.h>
-+#include <linux/random.h>
-+#include <linux/reboot.h>
-+#include <linux/module.h>
-+#include <linux/dump.h>
-+#include <linux/dump_netdev.h>
-+
-+#include <asm/unaligned.h>
-+
-+static int startup_handshake;
-+static int page_counter;
-+static struct net_device *dump_ndev;
-+static struct in_device *dump_in_dev;
-+static u16 source_port, target_port;
-+static u32 source_ip, target_ip;
-+static unsigned char daddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
-+static spinlock_t dump_skb_lock = SPIN_LOCK_UNLOCKED;
-+static int dump_nr_skbs;
-+static struct sk_buff *dump_skb;
-+static unsigned long flags_global;
-+static int netdump_in_progress;
-+static char device_name[IFNAMSIZ];
-+
-+/*
-+ * 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 dump_magic;
-+
-+#define MAX_UDP_CHUNK 1460
-+#define MAX_PRINT_CHUNK (MAX_UDP_CHUNK-HEADER_LEN)
-+
-+/*
-+ * We maintain a small pool of fully-sized skbs,
-+ * to make sure the message gets out even in
-+ * extreme OOM situations.
-+ */
-+#define DUMP_MAX_SKBS 32
-+
-+#define MAX_SKB_SIZE \
-+              (MAX_UDP_CHUNK + sizeof(struct udphdr) + \
-+                              sizeof(struct iphdr) + sizeof(struct ethhdr))
-+
-+static void
-+dump_refill_skbs(void)
-+{
-+      struct sk_buff *skb;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&dump_skb_lock, flags);
-+      while (dump_nr_skbs < DUMP_MAX_SKBS) {
-+              skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
-+              if (!skb)
-+                      break;
-+              if (dump_skb)
-+                      skb->next = dump_skb;
-+              else
-+                      skb->next = NULL;
-+              dump_skb = skb;
-+              dump_nr_skbs++;
-+      }
-+      spin_unlock_irqrestore(&dump_skb_lock, flags);
-+}
-+
-+static struct
-+sk_buff * dump_get_skb(void)
-+{
-+      struct sk_buff *skb;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&dump_skb_lock, flags);
-+      skb = dump_skb;
-+      if (skb) {
-+              dump_skb = skb->next;
-+              skb->next = NULL;
-+              dump_nr_skbs--;
-+      }
-+      spin_unlock_irqrestore(&dump_skb_lock, flags);
-+        
-+      return skb;
-+}
-+
-+/*
-+ * Zap completed output skbs.
-+ */
-+static void
-+zap_completion_queue(void)
-+{
-+      int count;
-+      unsigned long flags;
-+      int cpu = smp_processor_id();
-+      struct softnet_data *softnet_data;
-+              
-+
-+      softnet_data = &__get_cpu_var(softnet_data);
-+      count=0;
-+      if (softnet_data[cpu].completion_queue) {
-+              struct sk_buff *clist;
-+      
-+              local_irq_save(flags);
-+              clist = softnet_data[cpu].completion_queue;
-+              softnet_data[cpu].completion_queue = NULL;
-+              local_irq_restore(flags);
-+
-+              while (clist != NULL) {
-+                      struct sk_buff *skb = clist;
-+                      clist = clist->next;
-+                      __kfree_skb(skb);
-+                      count++;
-+                      if (count > 10000)
-+                              printk("Error in sk list\n");
-+              }
-+      }
-+}
-+
-+static void
-+dump_send_skb(struct net_device *dev, const char *msg, unsigned int msg_len,
-+              reply_t *reply)
-+{
-+      int once = 1;
-+      int total_len, eth_len, ip_len, udp_len, count = 0;
-+      struct sk_buff *skb;
-+      struct udphdr *udph;
-+      struct iphdr *iph;
-+      struct ethhdr *eth; 
-+
-+      udp_len = msg_len + HEADER_LEN + sizeof(*udph);
-+      ip_len = eth_len = udp_len + sizeof(*iph);
-+      total_len = eth_len + ETH_HLEN;
-+
-+repeat_loop:
-+      zap_completion_queue();
-+      if (dump_nr_skbs < DUMP_MAX_SKBS)
-+              dump_refill_skbs();
-+
-+      skb = alloc_skb(total_len, GFP_ATOMIC);
-+      if (!skb) {
-+              skb = dump_get_skb();
-+              if (!skb) {
-+                      count++;
-+                      if (once && (count == 1000000)) {
-+                              printk("possibly FATAL: out of netconsole "
-+                                      "skbs!!! will keep retrying.\n");
-+                              once = 0;
-+                      }
-+                      dev->poll_controller(dev);
-+                      goto repeat_loop;
-+              }
-+      }
-+
-+      atomic_set(&skb->users, 1);
-+      skb_reserve(skb, total_len - msg_len - HEADER_LEN);
-+      skb->data[0] = NETCONSOLE_VERSION;
-+
-+      put_unaligned(htonl(reply->nr), (u32 *) (skb->data + 1));
-+      put_unaligned(htonl(reply->code), (u32 *) (skb->data + 5));
-+      put_unaligned(htonl(reply->info), (u32 *) (skb->data + 9));
-+
-+      memcpy(skb->data + HEADER_LEN, msg, msg_len);
-+      skb->len += msg_len + HEADER_LEN;
-+
-+      udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
-+      udph->source = source_port;
-+      udph->dest = target_port;
-+      udph->len = htons(udp_len);
-+      udph->check = 0;
-+
-+      iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
-+
-+      iph->version  = 4;
-+      iph->ihl      = 5;
-+      iph->tos      = 0;
-+      iph->tot_len  = htons(ip_len);
-+      iph->id       = 0;
-+      iph->frag_off = 0;
-+      iph->ttl      = 64;
-+      iph->protocol = IPPROTO_UDP;
-+      iph->check    = 0;
-+      iph->saddr    = source_ip;
-+      iph->daddr    = target_ip;
-+      iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
-+
-+      eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
-+
-+      eth->h_proto = htons(ETH_P_IP);
-+      memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-+      memcpy(eth->h_dest, daddr, dev->addr_len);
-+
-+      count=0;
-+repeat_poll:
-+      spin_lock(&dev->xmit_lock);
-+      dev->xmit_lock_owner = smp_processor_id();
-+
-+      count++;
-+
-+
-+      if (netif_queue_stopped(dev)) {
-+              dev->xmit_lock_owner = -1;
-+              spin_unlock(&dev->xmit_lock);
-+
-+              dev->poll_controller(dev);
-+              zap_completion_queue();
-+
-+
-+              goto repeat_poll;
-+      }
-+
-+      dev->hard_start_xmit(skb, dev);
-+
-+      dev->xmit_lock_owner = -1;
-+      spin_unlock(&dev->xmit_lock);
-+}
-+
-+static unsigned short
-+udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr,
-+              unsigned long base)
-+{
-+      return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base);
-+}
-+
-+static int
-+udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
-+                           unsigned short ulen, u32 saddr, u32 daddr)
-+{
-+      if (uh->check == 0) {
-+              skb->ip_summed = CHECKSUM_UNNECESSARY;
-+      } else if (skb->ip_summed == CHECKSUM_HW) {
-+              skb->ip_summed = CHECKSUM_UNNECESSARY;
-+              if (!udp_check(uh, ulen, saddr, daddr, skb->csum))
-+                      return 0;
-+              skb->ip_summed = CHECKSUM_NONE;
-+      }
-+      if (skb->ip_summed != CHECKSUM_UNNECESSARY)
-+              skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen,
-+                              IPPROTO_UDP, 0);
-+      /* Probably, we should checksum udp header (it should be in cache
-+       * in any case) and data in tiny packets (< rx copybreak).
-+       */
-+      return 0;
-+}
-+
-+static __inline__ int
-+__udp_checksum_complete(struct sk_buff *skb)
-+{
-+      return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len,
-+                              skb->csum));
-+}
-+
-+static __inline__
-+int udp_checksum_complete(struct sk_buff *skb)
-+{
-+      return skb->ip_summed != CHECKSUM_UNNECESSARY &&
-+              __udp_checksum_complete(skb);
-+}
-+
-+int new_req = 0;
-+static req_t req;
-+
-+static int
-+dump_rx_hook(struct sk_buff *skb)
-+{
-+      int proto;
-+      struct iphdr *iph;
-+      struct udphdr *uh;
-+      __u32 len, saddr, daddr, ulen;
-+      req_t *__req;
-+
-+      /* 
-+       * First check if were are dumping or doing startup handshake, if
-+       * not quickly return.
-+       */
-+      if (!netdump_in_progress)
-+              return NET_RX_SUCCESS;
-+
-+      if (skb->dev->type != ARPHRD_ETHER)
-+              goto out;
-+
-+      proto = ntohs(skb->mac.ethernet->h_proto);
-+      if (proto != ETH_P_IP)
-+              goto out;
-+
-+      if (skb->pkt_type == PACKET_OTHERHOST)
-+              goto out;
-+
-+      if (skb_shared(skb))
-+              goto out;
-+
-+       /* IP header correctness testing: */
-+      iph = (struct iphdr *)skb->data;
-+      if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-+              goto out;
-+
-+      if (iph->ihl < 5 || iph->version != 4)
-+              goto out;
-+
-+      if (!pskb_may_pull(skb, iph->ihl*4))
-+              goto out;
-+
-+      if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
-+              goto out;
-+
-+      len = ntohs(iph->tot_len);
-+      if (skb->len < len || len < iph->ihl*4)
-+              goto out;
-+
-+      saddr = iph->saddr;
-+      daddr = iph->daddr;
-+      if (iph->protocol != IPPROTO_UDP)
-+              goto out;
-+
-+      if (source_ip != daddr)
-+              goto out;
-+
-+      if (target_ip != saddr)
-+              goto out;
-+
-+      len -= iph->ihl*4;
-+      uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
-+      ulen = ntohs(uh->len);
-+
-+      if (ulen != len || ulen < (sizeof(*uh) + sizeof(*__req)))
-+              goto out;
-+
-+      if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0)
-+              goto out;
-+
-+      if (udp_checksum_complete(skb))
-+              goto out;
-+
-+      if (source_port != uh->dest)
-+              goto out;
-+
-+      if (target_port != uh->source)
-+              goto out;
-+
-+      __req = (req_t *)(uh + 1);
-+      if ((ntohl(__req->command) != COMM_GET_MAGIC) &&
-+          (ntohl(__req->command) != COMM_HELLO) &&
-+          (ntohl(__req->command) != COMM_START_WRITE_NETDUMP_ACK) &&
-+          (ntohl(__req->command) != COMM_START_NETDUMP_ACK) &&
-+          (memcmp(&__req->magic, &dump_magic, sizeof(dump_magic)) != 0))
-+              goto out;
-+
-+      req.magic = ntohl(__req->magic);
-+      req.command = ntohl(__req->command);
-+      req.from = ntohl(__req->from);
-+      req.to = ntohl(__req->to);
-+      req.nr = ntohl(__req->nr);
-+      new_req = 1;
-+out:
-+      return NET_RX_DROP;
-+}
-+
-+static void
-+dump_send_mem(struct net_device *dev, req_t *req, const char* buff, size_t len)
-+{
-+      int i;
-+
-+      int nr_chunks = len/1024;
-+      reply_t reply;
-+      
-+      reply.nr = req->nr;
-+      reply.info = 0;
-+
-+        if ( nr_chunks <= 0)
-+               nr_chunks = 1;
-+      for (i = 0; i < nr_chunks; i++) {
-+              unsigned int offset = i*1024;
-+              reply.code = REPLY_MEM;
-+              reply.info = offset;
-+                dump_send_skb(dev, buff + offset, 1024, &reply);
-+      }
-+}
-+static void dump_do_sysrq(int key)
-+{
-+        struct pt_regs regs;
-+        
-+      get_current_regs(&regs);
-+      handle_sysrq(key, &regs, NULL, NULL);
-+}
-+
-+/*
-+ * 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 int
-+dump_handshake(struct dump_dev *net_dev)
-+{
-+      char tmp[200];
-+      reply_t reply;
-+      int i, j;
-+
-+      if (startup_handshake) {
-+              sprintf(tmp, "NETDUMP start, waiting for start-ACK.\n");
-+              reply.code = REPLY_START_NETDUMP;
-+              reply.nr = 0;
-+              reply.info = 0;
-+      } else {
-+              sprintf(tmp, "NETDUMP start, waiting for start-ACK.\n");
-+              reply.code = REPLY_START_WRITE_NETDUMP;
-+              reply.nr = net_dev->curr_offset;
-+              reply.info = net_dev->curr_offset;
-+      }
-+      
-+      /* send 300 handshake packets before declaring failure */
-+      for (i = 0; i < 300; i++) {
-+              dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
-+
-+              /* wait 1 sec */
-+              for (j = 0; j < 10000; j++) {
-+                      udelay(100);
-+                      dump_ndev->poll_controller(dump_ndev);
-+                      zap_completion_queue();
-+                      if (new_req)
-+                              break;
-+              }
-+
-+              /* 
-+               * if there is no new request, try sending the handshaking
-+               * packet again
-+               */
-+              if (!new_req)
-+                      continue;
-+
-+              /* 
-+               * check if the new request is of the expected type,
-+               * if so, return, else try sending the handshaking
-+               * packet again
-+               */
-+              if (startup_handshake) {
-+                      if (req.command == COMM_HELLO || req.command ==
-+                              COMM_START_NETDUMP_ACK) {
-+                              return 0;
-+                      } else {
-+                              new_req = 0;
-+                              continue;
-+                      }
-+              } else {
-+                      if (req.command == COMM_SEND_MEM) {
-+                              return 0;
-+                      } else {
-+                              new_req = 0;
-+                              continue;
-+                      }
-+              }
-+      }
-+      return -1;
-+}
-+
-+static ssize_t
-+do_netdump(struct dump_dev *net_dev, const char* buff, size_t len)
-+{
-+      reply_t reply;
-+      char tmp[200];
-+      ssize_t  ret = 0;
-+      int repeatCounter, counter, total_loop;
-+      
-+      netdump_in_progress = 1;
-+
-+      if (dump_handshake(net_dev) < 0) {
-+              printk("network dump failed due to handshake failure\n");
-+              goto out;
-+      }
-+
-+      /*
-+       * Ideally startup handshake should be done during dump configuration,
-+       * i.e., in dump_net_open(). This will be done when I figure out
-+       * the dependency between startup handshake, subsequent write and
-+       * various commands wrt to net-server.
-+       */
-+      if (startup_handshake)
-+              startup_handshake = 0;
-+
-+        counter = 0;
-+      repeatCounter = 0;
-+      total_loop = 0;
-+      while (1) {
-+                if (!new_req) {
-+                      dump_ndev->poll_controller(dump_ndev);
-+                      zap_completion_queue();
-+              }
-+              if (!new_req) {
-+                      repeatCounter++;
-+
-+                      if (repeatCounter > 5) {
-+                              counter++;
-+                              if (counter > 10000) {
-+                                      if (total_loop >= 100000) {
-+                                              printk("Time OUT LEAVE NOW\n");
-+                                              goto out;
-+                                      } else {
-+                                              total_loop++;
-+                                              printk("Try number %d out of "
-+                                                      "10 before Time Out\n",
-+                                                      total_loop);
-+                                      }
-+                              }
-+                              mdelay(1);
-+                              repeatCounter = 0;
-+                      }       
-+                      continue;
-+              }
-+              repeatCounter = 0;
-+              counter = 0;
-+              total_loop = 0;
-+              new_req = 0;
-+              switch (req.command) {
-+              case COMM_NONE:
-+                      break;
-+
-+              case COMM_SEND_MEM:
-+                      dump_send_mem(dump_ndev, &req, buff, len);
-+                      break;
-+
-+              case COMM_EXIT:
-+                case COMM_START_WRITE_NETDUMP_ACK:
-+                      ret = len;
-+                      goto out;
-+
-+              case COMM_HELLO:
-+                      sprintf(tmp, "Hello, this is netdump version "
-+                                      "0.%02d\n", NETCONSOLE_VERSION);
-+                      reply.code = REPLY_HELLO;
-+                      reply.nr = req.nr;
-+                        reply.info = net_dev->curr_offset;
-+                      dump_send_skb(dump_ndev, 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;
-+                      dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
-+                      break;
-+
-+              case COMM_GET_NR_PAGES:
-+                      reply.code = REPLY_NR_PAGES;
-+                      reply.nr = req.nr;
-+                      reply.info = num_physpages;
-+                        reply.info = page_counter;
-+                      sprintf(tmp, "Number of pages: %ld\n", num_physpages);
-+                      dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
-+                      break;
-+
-+              case COMM_GET_MAGIC:
-+                      reply.code = REPLY_MAGIC;
-+                      reply.nr = req.nr;
-+                      reply.info = NETCONSOLE_VERSION;
-+                      dump_send_skb(dump_ndev, (char *)&dump_magic,
-+                                      sizeof(dump_magic), &reply);
-+                      break;
-+                case COMM_SYSRQ:
-+                      dump_do_sysrq(req.from);
-+                      reply.code = REPLY_SYSRQ;
-+                      reply.nr = req.nr;
-+                      reply.info = req.from;
-+                      sprintf(tmp, "SYSRQ command %d \n", req.from);
-+                      dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
-+                      break;
-+              default:
-+                      reply.code = REPLY_ERROR;
-+                      reply.nr = req.nr;
-+                      reply.info = req.command;
-+                      sprintf(tmp, "Got unknown command code %d!\n",
-+                                      req.command);
-+                      dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
-+                      break;
-+              }
-+      }
-+out:
-+      netdump_in_progress = 0;
-+      return ret;
-+}
-+
-+static int
-+dump_validate_config(void)
-+{
-+      source_ip = dump_in_dev->ifa_list->ifa_local;
-+      if (!source_ip) {
-+              printk("network device %s has no local address, "
-+                              "aborting.\n", device_name);
-+              return -1;
-+      }
-+
-+#define IP(x) ((unsigned char *)&source_ip)[x]
-+      printk("Source %d.%d.%d.%d", IP(0), IP(1), IP(2), IP(3));
-+#undef IP
-+
-+      if (!source_port) {
-+              printk("source_port parameter not specified, aborting.\n");
-+              return -1;
-+      }
-+      printk(":%i\n", source_port);
-+      source_port = htons(source_port);
-+
-+      if (!target_ip) {
-+              printk("target_ip parameter not specified, aborting.\n");
-+              return -1;
-+      }
-+
-+#define IP(x) ((unsigned char *)&target_ip)[x]
-+      printk("Target %d.%d.%d.%d", IP(0), IP(1), IP(2), IP(3));
-+#undef IP
-+
-+      if (!target_port) {
-+              printk("target_port parameter not specified, aborting.\n");
-+              return -1;
-+      }
-+      printk(":%i\n", target_port);
-+      target_port = htons(target_port);
-+
-+      printk("Target Ethernet Address %02x:%02x:%02x:%02x:%02x:%02x",
-+              daddr[0], daddr[1], daddr[2], daddr[3], daddr[4], daddr[5]);
-+
-+      if ((daddr[0] & daddr[1] & daddr[2] & daddr[3] & daddr[4] & 
-+                              daddr[5]) == 255)
-+              printk("(Broadcast)");
-+      printk("\n");
-+      return 0;
-+}
-+
-+/*
-+ * Prepares the dump device so we can take a dump later. 
-+ * Validates the netdump configuration parameters.
-+ *
-+ * TODO: Network connectivity check should be done here.
-+ */
-+static int
-+dump_net_open(struct dump_dev *net_dev, unsigned long arg)
-+{
-+      int retval = 0;
-+
-+      /* get the interface name */
-+      if (copy_from_user(device_name, (void *)arg, IFNAMSIZ))
-+              return -EFAULT;
-+
-+      if (!(dump_ndev = dev_get_by_name(device_name))) {
-+              printk("network device %s does not exist, aborting.\n",
-+                              device_name);
-+              return -ENODEV;
-+      }
-+
-+      if (!dump_ndev->poll_controller) {
-+              printk("network device %s does not implement polling yet, "
-+                              "aborting.\n", device_name);
-+              retval = -1; /* return proper error */
-+              goto err1;
-+      }
-+
-+      if (!(dump_in_dev = in_dev_get(dump_ndev))) {
-+              printk("network device %s is not an IP protocol device, "
-+                              "aborting.\n", device_name);
-+              retval = -EINVAL;
-+              goto err1;
-+      }
-+
-+      if ((retval = dump_validate_config()) < 0)
-+              goto err2;
-+
-+      net_dev->curr_offset = 0;
-+      printk("Network device %s successfully configured for dumping\n",
-+                      device_name);
-+      return retval;
-+err2:
-+      in_dev_put(dump_in_dev);
-+err1:
-+      dev_put(dump_ndev);     
-+      return retval;
-+}
-+
-+/*
-+ * Close the dump device and release associated resources
-+ * Invoked when unconfiguring the dump device.
-+ */
-+static int
-+dump_net_release(struct dump_dev *net_dev)
-+{
-+      if (dump_in_dev)
-+              in_dev_put(dump_in_dev);
-+      if (dump_ndev)
-+              dev_put(dump_ndev);
-+      return 0;
-+}
-+
-+/*
-+ * Prepare the dump device for use (silence any ongoing activity
-+ * and quiesce state) when the system crashes.
-+ */
-+static int
-+dump_net_silence(struct dump_dev *net_dev)
-+{
-+      local_irq_save(flags_global);
-+      dump_ndev->rx_hook = dump_rx_hook;
-+        startup_handshake = 1;
-+      net_dev->curr_offset = 0;
-+      printk("Dumping to network device %s on CPU %d ...\n", device_name,
-+                      smp_processor_id());
-+      return 0;
-+}
-+
-+/*
-+ * Invoked when dumping is done. This is the time to put things back 
-+ * (i.e. undo the effects of dump_block_silence) so the device is 
-+ * available for normal use.
-+ */
-+static int
-+dump_net_resume(struct dump_dev *net_dev)
-+{
-+      int indx;
-+      reply_t reply;
-+      char tmp[200];
-+
-+        if (!dump_ndev)
-+              return (0);
-+
-+      sprintf(tmp, "NETDUMP end.\n");
-+      for( indx = 0; indx < 6; indx++) {
-+              reply.code = REPLY_END_NETDUMP;
-+              reply.nr = 0;
-+              reply.info = 0;
-+              dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
-+      }
-+      printk("NETDUMP END!\n");
-+      local_irq_restore(flags_global);
-+      dump_ndev->rx_hook = NULL;
-+      startup_handshake = 0;
-+      return 0;
-+}
-+
-+/*
-+ * Seek to the specified offset in the dump device.
-+ * Makes sure this is a valid offset, otherwise returns an error.
-+ */
-+static  int
-+dump_net_seek(struct dump_dev *net_dev, loff_t off)
-+{
-+      /*
-+       * For now using DUMP_HEADER_OFFSET as hard coded value,
-+       * See dump_block_seekin dump_blockdev.c to know how to
-+       * do this properly.
-+       */
-+      net_dev->curr_offset = off + DUMP_HEADER_OFFSET;
-+      return 0;
-+}
-+
-+/*
-+ *
-+ */
-+static int
-+dump_net_write(struct dump_dev *net_dev, void *buf, unsigned long len)
-+{
-+      int cnt, i, off;
-+      ssize_t ret;
-+
-+      cnt = len/ PAGE_SIZE;
-+
-+      for (i = 0; i < cnt; i++) {
-+              off = i* PAGE_SIZE;
-+              ret = do_netdump(net_dev, buf+off, PAGE_SIZE);
-+              if (ret <= 0)
-+                      return -1;
-+              net_dev->curr_offset = net_dev->curr_offset + PAGE_SIZE;
-+      }
-+      return len;
-+}
-+
-+/*
-+ * check if the last dump i/o is over and ready for next request
-+ */
-+static int
-+dump_net_ready(struct dump_dev *net_dev, void *buf)
-+{
-+      return 0;
-+}
-+
-+/*
-+ * ioctl function used for configuring network dump
-+ */
-+static int
-+dump_net_ioctl(struct dump_dev *net_dev, unsigned int cmd, unsigned long arg)
-+{
-+      switch (cmd) {
-+      case DIOSTARGETIP:
-+              target_ip = arg;
-+              break;
-+      case DIOSTARGETPORT:
-+              target_port = (u16)arg;
-+              break;
-+      case DIOSSOURCEPORT:
-+              source_port = (u16)arg;
-+              break;
-+      case DIOSETHADDR:
-+              return copy_from_user(daddr, (void *)arg, 6);
-+              break;
-+      case DIOGTARGETIP:
-+      case DIOGTARGETPORT:
-+      case DIOGSOURCEPORT:
-+      case DIOGETHADDR:
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+      return 0;
-+}
-+
-+struct dump_dev_ops dump_netdev_ops = {
-+      .open           = dump_net_open,
-+      .release        = dump_net_release,
-+      .silence        = dump_net_silence,
-+      .resume         = dump_net_resume,
-+      .seek           = dump_net_seek,
-+      .write          = dump_net_write,
-+      /* .read not implemented */
-+      .ready          = dump_net_ready,
-+      .ioctl          = dump_net_ioctl
-+};
-+
-+static struct dump_dev default_dump_netdev = {
-+      .type_name = "networkdev", 
-+      .ops = &dump_netdev_ops, 
-+      .curr_offset = 0
-+};
-+
-+static int __init
-+dump_netdev_init(void)
-+{
-+        default_dump_netdev.curr_offset = 0;
-+
-+      if (dump_register_device(&default_dump_netdev) < 0) {
-+              printk("network dump device driver registration failed\n");
-+              return -1;
-+      }
-+      printk("network device driver for LKCD registered\n");
-+ 
-+      get_random_bytes(&dump_magic, sizeof(dump_magic));
-+      return 0;
-+}
-+
-+static void __exit
-+dump_netdev_cleanup(void)
-+{
-+      dump_unregister_device(&default_dump_netdev);
-+}
-+
-+MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
-+MODULE_DESCRIPTION("Network Dump Driver for Linux Kernel Crash Dump (LKCD)");
-+MODULE_LICENSE("GPL");
-+
-+module_init(dump_netdev_init);
-+module_exit(dump_netdev_cleanup);
-Index: linux-2.6.0-test5/drivers/dump/dump_overlay.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_overlay.c 2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_overlay.c      2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,848 @@
-+/*
-+ * Two-stage soft-boot based dump scheme methods (memory overlay
-+ * with post soft-boot writeout)
-+ *
-+ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
-+ *
-+ * This approach of saving the dump in memory and writing it 
-+ * out after a softboot without clearing memory is derived from the 
-+ * Mission Critical Linux dump implementation. Credits and a big
-+ * thanks for letting the lkcd project make use of the excellent 
-+ * piece of work and also for helping with clarifications and 
-+ * tips along the way are due to:
-+ *    Dave Winchell <winchell@mclx.com> (primary author of mcore)
-+ *    and also to
-+ *    Jeff Moyer <moyer@mclx.com>
-+ *    Josh Huber <huber@mclx.com>
-+ * 
-+ * For those familiar with the mcore implementation, the key 
-+ * differences/extensions here are in allowing entire memory to be 
-+ * saved (in compressed form) through a careful ordering scheme 
-+ * on both the way down as well on the way up after boot, the latter
-+ * for supporting the LKCD notion of passes in which most critical 
-+ * data is the first to be saved to the dump device. Also the post 
-+ * boot writeout happens from within the kernel rather than driven 
-+ * from userspace.
-+ *
-+ * The sequence is orchestrated through the abstraction of "dumpers",
-+ * one for the first stage which then sets up the dumper for the next 
-+ * stage, providing for a smooth and flexible reuse of the singlestage 
-+ * dump scheme methods and a handle to pass dump device configuration 
-+ * information across the soft boot. 
-+ *
-+ * Copyright (C) 2002 International Business Machines Corp. 
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+/*
-+ * Disruptive dumping using the second kernel soft-boot option
-+ * for issuing dump i/o operates in 2 stages:
-+ * 
-+ * (1) - Saves the (compressed & formatted) dump in memory using a 
-+ *       carefully ordered overlay scheme designed to capture the 
-+ *       entire physical memory or selective portions depending on 
-+ *       dump config settings, 
-+ *     - Registers the stage 2 dumper and 
-+ *     - Issues a soft reboot w/o clearing memory. 
-+ *
-+ *     The overlay scheme starts with a small bootstrap free area
-+ *     and follows a reverse ordering of passes wherein it 
-+ *     compresses and saves data starting with the least critical 
-+ *     areas first, thus freeing up the corresponding pages to 
-+ *     serve as destination for subsequent data to be saved, and
-+ *     so on. With a good compression ratio, this makes it feasible
-+ *     to capture an entire physical memory dump without significantly
-+ *     reducing memory available during regular operation.
-+ *
-+ * (2) Post soft-reboot, runs through the saved memory dump and
-+ *     writes it out to disk, this time around, taking care to
-+ *     save the more critical data first (i.e. pages which figure 
-+ *     in early passes for a regular dump). Finally issues a 
-+ *     clean reboot.
-+ *     
-+ *     Since the data was saved in memory after selection/filtering
-+ *     and formatted as per the chosen output dump format, at this 
-+ *     stage the filter and format actions are just dummy (or
-+ *     passthrough) actions, except for influence on ordering of
-+ *     passes.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/highmem.h>
-+#include <linux/bootmem.h>
-+#include <linux/dump.h>
-+#include "dump_methods.h"
-+
-+extern struct list_head dumper_list_head;
-+extern struct dump_memdev *dump_memdev;
-+extern struct dumper dumper_stage2;
-+struct dump_config_block *dump_saved_config = NULL;
-+extern struct dump_blockdev *dump_blockdev;
-+static struct dump_memdev *saved_dump_memdev = NULL;
-+static struct dumper *saved_dumper = NULL;
-+
-+/* For testing 
-+extern void dump_display_map(struct dump_memdev *);
-+*/
-+
-+struct dumper *dumper_by_name(char *name)
-+{
-+#ifdef LATER
-+      struct dumper *dumper;
-+      list_for_each_entry(dumper, &dumper_list_head, dumper_list)
-+              if (!strncmp(dumper->name, name, 32))
-+                      return dumper;
-+
-+      /* not found */
-+      return NULL; 
-+#endif
-+      /* Temporary proof of concept */
-+      if (!strncmp(dumper_stage2.name, name, 32))
-+              return &dumper_stage2;
-+      else
-+              return NULL;
-+}
-+
-+#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
-+extern void dump_early_reserve_map(struct dump_memdev *);
-+
-+void crashdump_reserve(void)
-+{
-+      extern unsigned long crashdump_addr;
-+
-+      if (crashdump_addr == 0xdeadbeef) 
-+              return;
-+
-+      /* reserve dump config and saved dump pages */
-+      dump_saved_config = (struct dump_config_block *)crashdump_addr;
-+      /* magic verification */
-+      if (dump_saved_config->magic != DUMP_MAGIC_LIVE) {
-+              printk("Invalid dump magic. Ignoring dump\n");
-+              dump_saved_config = NULL;
-+              return;
-+      }
-+                      
-+      printk("Dump may be available from previous boot\n");
-+
-+      reserve_bootmem(virt_to_phys((void *)crashdump_addr), 
-+              PAGE_ALIGN(sizeof(struct dump_config_block)));
-+      dump_early_reserve_map(&dump_saved_config->memdev);
-+
-+}
-+#endif
-+
-+/* 
-+ * Loads the dump configuration from a memory block saved across soft-boot
-+ * The ops vectors need fixing up as the corresp. routines may have 
-+ * relocated in the new soft-booted kernel.
-+ */
-+int dump_load_config(struct dump_config_block *config)
-+{
-+      struct dumper *dumper;
-+      struct dump_data_filter *filter_table, *filter;
-+      struct dump_dev *dev;
-+      int i;
-+
-+      if (config->magic != DUMP_MAGIC_LIVE)
-+              return -ENOENT; /* not a valid config */
-+
-+      /* initialize generic config data */
-+      memcpy(&dump_config, &config->config, sizeof(dump_config));
-+
-+      /* initialize dumper state */
-+      if (!(dumper = dumper_by_name(config->dumper.name)))  {
-+              printk("dumper name mismatch\n");
-+              return -ENOENT; /* dumper mismatch */
-+      }
-+      
-+      /* verify and fixup schema */
-+      if (strncmp(dumper->scheme->name, config->scheme.name, 32)) {
-+              printk("dumper scheme mismatch\n");
-+              return -ENOENT; /* mismatch */
-+      }
-+      config->scheme.ops = dumper->scheme->ops;
-+      config->dumper.scheme = &config->scheme;
-+      
-+      /* verify and fixup filter operations */
-+      filter_table = dumper->filter;
-+      for (i = 0, filter = config->filter_table; 
-+              ((i < MAX_PASSES) && filter_table[i].selector); 
-+              i++, filter++) {
-+              if (strncmp(filter_table[i].name, filter->name, 32)) {
-+                      printk("dump filter mismatch\n");
-+                      return -ENOENT; /* filter name mismatch */
-+              }
-+              filter->selector = filter_table[i].selector;
-+      }
-+      config->dumper.filter = config->filter_table;
-+
-+      /* fixup format */
-+      if (strncmp(dumper->fmt->name, config->fmt.name, 32)) {
-+              printk("dump format mismatch\n");
-+              return -ENOENT; /* mismatch */
-+      }
-+      config->fmt.ops = dumper->fmt->ops;
-+      config->dumper.fmt = &config->fmt;
-+
-+      /* fixup target device */
-+      dev = (struct dump_dev *)(&config->dev[0]);
-+      if (dumper->dev == NULL) {
-+              pr_debug("Vanilla dumper - assume default\n");
-+              if (dump_dev == NULL)
-+                      return -ENODEV;
-+              dumper->dev = dump_dev;
-+      }
-+
-+      if (strncmp(dumper->dev->type_name, dev->type_name, 32)) { 
-+              printk("dump dev type mismatch %s instead of %s\n",
-+                              dev->type_name, dumper->dev->type_name);
-+              return -ENOENT; /* mismatch */
-+      }
-+      dev->ops = dumper->dev->ops; 
-+      config->dumper.dev = dev;
-+      
-+      /* fixup memory device containing saved dump pages */
-+      /* assume statically init'ed dump_memdev */
-+      config->memdev.ddev.ops = dump_memdev->ddev.ops; 
-+      /* switch to memdev from prev boot */
-+      saved_dump_memdev = dump_memdev; /* remember current */
-+      dump_memdev = &config->memdev;
-+
-+      /* Make this the current primary dumper */
-+      dump_config.dumper = &config->dumper;
-+
-+      return 0;
-+}
-+
-+/* Saves the dump configuration in a memory block for use across a soft-boot */
-+int dump_save_config(struct dump_config_block *config)
-+{
-+      printk("saving dump config settings\n");
-+
-+      /* dump config settings */
-+      memcpy(&config->config, &dump_config, sizeof(dump_config));
-+
-+      /* dumper state */
-+      memcpy(&config->dumper, dump_config.dumper, sizeof(struct dumper));
-+      memcpy(&config->scheme, dump_config.dumper->scheme, 
-+              sizeof(struct dump_scheme));
-+      memcpy(&config->fmt, dump_config.dumper->fmt, sizeof(struct dump_fmt));
-+      memcpy(&config->dev[0], dump_config.dumper->dev, 
-+              sizeof(struct dump_anydev));
-+      memcpy(&config->filter_table, dump_config.dumper->filter, 
-+              sizeof(struct dump_data_filter)*MAX_PASSES);
-+
-+      /* handle to saved mem pages */
-+      memcpy(&config->memdev, dump_memdev, sizeof(struct dump_memdev));
-+
-+      config->magic = DUMP_MAGIC_LIVE;
-+      
-+      return 0;
-+}
-+
-+int dump_init_stage2(struct dump_config_block *saved_config)
-+{
-+      int err = 0;
-+
-+      pr_debug("dump_init_stage2\n");
-+      /* Check if dump from previous boot exists */
-+      if (saved_config) {
-+              printk("loading dumper from previous boot \n");
-+              /* load and configure dumper from previous boot */
-+              if ((err = dump_load_config(saved_config)))
-+                      return err;
-+
-+              if (!dump_oncpu) {
-+                      if ((err = dump_configure(dump_config.dump_device))) {
-+                              printk("Stage 2 dump configure failed\n");
-+                              return err;
-+                      }
-+              }
-+
-+              dumper_reset();
-+              dump_dev = dump_config.dumper->dev;
-+              /* write out the dump */
-+              err = dump_generic_execute(NULL, NULL);
-+              
-+              dump_saved_config = NULL;
-+
-+              if (!dump_oncpu) {
-+                      dump_unconfigure(); 
-+              }
-+              
-+              return err;
-+
-+      } else {
-+              /* no dump to write out */
-+              printk("no dumper from previous boot \n");
-+              return 0;
-+      }
-+}
-+
-+extern void dump_mem_markpages(struct dump_memdev *);
-+
-+int dump_switchover_stage(void)
-+{
-+      int ret = 0;
-+
-+      /* trigger stage 2 rightaway - in real life would be after soft-boot */
-+      /* dump_saved_config would be a boot param */
-+      saved_dump_memdev = dump_memdev;
-+      saved_dumper = dump_config.dumper;
-+      ret = dump_init_stage2(dump_saved_config);
-+      dump_memdev = saved_dump_memdev;
-+      dump_config.dumper = saved_dumper;
-+      return ret;
-+}
-+
-+int dump_activate_softboot(void) 
-+{
-+      int err = 0;
-+
-+      /* temporary - switchover to writeout previously saved dump */
-+      err = dump_switchover_stage(); /* non-disruptive case */
-+      if (dump_oncpu) 
-+              dump_config.dumper = &dumper_stage1; /* set things back */
-+
-+      return err;
-+
-+      dump_silence_level = DUMP_HALT_CPUS;
-+      /* wait till we become the only cpu */
-+      /* maybe by checking for online cpus ? */
-+
-+      /* now call into kexec */
-+
-+      /* TBD/Fixme: 
-+       * should we call reboot notifiers ? inappropriate for panic ?  
-+       * what about device_shutdown() ? 
-+       * is explicit bus master disabling needed or can we do that
-+       * through driverfs ? 
-+       */
-+      return 0;
-+}
-+
-+/* --- DUMP SCHEME ROUTINES  --- */
-+
-+static inline int dump_buf_pending(struct dumper *dumper)
-+{
-+      return (dumper->curr_buf - dumper->dump_buf);
-+}
-+
-+/* Invoked during stage 1 of soft-reboot based dumping */
-+int dump_overlay_sequencer(void)
-+{
-+      struct dump_data_filter *filter = dump_config.dumper->filter;
-+      struct dump_data_filter *filter2 = dumper_stage2.filter;
-+      int pass = 0, err = 0, save = 0;
-+      int (*action)(unsigned long, unsigned long);
-+
-+      /* Make sure gzip compression is being used */
-+      if (dump_config.dumper->compress->compress_type != DUMP_COMPRESS_GZIP) {
-+              printk(" Please set GZIP compression \n");
-+              return -EINVAL;
-+      }
-+
-+      /* start filling in dump data right after the header */
-+      dump_config.dumper->curr_offset = 
-+              PAGE_ALIGN(dump_config.dumper->header_len);
-+
-+      /* Locate the last pass */
-+      for (;filter->selector; filter++, pass++);
-+      
-+      /* 
-+       * Start from the end backwards: overlay involves a reverse 
-+       * ordering of passes, since less critical pages are more
-+       * likely to be reusable as scratch space once we are through
-+       * with them. 
-+       */
-+      for (--pass, --filter; pass >= 0; pass--, filter--)
-+      {
-+              /* Assumes passes are exclusive (even across dumpers) */
-+              /* Requires care when coding the selection functions */
-+              if ((save = filter->level_mask & dump_config.level))
-+                      action = dump_save_data;
-+              else
-+                      action = dump_skip_data;
-+
-+              /* Remember the offset where this pass started */
-+              /* The second stage dumper would use this */
-+              if (dump_buf_pending(dump_config.dumper) & (PAGE_SIZE - 1)) {
-+                      pr_debug("Starting pass %d with pending data\n", pass);
-+                      pr_debug("filling dummy data to page-align it\n");
-+                      dump_config.dumper->curr_buf = (void *)PAGE_ALIGN(
-+                              (unsigned long)dump_config.dumper->curr_buf);
-+              }
-+              
-+              filter2[pass].start = dump_config.dumper->curr_offset
-+                      + dump_buf_pending(dump_config.dumper);
-+
-+              err = dump_iterator(pass, action, filter);
-+
-+              filter2[pass].end = dump_config.dumper->curr_offset
-+                      + dump_buf_pending(dump_config.dumper);
-+
-+              if (err < 0) {
-+                      printk("dump_overlay_seq: failure %d in pass %d\n", 
-+                              err, pass);
-+                      break;
-+              }       
-+              printk("\n %d overlay pages %s of %d each in pass %d\n", 
-+              err, save ? "saved" : "skipped", DUMP_PAGE_SIZE, pass);
-+      }
-+
-+      return err;
-+}
-+
-+/* from dump_memdev.c */
-+extern struct page *dump_mem_lookup(struct dump_memdev *dev, unsigned long loc);
-+extern struct page *dump_mem_next_page(struct dump_memdev *dev);
-+
-+static inline struct page *dump_get_saved_page(loff_t loc)
-+{
-+      return (dump_mem_lookup(dump_memdev, loc >> PAGE_SHIFT));
-+}
-+
-+static inline struct page *dump_next_saved_page(void)
-+{
-+      return (dump_mem_next_page(dump_memdev));
-+}
-+
-+/* 
-+ * Iterates over list of saved dump pages. Invoked during second stage of 
-+ * soft boot dumping
-+ *
-+ * Observation: If additional selection is desired at this stage then
-+ * a different iterator could be written which would advance 
-+ * to the next page header everytime instead of blindly picking up
-+ * the data. In such a case loc would be interpreted differently. 
-+ * At this moment however a blind pass seems sufficient, cleaner and
-+ * faster.
-+ */
-+int dump_saved_data_iterator(int pass, int (*action)(unsigned long, 
-+      unsigned long), struct dump_data_filter *filter)
-+{
-+      loff_t loc = filter->start;
-+      struct page *page;
-+      unsigned long count = 0;
-+      int err = 0;
-+      unsigned long sz;
-+
-+      printk("pass %d, start off 0x%llx end offset 0x%llx\n", pass,
-+                      filter->start, filter->end);
-+
-+      /* loc will get treated as logical offset into stage 1 */
-+      page = dump_get_saved_page(loc);
-+                      
-+      for (; loc < filter->end; loc += PAGE_SIZE) {
-+              dump_config.dumper->curr_loc = loc;
-+              if (!page) {
-+                      printk("no more saved data for pass %d\n", pass);
-+                      break;
-+              }
-+              sz = (loc + PAGE_SIZE > filter->end) ? filter->end - loc :
-+                      PAGE_SIZE;
-+
-+              if (page && filter->selector(pass, (unsigned long)page, 
-+                      PAGE_SIZE))  {
-+                      pr_debug("mem offset 0x%llx\n", loc);
-+                      if ((err = action((unsigned long)page, sz))) 
-+                              break;
-+                      else
-+                              count++;
-+                      /* clear the contents of page */
-+                      /* fixme: consider using KM_DUMP instead */
-+                      clear_highpage(page);
-+                      
-+              }
-+              page = dump_next_saved_page();
-+      }
-+
-+      return err ? err : count;
-+}
-+
-+static inline int dump_overlay_pages_done(struct page *page, int nr)
-+{
-+      int ret=0;
-+
-+      for (; nr ; page++, nr--) {
-+              if (dump_check_and_free_page(dump_memdev, page))
-+                      ret++;
-+      }
-+      return ret;
-+}
-+
-+int dump_overlay_save_data(unsigned long loc, unsigned long len)
-+{
-+      int err = 0;
-+      struct page *page = (struct page *)loc;
-+      static unsigned long cnt = 0;
-+
-+      if ((err = dump_generic_save_data(loc, len)))
-+              return err;
-+
-+      if (dump_overlay_pages_done(page, len >> PAGE_SHIFT)) {
-+              cnt++;
-+              if (!(cnt & 0x7f))
-+                      pr_debug("released page 0x%lx\n", page_to_pfn(page));
-+      }
-+      
-+      return err;
-+}
-+
-+
-+int dump_overlay_skip_data(unsigned long loc, unsigned long len)
-+{
-+      struct page *page = (struct page *)loc;
-+
-+      dump_overlay_pages_done(page, len >> PAGE_SHIFT);
-+      return 0;
-+}
-+
-+int dump_overlay_resume(void)
-+{
-+      int err = 0;
-+
-+      /* 
-+       * switch to stage 2 dumper, save dump_config_block
-+       * and then trigger a soft-boot
-+       */
-+      dumper_stage2.header_len = dump_config.dumper->header_len;
-+      dump_config.dumper = &dumper_stage2;
-+      if ((err = dump_save_config(dump_saved_config)))
-+              return err;
-+
-+      dump_dev = dump_config.dumper->dev;
-+
-+      return err;
-+      err = dump_switchover_stage();  /* plugs into soft boot mechanism */
-+      dump_config.dumper = &dumper_stage1; /* set things back */
-+      return err;
-+}
-+
-+int dump_overlay_configure(unsigned long devid)
-+{
-+      struct dump_dev *dev;
-+      struct dump_config_block *saved_config = dump_saved_config;
-+      int err = 0;
-+
-+      /* If there is a previously saved dump, write it out first */
-+      if (saved_config) {
-+              printk("Processing old dump pending writeout\n");
-+              err = dump_switchover_stage();
-+              if (err) {
-+                      printk("failed to writeout saved dump\n");
-+                      return err;
-+              }
-+              dump_free_mem(saved_config); /* testing only: not after boot */
-+      }
-+
-+      dev = dumper_stage2.dev = dump_config.dumper->dev;
-+      /* From here on the intermediate dump target is memory-only */
-+      dump_dev = dump_config.dumper->dev = &dump_memdev->ddev;
-+      if ((err = dump_generic_configure(0))) {
-+              printk("dump generic configure failed: err %d\n", err);
-+              return err;
-+      }
-+      /* temporary */
-+      dumper_stage2.dump_buf = dump_config.dumper->dump_buf;
-+
-+      /* Sanity check on the actual target dump device */
-+      if (!dev || (err = dev->ops->open(dev, devid))) {
-+              return err;
-+      }
-+      /* TBD: should we release the target if this is soft-boot only ? */
-+
-+      /* alloc a dump config block area to save across reboot */
-+      if (!(dump_saved_config = dump_alloc_mem(sizeof(struct 
-+              dump_config_block)))) {
-+              printk("dump config block alloc failed\n");
-+              /* undo configure */
-+              dump_generic_unconfigure();
-+              return -ENOMEM;
-+      }
-+      dump_config.dump_addr = (unsigned long)dump_saved_config;
-+      printk("Dump config block of size %d set up at 0x%lx\n", 
-+              sizeof(*dump_saved_config), (unsigned long)dump_saved_config);
-+      return 0;
-+}
-+
-+int dump_overlay_unconfigure(void)
-+{
-+      struct dump_dev *dev = dumper_stage2.dev;
-+      int err = 0;
-+
-+      pr_debug("dump_overlay_unconfigure\n");
-+      /* Close the secondary device */
-+      dev->ops->release(dev); 
-+      pr_debug("released secondary device\n");
-+
-+      err = dump_generic_unconfigure();
-+      pr_debug("Unconfigured generic portions\n");
-+      dump_free_mem(dump_saved_config);
-+      dump_saved_config = NULL;
-+      pr_debug("Freed saved config block\n");
-+      dump_dev = dump_config.dumper->dev = dumper_stage2.dev;
-+
-+      printk("Unconfigured overlay dumper\n");
-+      return err;
-+}
-+
-+int dump_staged_unconfigure(void)
-+{
-+      int err = 0;
-+      struct dump_config_block *saved_config = dump_saved_config;
-+      struct dump_dev *dev;
-+
-+      pr_debug("dump_staged_unconfigure\n");
-+      err = dump_generic_unconfigure();
-+
-+      /* now check if there is a saved dump waiting to be written out */
-+      if (saved_config) {
-+              printk("Processing saved dump pending writeout\n");
-+              if ((err = dump_switchover_stage())) {
-+                      printk("Error in commiting saved dump at 0x%lx\n", 
-+                              (unsigned long)saved_config);
-+                      printk("Old dump may hog memory\n");
-+              } else {
-+                      dump_free_mem(saved_config);
-+                      pr_debug("Freed saved config block\n");
-+              }
-+              dump_saved_config = NULL;
-+      } else {
-+              dev = &dump_memdev->ddev;
-+              dev->ops->release(dev);
-+      }
-+      printk("Unconfigured second stage dumper\n");
-+
-+      return 0;
-+}
-+
-+/* ----- PASSTHRU FILTER ROUTINE --------- */
-+
-+/* transparent - passes everything through */
-+int dump_passthru_filter(int pass, unsigned long loc, unsigned long sz)
-+{
-+      return 1;
-+}
-+
-+/* ----- PASSTRU FORMAT ROUTINES ---- */
-+
-+
-+int dump_passthru_configure_header(const char *panic_str, const struct pt_regs *regs)
-+{
-+      dump_config.dumper->header_dirty++;
-+      return 0;
-+}
-+
-+/* Copies bytes of data from page(s) to the specified buffer */
-+int dump_copy_pages(void *buf, struct page *page, unsigned long sz)
-+{
-+      unsigned long len = 0, bytes;
-+      void *addr;
-+
-+      while (len < sz) {
-+              addr = kmap_atomic(page, KM_DUMP);
-+              bytes = (sz > len + PAGE_SIZE) ? PAGE_SIZE : sz - len;  
-+              memcpy(buf, addr, bytes); 
-+              kunmap_atomic(addr, KM_DUMP);
-+              buf += bytes;
-+              len += bytes;
-+              page++;
-+      }
-+      /* memset(dump_config.dumper->curr_buf, 0x57, len); temporary */
-+
-+      return sz - len;
-+}
-+
-+int dump_passthru_update_header(void)
-+{
-+      long len = dump_config.dumper->header_len;
-+      struct page *page;
-+      void *buf = dump_config.dumper->dump_buf;
-+      int err = 0;
-+
-+      if (!dump_config.dumper->header_dirty)
-+              return 0;
-+
-+      pr_debug("Copying header of size %ld bytes from memory\n", len);
-+      if (len > DUMP_BUFFER_SIZE) 
-+              return -E2BIG;
-+
-+      page = dump_mem_lookup(dump_memdev, 0);
-+      for (; (len > 0) && page; buf += PAGE_SIZE, len -= PAGE_SIZE) {
-+              if ((err = dump_copy_pages(buf, page, PAGE_SIZE)))
-+                      return err;
-+              page = dump_mem_next_page(dump_memdev);
-+      }
-+      if (len > 0) {
-+              printk("Incomplete header saved in mem\n");
-+              return -ENOENT;
-+      }
-+
-+      if ((err = dump_dev_seek(0))) {
-+              printk("Unable to seek to dump header offset\n");
-+              return err;
-+      }
-+      err = dump_ll_write(dump_config.dumper->dump_buf, 
-+              buf - dump_config.dumper->dump_buf);
-+      if (err < dump_config.dumper->header_len)
-+              return (err < 0) ? err : -ENOSPC;
-+
-+      dump_config.dumper->header_dirty = 0;
-+      return 0;
-+}
-+
-+static loff_t next_dph_offset = 0;
-+
-+static int dph_valid(struct __dump_page *dph)
-+{
-+      if ((dph->dp_address & (PAGE_SIZE - 1)) || (dph->dp_flags 
-+            > DUMP_DH_COMPRESSED) || (!dph->dp_flags) ||
-+              (dph->dp_size > PAGE_SIZE)) {
-+      printk("dp->address = 0x%llx, dp->size = 0x%x, dp->flag = 0x%x\n",
-+              dph->dp_address, dph->dp_size, dph->dp_flags);
-+              return 0;
-+      }
-+      return 1;
-+}
-+
-+int dump_verify_lcrash_data(void *buf, unsigned long sz)
-+{
-+      struct __dump_page *dph;
-+
-+      /* sanity check for page headers */
-+      while (next_dph_offset + sizeof(*dph) < sz) {
-+              dph = (struct __dump_page *)(buf + next_dph_offset);
-+              if (!dph_valid(dph)) {
-+                      printk("Invalid page hdr at offset 0x%llx\n",
-+                              next_dph_offset);
-+                      return -EINVAL;
-+              }
-+              next_dph_offset += dph->dp_size + sizeof(*dph);
-+      }
-+
-+      next_dph_offset -= sz;  
-+      return 0;
-+}
-+
-+/* 
-+ * TBD/Later: Consider avoiding the copy by using a scatter/gather 
-+ * vector representation for the dump buffer
-+ */
-+int dump_passthru_add_data(unsigned long loc, unsigned long sz)
-+{
-+      struct page *page = (struct page *)loc;
-+      void *buf = dump_config.dumper->curr_buf;
-+      int err = 0;
-+
-+      if ((err = dump_copy_pages(buf, page, sz))) {
-+              printk("dump_copy_pages failed");
-+              return err;
-+      }
-+
-+      if ((err = dump_verify_lcrash_data(buf, sz))) {
-+              printk("dump_verify_lcrash_data failed\n");
-+              printk("Invalid data for pfn 0x%lx\n", page_to_pfn(page));
-+              printk("Page flags 0x%lx\n", page->flags);
-+              printk("Page count 0x%x\n", atomic_read(&page->count));
-+              return err;
-+      }
-+
-+      dump_config.dumper->curr_buf = buf + sz;
-+
-+      return 0;
-+}
-+
-+
-+/* Stage 1 dumper: Saves compressed dump in memory and soft-boots system */
-+
-+/* Scheme to overlay saved data in memory for writeout after a soft-boot */
-+struct dump_scheme_ops dump_scheme_overlay_ops = {
-+      .configure      = dump_overlay_configure,
-+      .unconfigure    = dump_overlay_unconfigure,
-+      .sequencer      = dump_overlay_sequencer,
-+      .iterator       = dump_page_iterator,
-+      .save_data      = dump_overlay_save_data,
-+      .skip_data      = dump_overlay_skip_data,
-+      .write_buffer   = dump_generic_write_buffer
-+};
-+
-+struct dump_scheme dump_scheme_overlay = {
-+      .name           = "overlay",
-+      .ops            = &dump_scheme_overlay_ops
-+};
-+
-+
-+/* Stage 1 must use a good compression scheme - default to gzip */
-+extern struct __dump_compress dump_gzip_compression;
-+
-+struct dumper dumper_stage1 = {
-+      .name           = "stage1",
-+      .scheme         = &dump_scheme_overlay,
-+      .fmt            = &dump_fmt_lcrash,
-+      .compress       = &dump_none_compression, /* needs to be gzip */
-+      .filter         = dump_filter_table,
-+      .dev            = NULL,
-+};            
-+
-+/* Stage 2 dumper: Activated after softboot to write out saved dump to device */
-+
-+/* Formatter that transfers data as is (transparent) w/o further conversion */
-+struct dump_fmt_ops dump_fmt_passthru_ops = {
-+      .configure_header       = dump_passthru_configure_header,
-+      .update_header          = dump_passthru_update_header,
-+      .save_context           = NULL, /* unused */
-+      .add_data               = dump_passthru_add_data,
-+      .update_end_marker      = dump_lcrash_update_end_marker
-+};
-+
-+struct dump_fmt dump_fmt_passthru = {
-+      .name   = "passthru",
-+      .ops    = &dump_fmt_passthru_ops
-+};
-+
-+/* Filter that simply passes along any data within the range (transparent)*/
-+/* Note: The start and end ranges in the table are filled in at run-time */
-+
-+extern int dump_filter_none(int pass, unsigned long loc, unsigned long sz);
-+
-+struct dump_data_filter dump_passthru_filtertable[MAX_PASSES] = {
-+{.name = "passkern", .selector = dump_passthru_filter, 
-+      .level_mask = DUMP_MASK_KERN },
-+{.name = "passuser", .selector = dump_passthru_filter, 
-+      .level_mask = DUMP_MASK_USED },
-+{.name = "passunused", .selector = dump_passthru_filter, 
-+      .level_mask = DUMP_MASK_UNUSED },
-+{.name = "none", .selector = dump_filter_none, 
-+      .level_mask = DUMP_MASK_REST }
-+};
-+
-+
-+/* Scheme to handle data staged / preserved across a soft-boot */
-+struct dump_scheme_ops dump_scheme_staged_ops = {
-+      .configure      = dump_generic_configure,
-+      .unconfigure    = dump_staged_unconfigure,
-+      .sequencer      = dump_generic_sequencer,
-+      .iterator       = dump_saved_data_iterator,
-+      .save_data      = dump_generic_save_data,
-+      .skip_data      = dump_generic_skip_data,
-+      .write_buffer   = dump_generic_write_buffer
-+};
-+
-+struct dump_scheme dump_scheme_staged = {
-+      .name           = "staged",
-+      .ops            = &dump_scheme_staged_ops
-+};
-+
-+/* The stage 2 dumper comprising all these */
-+struct dumper dumper_stage2 = {
-+      .name           = "stage2",
-+      .scheme         = &dump_scheme_staged,
-+      .fmt            = &dump_fmt_passthru,
-+      .compress       = &dump_none_compression,
-+      .filter         = dump_passthru_filtertable,
-+      .dev            = NULL,
-+};            
-+
-Index: linux-2.6.0-test5/drivers/dump/dump_rle.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_rle.c     2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_rle.c  2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,175 @@
-+/*
-+ * RLE Compression functions for kernel crash dumps.
-+ *
-+ * Created by: Matt Robinson (yakker@sourceforge.net)
-+ * Copyright 2001 Matt D. Robinson.  All rights reserved.
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+/* header files */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/file.h>
-+#include <linux/init.h>
-+#include <linux/dump.h>
-+
-+/*
-+ * Name: dump_compress_rle()
-+ * Func: Compress a DUMP_PAGE_SIZE (hardware) page down to something more
-+ *       reasonable, if possible.  This is the same routine we use in IRIX.
-+ */
-+static u16
-+dump_compress_rle(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
-+{
-+      u16 ri, wi, count = 0;
-+      u_char value = 0, cur_byte;
-+
-+      /*
-+       * If the block should happen to "compress" to larger than the
-+       * buffer size, allocate a larger one and change cur_buf_size.
-+       */
-+
-+      wi = ri = 0;
-+
-+      while (ri < oldsize) {
-+              if (!ri) {
-+                      cur_byte = value = old[ri];
-+                      count = 0;
-+              } else {
-+                      if (count == 255) {
-+                              if (wi + 3 > oldsize) {
-+                                      return oldsize;
-+                              }
-+                              new[wi++] = 0;
-+                              new[wi++] = count;
-+                              new[wi++] = value;
-+                              value = cur_byte = old[ri];
-+                              count = 0;
-+                      } else { 
-+                              if ((cur_byte = old[ri]) == value) {
-+                                      count++;
-+                              } else {
-+                                      if (count > 1) {
-+                                              if (wi + 3 > oldsize) {
-+                                                      return oldsize;
-+                                              }
-+                                              new[wi++] = 0;
-+                                              new[wi++] = count;
-+                                              new[wi++] = value;
-+                                      } else if (count == 1) {
-+                                              if (value == 0) {
-+                                                      if (wi + 3 > oldsize) {
-+                                                              return oldsize;
-+                                                      }
-+                                                      new[wi++] = 0;
-+                                                      new[wi++] = 1;
-+                                                      new[wi++] = 0;
-+                                              } else {
-+                                                      if (wi + 2 > oldsize) {
-+                                                              return oldsize;
-+                                                      }
-+                                                      new[wi++] = value;
-+                                                      new[wi++] = value;
-+                                              }
-+                                      } else { /* count == 0 */
-+                                              if (value == 0) {
-+                                                      if (wi + 2 > oldsize) {
-+                                                              return oldsize;
-+                                                      }
-+                                                      new[wi++] = value;
-+                                                      new[wi++] = value;
-+                                              } else {
-+                                                      if (wi + 1 > oldsize) {
-+                                                              return oldsize;
-+                                                      }
-+                                                      new[wi++] = value;
-+                                              }
-+                                      } /* if count > 1 */
-+
-+                                      value = cur_byte;
-+                                      count = 0;
-+
-+                              } /* if byte == value */
-+
-+                      } /* if count == 255 */
-+
-+              } /* if ri == 0 */
-+              ri++;
-+
-+      }
-+      if (count > 1) {
-+              if (wi + 3 > oldsize) {
-+                      return oldsize;
-+              }
-+              new[wi++] = 0;
-+              new[wi++] = count;
-+              new[wi++] = value;
-+      } else if (count == 1) {
-+              if (value == 0) {
-+                      if (wi + 3 > oldsize)
-+                              return oldsize;
-+                      new[wi++] = 0;
-+                      new[wi++] = 1;
-+                      new[wi++] = 0;
-+              } else {
-+                      if (wi + 2 > oldsize)
-+                              return oldsize;
-+                      new[wi++] = value;
-+                      new[wi++] = value;
-+              }
-+      } else { /* count == 0 */
-+              if (value == 0) {
-+                      if (wi + 2 > oldsize)
-+                              return oldsize;
-+                      new[wi++] = value;
-+                      new[wi++] = value;
-+              } else {
-+                      if (wi + 1 > oldsize)
-+                              return oldsize;
-+                      new[wi++] = value;
-+              }
-+      } /* if count > 1 */
-+
-+      value = cur_byte;
-+      count = 0;
-+      return wi;
-+}
-+
-+/* setup the rle compression functionality */
-+static struct __dump_compress dump_rle_compression = {
-+      .compress_type = DUMP_COMPRESS_RLE,
-+      .compress_func = dump_compress_rle,
-+      .compress_name = "RLE",
-+};
-+
-+/*
-+ * Name: dump_compress_rle_init()
-+ * Func: Initialize rle compression for dumping.
-+ */
-+static int __init
-+dump_compress_rle_init(void)
-+{
-+      dump_register_compression(&dump_rle_compression);
-+      return 0;
-+}
-+
-+/*
-+ * Name: dump_compress_rle_cleanup()
-+ * Func: Remove rle compression for dumping.
-+ */
-+static void __exit
-+dump_compress_rle_cleanup(void)
-+{
-+      dump_unregister_compression(DUMP_COMPRESS_RLE);
-+}
-+
-+/* module initialization */
-+module_init(dump_compress_rle_init);
-+module_exit(dump_compress_rle_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
-+MODULE_DESCRIPTION("RLE compression module for crash dump driver");
-Index: linux-2.6.0-test5/drivers/dump/dump_scheme.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_scheme.c  2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_scheme.c       2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,357 @@
-+/* 
-+ * Default single stage dump scheme methods
-+ *
-+ * Previously a part of dump_base.c
-+ *
-+ * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
-+ *    Split and rewrote LKCD dump scheme to generic dump method 
-+ *    interfaces 
-+ * Derived from original code created by
-+ *    Matt Robinson <yakker@sourceforge.net>)
-+ *
-+ * Contributions from SGI, IBM, HP, MCL, and others.
-+ *
-+ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
-+ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
-+ * Copyright (C) 2002 International Business Machines Corp. 
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+/*
-+ * Implements the default dump scheme, i.e. single-stage gathering and 
-+ * saving of dump data directly to the target device, which operates in
-+ * a push mode, where the dumping system decides what data it saves
-+ * taking into account pre-specified dump config options.
-+ *
-+ * Aside: The 2-stage dump scheme, where there is a soft-reset between
-+ * the gathering and saving phases, also reuses some of these
-+ * default routines (see dump_overlay.c) 
-+ */ 
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/reboot.h>
-+#include <linux/nmi.h>
-+#include <linux/dump.h>
-+#include "dump_methods.h"
-+
-+extern int panic_timeout;  /* time before reboot */
-+
-+extern void dump_speedo(int);
-+
-+/* Default sequencer used during single stage dumping */
-+/* Also invoked during stage 2 of soft-boot based dumping */
-+int dump_generic_sequencer(void)
-+{
-+      struct dump_data_filter *filter = dump_config.dumper->filter;
-+      int pass = 0, err = 0, save = 0;
-+      int (*action)(unsigned long, unsigned long);
-+
-+      /* 
-+       * We want to save the more critical data areas first in 
-+       * case we run out of space, encounter i/o failures, or get
-+       * interrupted otherwise and have to give up midway
-+       * So, run through the passes in increasing order 
-+       */
-+      for (;filter->selector; filter++, pass++)
-+      {
-+              /* Assumes passes are exclusive (even across dumpers) */
-+              /* Requires care when coding the selection functions */
-+              if ((save = filter->level_mask & dump_config.level))
-+                      action = dump_save_data;
-+              else
-+                      action = dump_skip_data;
-+
-+              if ((err = dump_iterator(pass, action, filter)) < 0)
-+                      break;
-+
-+              printk("\n %d dump pages %s of %d each in pass %d\n", 
-+              err, save ? "saved" : "skipped", DUMP_PAGE_SIZE, pass);
-+
-+      }
-+
-+      return (err < 0) ? err : 0;
-+}
-+
-+static inline struct page *dump_get_page(loff_t loc)
-+{
-+      unsigned long page_index = loc >> PAGE_SHIFT;
-+
-+      /* todo: complete this  to account for ia64/discontig mem */
-+      /* todo: and to check for validity, ram page, no i/o mem etc */
-+      /* need to use pfn/physaddr equiv of kern_addr_valid */
-+      if (__dump_page_valid(page_index))
-+              return pfn_to_page(page_index);
-+      else
-+              return NULL;
-+
-+}
-+
-+/* Default iterator: for singlestage and stage 1 of soft-boot dumping */
-+/* Iterates over range of physical memory pages in DUMP_PAGE_SIZE increments */
-+int dump_page_iterator(int pass, int (*action)(unsigned long, unsigned long), 
-+      struct dump_data_filter *filter)
-+{
-+      /* Todo : fix unit, type */
-+      loff_t loc;
-+      int count = 0, err = 0;
-+      struct page *page;
-+
-+      /* Todo: Add membanks code */
-+      /* TBD: Check if we need to address DUMP_PAGE_SIZE < PAGE_SIZE */       
-+      
-+      for (loc = filter->start; loc < filter->end; loc += DUMP_PAGE_SIZE) {
-+              dump_config.dumper->curr_loc = loc;
-+              page = dump_get_page(loc);
-+              if (page && filter->selector(pass, (unsigned long) page, 
-+              DUMP_PAGE_SIZE)) {
-+                      if ((err = action((unsigned long)page, DUMP_PAGE_SIZE)))
-+                      {
-+                              printk("dump_page_iterator: err %d for loc "
-+                              "0x%llx, in pass %d\n", err, loc, pass);
-+                              break;
-+                      } else
-+                              count++;
-+              }
-+      }
-+
-+      return err ? err : count;
-+}
-+
-+/* 
-+ * Base function that saves the selected block of data in the dump 
-+ * Action taken when iterator decides that data needs to be saved 
-+ */
-+int dump_generic_save_data(unsigned long loc, unsigned long sz)
-+{
-+      void *buf;
-+      void *dump_buf = dump_config.dumper->dump_buf;
-+      int left, bytes, ret;
-+
-+      if ((ret = dump_add_data(loc, sz))) {
-+              return ret;
-+      }
-+      buf = dump_config.dumper->curr_buf;
-+
-+      /* If we've filled up the buffer write it out */
-+      if ((left = buf - dump_buf) >= DUMP_BUFFER_SIZE) {
-+              bytes = dump_write_buffer(dump_buf, DUMP_BUFFER_SIZE);
-+              if (bytes < DUMP_BUFFER_SIZE) {
-+                      printk("dump_write_buffer failed %d\n", bytes);
-+                      return bytes ? -ENOSPC : bytes;
-+              }
-+
-+              left -= bytes;
-+              
-+              /* -- A few chores to do from time to time -- */
-+              dump_config.dumper->count++;
-+
-+              if (!(dump_config.dumper->count & 0x3f)) {
-+                      /* Update the header every one in a while */
-+                      memset((void *)dump_buf, 'b', DUMP_BUFFER_SIZE);
-+                      if ((ret = dump_update_header()) < 0) {
-+                              /* issue warning */
-+                              return ret;
-+                      }
-+                      printk(".");
-+
-+                      touch_nmi_watchdog();
-+              } else if (!(dump_config.dumper->count & 0x7)) {
-+                      /* Show progress so the user knows we aren't hung */
-+                      dump_speedo(dump_config.dumper->count >> 3); 
-+              }
-+              /* Todo: Touch/Refresh watchdog */
-+
-+              /* --- Done with periodic chores -- */
-+
-+              /* 
-+               * extra bit of copying to simplify verification  
-+               * in the second kernel boot based scheme
-+               */
-+              memcpy(dump_buf - DUMP_PAGE_SIZE, dump_buf + 
-+                      DUMP_BUFFER_SIZE - DUMP_PAGE_SIZE, DUMP_PAGE_SIZE);
-+
-+              /* now adjust the leftover bits back to the top of the page */
-+              /* this case would not arise during stage 2 (passthru) */
-+              memset(dump_buf, 'z', DUMP_BUFFER_SIZE);
-+              if (left) {
-+                      memcpy(dump_buf, dump_buf + DUMP_BUFFER_SIZE, left);
-+              }
-+              buf -= DUMP_BUFFER_SIZE;
-+              dump_config.dumper->curr_buf = buf;
-+      }
-+                              
-+      return 0;
-+}
-+
-+int dump_generic_skip_data(unsigned long loc, unsigned long sz)
-+{
-+      /* dummy by default */
-+      return 0;
-+}
-+
-+/* 
-+ * Common low level routine to write a buffer to current dump device 
-+ * Expects checks for space etc to have been taken care of by the caller 
-+ * Operates serially at the moment for simplicity. 
-+ * TBD/Todo: Consider batching for improved throughput
-+ */
-+int dump_ll_write(void *buf, unsigned long len)
-+{
-+      long transferred = 0, last_transfer = 0;
-+      int ret = 0;
-+
-+      /* make sure device is ready */
-+      while ((ret = dump_dev_ready(NULL)) == -EAGAIN);
-+      if  (ret < 0) {
-+              printk("dump_dev_ready failed !err %d\n", ret);
-+              return ret;
-+      }
-+
-+      while (len) {
-+              if ((last_transfer = dump_dev_write(buf, len)) <= 0)  {
-+                      ret = last_transfer;
-+                      printk("dump_dev_write failed !err %d\n", 
-+                      ret);
-+                      break;
-+              }
-+              /* wait till complete */
-+              while ((ret = dump_dev_ready(buf)) == -EAGAIN)
-+                      cpu_relax();
-+
-+              if  (ret < 0) {
-+                      printk("i/o failed !err %d\n", ret);
-+                      break;
-+              }
-+
-+              len -= last_transfer;
-+              buf += last_transfer;
-+              transferred += last_transfer;
-+      }
-+      return (ret < 0) ? ret : transferred;
-+}
-+
-+/* default writeout routine for single dump device */
-+/* writes out the dump data ensuring enough space is left for the end marker */
-+int dump_generic_write_buffer(void *buf, unsigned long len)
-+{
-+      long written = 0;
-+      int err = 0;
-+
-+      /* check for space */
-+      if ((err = dump_dev_seek(dump_config.dumper->curr_offset + len + 
-+                      2*DUMP_BUFFER_SIZE)) < 0) {
-+              printk("dump_write_buffer: insuff space after offset 0x%llx\n",
-+                      dump_config.dumper->curr_offset);
-+              return err;
-+      }
-+      /* alignment check would happen as a side effect of this */
-+      if ((err = dump_dev_seek(dump_config.dumper->curr_offset)) < 0)
-+              return err; 
-+
-+      written = dump_ll_write(buf, len);
-+
-+      /* all or none */
-+
-+      if (written < len)
-+              written = written ? -ENOSPC : written;
-+      else
-+              dump_config.dumper->curr_offset += len;
-+
-+      return written;
-+}
-+
-+int dump_generic_configure(unsigned long devid)
-+{
-+      struct dump_dev *dev = dump_config.dumper->dev;
-+      struct dump_data_filter *filter;
-+      void *buf;
-+      int ret = 0;
-+
-+      /* Allocate the dump buffer and initialize dumper state */
-+      /* Assume that we get aligned addresses */
-+      if (!(buf = dump_alloc_mem(DUMP_BUFFER_SIZE + 3 * DUMP_PAGE_SIZE)))
-+              return -ENOMEM;
-+
-+      if ((unsigned long)buf & (PAGE_SIZE - 1)) {
-+              /* sanity check for page aligned address */
-+              dump_free_mem(buf);
-+              return -ENOMEM; /* fixme: better error code */
-+      }
-+
-+      /* Initialize the rest of the fields */
-+      dump_config.dumper->dump_buf = buf + DUMP_PAGE_SIZE;
-+      dumper_reset();
-+
-+      /* Open the dump device */
-+      if (!dev)
-+              return -ENODEV;
-+
-+      if ((ret = dev->ops->open(dev, devid))) {
-+             return ret;
-+      }
-+
-+      /* Initialise the memory ranges in the dump filter */
-+      for (filter = dump_config.dumper->filter ;filter->selector; filter++) {
-+              if (!filter->start && !filter->end) {
-+                      filter->start = 0;
-+                      filter->end = num_physpages << PAGE_SHIFT;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+int dump_generic_unconfigure(void)
-+{
-+      struct dump_dev *dev = dump_config.dumper->dev;
-+      void *buf = dump_config.dumper->dump_buf;
-+      int ret = 0;
-+
-+      pr_debug("Generic unconfigure\n");
-+      /* Close the dump device */
-+      if (dev && (ret = dev->ops->release(dev)))
-+              return ret;
-+
-+      printk("Closed dump device\n");
-+      
-+      if (buf)
-+              dump_free_mem((buf - DUMP_PAGE_SIZE));
-+
-+      dump_config.dumper->curr_buf = dump_config.dumper->dump_buf = NULL;
-+      pr_debug("Released dump buffer\n");
-+
-+      return 0;
-+}
-+
-+
-+/* Set up the default dump scheme */
-+
-+struct dump_scheme_ops dump_scheme_singlestage_ops = {
-+      .configure      = dump_generic_configure,
-+      .unconfigure    = dump_generic_unconfigure,
-+      .sequencer      = dump_generic_sequencer,
-+      .iterator       = dump_page_iterator,
-+      .save_data      = dump_generic_save_data,
-+      .skip_data      = dump_generic_skip_data,
-+      .write_buffer   = dump_generic_write_buffer,
-+};
-+
-+struct dump_scheme dump_scheme_singlestage = {
-+      .name           = "single-stage",
-+      .ops            = &dump_scheme_singlestage_ops
-+};
-+
-+/* The single stage dumper comprising all these */
-+struct dumper dumper_singlestage = {
-+      .name           = "single-stage",
-+      .scheme         = &dump_scheme_singlestage,
-+      .fmt            = &dump_fmt_lcrash,
-+      .compress       = &dump_none_compression,
-+      .filter         = dump_filter_table,
-+      .dev            = NULL,
-+};            
-+
-Index: linux-2.6.0-test5/drivers/dump/dump_setup.c
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_setup.c   2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_setup.c        2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,803 @@
-+/*
-+ * Standard kernel function entry points for Linux crash dumps.
-+ *
-+ * Created by: Matt Robinson (yakker@sourceforge.net)
-+ * Contributions from SGI, IBM, HP, MCL, and others.
-+ *
-+ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
-+ * Copyright (C) 2000 - 2002 TurboLinux, Inc.  All rights reserved.
-+ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
-+ * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+/*
-+ * -----------------------------------------------------------------------
-+ *
-+ * DUMP HISTORY
-+ *
-+ * This dump code goes back to SGI's first attempts at dumping system
-+ * memory on SGI systems running IRIX.  A few developers at SGI needed
-+ * a way to take this system dump and analyze it, and created 'icrash',
-+ * or IRIX Crash.  The mechanism (the dumps and 'icrash') were used
-+ * by support people to generate crash reports when a system failure
-+ * occurred.  This was vital for large system configurations that
-+ * couldn't apply patch after patch after fix just to hope that the
-+ * problems would go away.  So the system memory, along with the crash
-+ * dump analyzer, allowed support people to quickly figure out what the
-+ * problem was on the system with the crash dump.
-+ *
-+ * In comes Linux.  SGI started moving towards the open source community,
-+ * and upon doing so, SGI wanted to take its support utilities into Linux
-+ * with the hopes that they would end up the in kernel and user space to
-+ * be used by SGI's customers buying SGI Linux systems.  One of the first
-+ * few products to be open sourced by SGI was LKCD, or Linux Kernel Crash
-+ * Dumps.  LKCD comprises of a patch to the kernel to enable system
-+ * dumping, along with 'lcrash', or Linux Crash, to analyze the system
-+ * memory dump.  A few additional system scripts and kernel modifications
-+ * are also included to make the dump mechanism and dump data easier to
-+ * process and use.
-+ *
-+ * As soon as LKCD was released into the open source community, a number
-+ * of larger companies started to take advantage of it.  Today, there are
-+ * many community members that contribute to LKCD, and it continues to
-+ * flourish and grow as an open source project.
-+ */
-+
-+/*
-+ * DUMP TUNABLES
-+ *
-+ * This is the list of system tunables (via /proc) that are available
-+ * for Linux systems.  All the read, write, etc., functions are listed
-+ * here.  Currently, there are a few different tunables for dumps:
-+ *
-+ * dump_device (used to be dumpdev):
-+ *     The device for dumping the memory pages out to.  This 
-+ *     may be set to the primary swap partition for disruptive dumps,
-+ *     and must be an unused partition for non-disruptive dumps.
-+ *     Todo: In the case of network dumps, this may be interpreted 
-+ *     as the IP address of the netdump server to connect to.
-+ *
-+ * dump_compress (used to be dump_compress_pages):
-+ *     This is the flag which indicates which compression mechanism
-+ *     to use.  This is a BITMASK, not an index (0,1,2,4,8,16,etc.).
-+ *     This is the current set of values:
-+ *
-+ *     0: DUMP_COMPRESS_NONE -- Don't compress any pages.
-+ *     1: DUMP_COMPRESS_RLE  -- This uses RLE compression.
-+ *     2: DUMP_COMPRESS_GZIP -- This uses GZIP compression.
-+ *
-+ * dump_level:
-+ *     The amount of effort the dump module should make to save
-+ *     information for post crash analysis.  This value is now
-+ *     a BITMASK value, not an index:
-+ *
-+ *     0:   Do nothing, no dumping. (DUMP_LEVEL_NONE)
-+ *
-+ *     1:   Print out the dump information to the dump header, and
-+ *          write it out to the dump_device. (DUMP_LEVEL_HEADER)
-+ *
-+ *     2:   Write out the dump header and all kernel memory pages.
-+ *          (DUMP_LEVEL_KERN)
-+ *
-+ *     4:   Write out the dump header and all kernel and user
-+ *          memory pages.  (DUMP_LEVEL_USED)
-+ *
-+ *     8:   Write out the dump header and all conventional/cached 
-+ *        memory (RAM) pages in the system (kernel, user, free).  
-+ *        (DUMP_LEVEL_ALL_RAM)
-+ *
-+ *    16:   Write out everything, including non-conventional memory
-+ *        like firmware, proms, I/O registers, uncached memory.
-+ *        (DUMP_LEVEL_ALL)
-+ *
-+ *     The dump_level will default to 1.
-+ *
-+ * dump_flags:
-+ *     These are the flags to use when talking about dumps.  There
-+ *     are lots of possibilities.  This is a BITMASK value, not an index.
-+ * 
-+ * -----------------------------------------------------------------------
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/reboot.h>
-+#include <linux/fs.h>
-+#include <linux/dump.h>
-+#include "dump_methods.h"
-+#include <linux/proc_fs.h>
-+#include <linux/module.h>
-+#include <linux/utsname.h>
-+#include <linux/highmem.h>
-+#include <linux/major.h>
-+#include <linux/sysrq.h>
-+#include <linux/sysctl.h>
-+#include <linux/nmi.h>
-+
-+#include <asm/hardirq.h>
-+#include <asm/uaccess.h>
-+
-+/*
-+ * -----------------------------------------------------------------------
-+ *                         V A R I A B L E S
-+ * -----------------------------------------------------------------------
-+ */
-+
-+/* Dump tunables */
-+struct dump_config dump_config = {
-+      .level          = 0,
-+      .flags          = 0,
-+      .dump_device    = 0,
-+      .dump_addr      = 0,
-+      .dumper         = NULL
-+};
-+
-+
-+/* Global variables used in dump.h */
-+/* degree of system freeze when dumping */
-+enum dump_silence_levels dump_silence_level = DUMP_HARD_SPIN_CPUS;     
-+
-+/* Other global fields */
-+extern struct __dump_header dump_header; 
-+struct dump_dev *dump_dev = NULL;  /* Active dump device                   */
-+static int dump_compress = 0;
-+
-+static u16 dump_compress_none(const u8 *old, u16 oldsize, u8 *new, u16 newsize);
-+struct __dump_compress dump_none_compression = {
-+      .compress_type  = DUMP_COMPRESS_NONE,
-+      .compress_func  = dump_compress_none,
-+      .compress_name  = "none",
-+};
-+
-+/* our device operations and functions */
-+static int dump_ioctl(struct inode *i, struct file *f,
-+      unsigned int cmd, unsigned long arg);
-+
-+static struct file_operations dump_fops = {
-+      .ioctl          =       dump_ioctl,
-+};
-+
-+/* static variables                                                   */
-+static int dump_okay = 0;             /* can we dump out to disk?     */
-+static spinlock_t dump_lock = SPIN_LOCK_UNLOCKED;
-+
-+/* used for dump compressors */
-+static struct list_head dump_compress_list = LIST_HEAD_INIT(dump_compress_list);
-+
-+/* list of registered dump targets */
-+static struct list_head dump_target_list = LIST_HEAD_INIT(dump_target_list);
-+
-+/* lkcd info structure -- this is used by lcrash for basic system data     */
-+struct __lkcdinfo lkcdinfo = {
-+      .ptrsz          = (sizeof(void *) * 8),
-+#if defined(__LITTLE_ENDIAN) 
-+      .byte_order     = __LITTLE_ENDIAN,
-+#else
-+      .byte_order     = __BIG_ENDIAN,
-+#endif
-+      .page_shift     = PAGE_SHIFT,
-+      .page_size      = PAGE_SIZE,
-+      .page_mask      = PAGE_MASK,
-+      .page_offset    = PAGE_OFFSET,
-+};
-+
-+/*
-+ * -----------------------------------------------------------------------
-+ *            / P R O C   T U N A B L E   F U N C T I O N S
-+ * -----------------------------------------------------------------------
-+ */
-+
-+static int proc_dump_device(ctl_table *ctl, int write, struct file *f,
-+                          void *buffer, size_t *lenp);
-+
-+static int proc_doulonghex(ctl_table *ctl, int write, struct file *f,
-+                          void *buffer, size_t *lenp);
-+/*
-+ * sysctl-tuning infrastructure.
-+ */
-+static ctl_table dump_table[] = {
-+      { .ctl_name = CTL_DUMP_LEVEL,
-+        .procname = DUMP_LEVEL_NAME, 
-+        .data = &dump_config.level,    
-+        .maxlen = sizeof(int),
-+        .mode = 0644,
-+        .proc_handler = proc_doulonghex, },
-+
-+      { .ctl_name = CTL_DUMP_FLAGS,
-+        .procname = DUMP_FLAGS_NAME,
-+        .data = &dump_config.flags,   
-+        .maxlen = sizeof(int),
-+        .mode = 0644,
-+        .proc_handler = proc_doulonghex, },
-+
-+      { .ctl_name = CTL_DUMP_COMPRESS,
-+        .procname = DUMP_COMPRESS_NAME,
-+        .data = &dump_compress, /* FIXME */
-+        .maxlen = sizeof(int),
-+        .mode = 0644,
-+        .proc_handler = proc_dointvec, },
-+        
-+      { .ctl_name = CTL_DUMP_DEVICE,
-+        .procname = DUMP_DEVICE_NAME,
-+        .mode = 0644,
-+        .data = &dump_config.dump_device, /* FIXME */
-+        .maxlen = sizeof(int),
-+        .proc_handler = proc_dump_device },
-+
-+#ifdef CONFIG_CRASH_DUMP_MEMDEV
-+      { .ctl_name = CTL_DUMP_ADDR,
-+        .procname = DUMP_ADDR_NAME,
-+        .mode = 0444,
-+        .data = &dump_config.dump_addr,
-+        .maxlen = sizeof(unsigned long),
-+        .proc_handler = proc_doulonghex },
-+#endif
-+
-+      { 0, }
-+};
-+
-+static ctl_table dump_root[] = {
-+      { .ctl_name = KERN_DUMP,
-+        .procname = "dump",
-+        .mode = 0555, 
-+        .child = dump_table },
-+      { 0, }
-+};
-+
-+static ctl_table kernel_root[] = {
-+      { .ctl_name = CTL_KERN,
-+        .procname = "kernel",
-+        .mode = 0555,
-+        .child = dump_root, },
-+      { 0, }
-+};
-+
-+static struct ctl_table_header *sysctl_header;
-+
-+/*
-+ * -----------------------------------------------------------------------
-+ *              C O M P R E S S I O N   F U N C T I O N S
-+ * -----------------------------------------------------------------------
-+ */
-+
-+/*
-+ * Name: dump_compress_none()
-+ * Func: Don't do any compression, period.
-+ */
-+static u16
-+dump_compress_none(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
-+{
-+      /* just return the old size */
-+      return oldsize;
-+}
-+
-+
-+/*
-+ * Name: dump_execute()
-+ * Func: Execute the dumping process.  This makes sure all the appropriate
-+ *       fields are updated correctly, and calls dump_execute_memdump(),
-+ *       which does the real work.
-+ */
-+void
-+dump_execute(const char *panic_str, const struct pt_regs *regs)
-+{
-+      int state = -1;
-+      unsigned long flags;
-+
-+      /* make sure we can dump */
-+      if (!dump_okay) {
-+              pr_info("LKCD not yet configured, can't take dump now\n");
-+              return;
-+      }
-+
-+      /* Exclude multiple dumps at the same time,
-+       * and disable interrupts,  some drivers may re-enable
-+       * interrupts in with silence()
-+       *
-+       * Try and acquire spin lock. If successful, leave preempt
-+       * and interrupts disabled.  See spin_lock_irqsave in spinlock.h
-+       */
-+      local_irq_save(flags);
-+      if (!spin_trylock(&dump_lock)) {
-+              local_irq_restore(flags);
-+              pr_info("LKCD dump already in progress\n");
-+              return;
-+      }
-+
-+      /* Bring system into the strictest level of quiescing for min drift 
-+       * dump drivers can soften this as required in dev->ops->silence() 
-+       */
-+      dump_oncpu = smp_processor_id() + 1;
-+      dump_silence_level = DUMP_HARD_SPIN_CPUS; 
-+
-+      state = dump_generic_execute(panic_str, regs);
-+      
-+      dump_oncpu = 0;
-+      spin_unlock_irqrestore(&dump_lock, flags);
-+
-+      if (state < 0) {
-+              printk("Dump Incomplete or failed!\n");
-+      } else {
-+              printk("Dump Complete; %d dump pages saved.\n", 
-+                     dump_header.dh_num_dump_pages);
-+      }
-+}
-+
-+/*
-+ * Name: dump_register_compression()
-+ * Func: Register a dump compression mechanism.
-+ */
-+void
-+dump_register_compression(struct __dump_compress *item)
-+{
-+      if (item)
-+              list_add(&(item->list), &dump_compress_list);
-+}
-+
-+/*
-+ * Name: dump_unregister_compression()
-+ * Func: Remove a dump compression mechanism, and re-assign the dump
-+ *       compression pointer if necessary.
-+ */
-+void
-+dump_unregister_compression(int compression_type)
-+{
-+      struct list_head *tmp;
-+      struct __dump_compress *dc;
-+
-+      /* let's make sure our list is valid */
-+      if (compression_type != DUMP_COMPRESS_NONE) {
-+              list_for_each(tmp, &dump_compress_list) {
-+                      dc = list_entry(tmp, struct __dump_compress, list);
-+                      if (dc->compress_type == compression_type) {
-+                              list_del(&(dc->list));
-+                              break;
-+                      }
-+              }
-+      }
-+}
-+
-+/*
-+ * Name: dump_compress_init()
-+ * Func: Initialize (or re-initialize) compression scheme.
-+ */
-+static int
-+dump_compress_init(int compression_type)
-+{
-+      struct list_head *tmp;
-+      struct __dump_compress *dc;
-+
-+      /* try to remove the compression item */
-+      list_for_each(tmp, &dump_compress_list) {
-+              dc = list_entry(tmp, struct __dump_compress, list);
-+              if (dc->compress_type == compression_type) {
-+                      dump_config.dumper->compress = dc;
-+                      dump_compress = compression_type;
-+                      pr_debug("Dump Compress %s\n", dc->compress_name);
-+                      return 0;
-+              }
-+      }
-+
-+      /* 
-+       * nothing on the list -- return ENODATA to indicate an error 
-+       *
-+       * NB: 
-+       *      EAGAIN: reports "Resource temporarily unavailable" which
-+       *              isn't very enlightening.
-+       */
-+      printk("compression_type:%d not found\n", compression_type);
-+
-+      return -ENODATA;
-+}
-+
-+static int
-+dumper_setup(unsigned long flags, unsigned long devid)
-+{
-+      int ret = 0;
-+
-+      /* unconfigure old dumper if it exists */
-+      dump_okay = 0;
-+      if (dump_config.dumper) {
-+              pr_debug("Unconfiguring current dumper\n");
-+              dump_unconfigure();
-+      }
-+      /* set up new dumper */
-+      if (dump_config.flags & DUMP_FLAGS_SOFTBOOT) {
-+              printk("Configuring softboot based dump \n");
-+#ifdef CONFIG_CRASH_DUMP_MEMDEV
-+              dump_config.dumper = &dumper_stage1; 
-+#else
-+              printk("Requires CONFIG_CRASHDUMP_MEMDEV. Can't proceed.\n");
-+              return -1;
-+#endif
-+      } else {
-+              dump_config.dumper = &dumper_singlestage;
-+      }       
-+      dump_config.dumper->dev = dump_dev;
-+
-+      ret = dump_configure(devid);
-+      if (!ret) {
-+              dump_okay = 1;
-+              pr_debug("%s dumper set up for dev 0x%lx\n", 
-+                      dump_config.dumper->name, devid);
-+              dump_config.dump_device = devid;
-+      } else {
-+              printk("%s dumper set up failed for dev 0x%lx\n", 
-+                     dump_config.dumper->name, devid);
-+              dump_config.dumper = NULL;
-+      }
-+      return ret;
-+}
-+
-+static int
-+dump_target_init(int target)
-+{
-+      char type[20];
-+      struct list_head *tmp;
-+      struct dump_dev *dev;
-+      
-+      switch (target) {
-+              case DUMP_FLAGS_DISKDUMP:
-+                      strcpy(type, "blockdev"); break;
-+              case DUMP_FLAGS_NETDUMP:
-+                      strcpy(type, "networkdev"); break;
-+              default:
-+                      return -1;
-+      }
-+
-+      /*
-+       * This is a bit stupid, generating strings from flag
-+       * and doing strcmp. This is done because 'struct dump_dev'
-+       * has string 'type_name' and not interger 'type'.
-+       */
-+      list_for_each(tmp, &dump_target_list) {
-+              dev = list_entry(tmp, struct dump_dev, list);
-+              if (strcmp(type, dev->type_name) == 0) {
-+                      dump_dev = dev;
-+                      return 0;
-+              }
-+      }
-+      return -1;
-+}
-+
-+/*
-+ * Name: dump_ioctl()
-+ * Func: Allow all dump tunables through a standard ioctl() mechanism.
-+ *       This is far better than before, where we'd go through /proc,
-+ *       because now this will work for multiple OS and architectures.
-+ */
-+static int
-+dump_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
-+{
-+      /* check capabilities */
-+      if (!capable(CAP_SYS_ADMIN))
-+              return -EPERM;
-+
-+      if (!dump_config.dumper && cmd == DIOSDUMPCOMPRESS)
-+              /* dump device must be configured first */
-+              return -ENODEV;
-+
-+      /*
-+       * This is the main mechanism for controlling get/set data
-+       * for various dump device parameters.  The real trick here
-+       * is setting the dump device (DIOSDUMPDEV).  That's what
-+       * triggers everything else.
-+       */
-+      switch (cmd) {
-+      case DIOSDUMPDEV:       /* set dump_device */
-+              pr_debug("Configuring dump device\n"); 
-+              if (!(f->f_flags & O_RDWR))
-+                      return -EPERM;
-+
-+              __dump_open();
-+              return dumper_setup(dump_config.flags, arg);
-+
-+              
-+      case DIOGDUMPDEV:       /* get dump_device */
-+              return put_user((long)dump_config.dump_device, (long *)arg);
-+
-+      case DIOSDUMPLEVEL:     /* set dump_level */
-+              if (!(f->f_flags & O_RDWR))
-+                      return -EPERM;
-+
-+              /* make sure we have a positive value */
-+              if (arg < 0)
-+                      return -EINVAL;
-+
-+              /* Fixme: clean this up */
-+              dump_config.level = 0;
-+              switch ((int)arg) {
-+                      case DUMP_LEVEL_ALL:
-+                      case DUMP_LEVEL_ALL_RAM:
-+                              dump_config.level |= DUMP_MASK_UNUSED;
-+                      case DUMP_LEVEL_USED:
-+                              dump_config.level |= DUMP_MASK_USED;
-+                      case DUMP_LEVEL_KERN:
-+                              dump_config.level |= DUMP_MASK_KERN;
-+                      case DUMP_LEVEL_HEADER:
-+                              dump_config.level |= DUMP_MASK_HEADER;
-+                      case DUMP_LEVEL_NONE:
-+                              break;
-+                      default:
-+                              return (-EINVAL);
-+                      }
-+              pr_debug("Dump Level 0x%lx\n", dump_config.level);
-+              break;
-+
-+      case DIOGDUMPLEVEL:     /* get dump_level */
-+              /* fixme: handle conversion */
-+              return put_user((long)dump_config.level, (long *)arg);
-+
-+              
-+      case DIOSDUMPFLAGS:     /* set dump_flags */
-+              /* check flags */
-+              if (!(f->f_flags & O_RDWR))
-+                      return -EPERM;
-+
-+              /* make sure we have a positive value */
-+              if (arg < 0)
-+                      return -EINVAL;
-+                      
-+              if (dump_target_init(arg & DUMP_FLAGS_TARGETMASK) < 0)
-+                      return -EINVAL; /* return proper error */
-+
-+              dump_config.flags = arg;
-+              
-+              pr_debug("Dump Flags 0x%lx\n", dump_config.flags);
-+              break;
-+              
-+      case DIOGDUMPFLAGS:     /* get dump_flags */
-+              return put_user((long)dump_config.flags, (long *)arg);
-+
-+      case DIOSDUMPCOMPRESS:  /* set the dump_compress status */
-+              if (!(f->f_flags & O_RDWR))
-+                      return -EPERM;
-+
-+              return dump_compress_init((int)arg);
-+
-+      case DIOGDUMPCOMPRESS:  /* get the dump_compress status */
-+              return put_user((long)(dump_config.dumper ? 
-+                      dump_config.dumper->compress->compress_type : 0), 
-+                      (long *)arg);
-+                      
-+      default:
-+              /* 
-+               * these are network dump specific ioctls, let the
-+               * module handle them.
-+               */
-+              return dump_dev_ioctl(cmd, arg);
-+      }
-+      return 0;
-+}
-+
-+/*
-+ * Handle special cases for dump_device 
-+ * changing dump device requires doing an opening the device
-+ */
-+static int 
-+proc_dump_device(ctl_table *ctl, int write, struct file *f,
-+               void *buffer, size_t *lenp)
-+{
-+      int *valp = ctl->data;
-+      int oval = *valp;
-+      int ret = -EPERM;
-+
-+      /* same permission checks as ioctl */
-+      if (capable(CAP_SYS_ADMIN)) {
-+              ret = proc_doulonghex(ctl, write, f, buffer, lenp);
-+              if (ret == 0 && write && *valp != oval) {
-+                      /* need to restore old value to close properly */
-+                      dump_config.dump_device = (dev_t) oval;
-+                      __dump_open();
-+                      ret = dumper_setup(dump_config.flags, (dev_t) *valp);
-+              }
-+      }
-+
-+      return ret;
-+}
-+
-+/* All for the want of a proc_do_xxx routine which prints values in hex */
-+static int 
-+proc_doulonghex(ctl_table *ctl, int write, struct file *f,
-+               void *buffer, size_t *lenp)
-+{
-+#define TMPBUFLEN 20
-+      unsigned long *i;
-+      size_t len, left;
-+      char buf[TMPBUFLEN];
-+
-+      if (!ctl->data || !ctl->maxlen || !*lenp || (f->f_pos)) {
-+              *lenp = 0;
-+              return 0;
-+      }
-+      
-+      i = (unsigned long *) ctl->data;
-+      left = *lenp;
-+      
-+      sprintf(buf, "0x%lx\n", (*i));
-+      len = strlen(buf);
-+      if (len > left)
-+              len = left;
-+      if(copy_to_user(buffer, buf, len))
-+              return -EFAULT;
-+      
-+      left -= len;
-+      *lenp -= left;
-+      f->f_pos += *lenp;
-+      return 0;
-+}
-+
-+/*
-+ * -----------------------------------------------------------------------
-+ *                     I N I T   F U N C T I O N S
-+ * -----------------------------------------------------------------------
-+ */
-+
-+/*
-+ * These register and unregister routines are exported for modules
-+ * to register their dump drivers (like block, net etc)
-+ */
-+int
-+dump_register_device(struct dump_dev *ddev)
-+{
-+      struct list_head *tmp;
-+      struct dump_dev *dev;
-+
-+      list_for_each(tmp, &dump_target_list) {
-+              dev = list_entry(tmp, struct dump_dev, list);
-+              if (strcmp(ddev->type_name, dev->type_name) == 0) {
-+                      printk("Target type %s already registered\n",
-+                                      dev->type_name);
-+                      return -1; /* return proper error */
-+              }
-+      }
-+      list_add(&(ddev->list), &dump_target_list);
-+      
-+      return 0;
-+}
-+
-+void
-+dump_unregister_device(struct dump_dev *ddev)
-+{
-+      list_del(&(ddev->list));
-+      if (ddev != dump_dev)
-+              return;
-+
-+      dump_okay = 0;
-+
-+      if (dump_config.dumper)
-+              dump_unconfigure();
-+
-+      dump_config.flags &= ~DUMP_FLAGS_TARGETMASK;
-+      dump_okay = 0;
-+      dump_dev = NULL;
-+      dump_config.dumper = NULL;
-+}
-+
-+static int panic_event(struct notifier_block *this, unsigned long event,
-+                     void *ptr)
-+{
-+      struct pt_regs regs;
-+
-+      get_current_regs(&regs);
-+      dump_execute((const char *)ptr, &regs);
-+      return 0;
-+}
-+
-+extern struct notifier_block *panic_notifier_list;
-+static int panic_event(struct notifier_block *, unsigned long, void *);
-+static struct notifier_block panic_block = {
-+      .notifier_call = panic_event,
-+};
-+
-+#ifdef CONFIG_MAGIC_SYSRQ
-+/* Sysrq handler */
-+static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
-+              struct tty_struct *tty) {
-+      dump_execute("sysrq", pt_regs);
-+}
-+
-+static struct sysrq_key_op sysrq_crashdump_op = {
-+      .handler        =       sysrq_handle_crashdump,
-+      .help_msg       =       "Dump",
-+      .action_msg     =       "Starting crash dump",
-+};
-+#endif
-+
-+static inline void
-+dump_sysrq_register(void) 
-+{
-+#ifdef CONFIG_MAGIC_SYSRQ
-+      __sysrq_lock_table();
-+      __sysrq_put_key_op(DUMP_SYSRQ_KEY, &sysrq_crashdump_op);
-+      __sysrq_unlock_table();
-+#endif
-+}
-+
-+static inline void
-+dump_sysrq_unregister(void)
-+{
-+#ifdef CONFIG_MAGIC_SYSRQ
-+      __sysrq_lock_table();
-+      if (__sysrq_get_key_op(DUMP_SYSRQ_KEY) == &sysrq_crashdump_op)
-+              __sysrq_put_key_op(DUMP_SYSRQ_KEY, NULL);
-+      __sysrq_unlock_table();
-+#endif
-+}
-+
-+/*
-+ * Name: dump_init()
-+ * Func: Initialize the dump process.  This will set up any architecture
-+ *       dependent code.  The big key is we need the memory offsets before
-+ *       the page table is initialized, because the base memory offset
-+ *       is changed after paging_init() is called.
-+ */
-+static int __init
-+dump_init(void)
-+{
-+      struct sysinfo info;
-+
-+      /* try to create our dump device */
-+      if (register_chrdev(CRASH_DUMP_MAJOR, "dump", &dump_fops)) {
-+              printk("cannot register dump character device!\n");
-+              return -EBUSY;
-+      }
-+
-+      __dump_init((u64)PAGE_OFFSET);
-+
-+      /* set the dump_compression_list structure up */
-+      dump_register_compression(&dump_none_compression);
-+
-+      /* grab the total memory size now (not if/when we crash) */
-+      si_meminfo(&info);
-+
-+      /* set the memory size */
-+      dump_header.dh_memory_size = (u64)info.totalram;
-+
-+      sysctl_header = register_sysctl_table(kernel_root, 0);
-+      dump_sysrq_register();
-+
-+      notifier_chain_register(&panic_notifier_list, &panic_block);
-+      dump_function_ptr = dump_execute;
-+
-+      pr_info("Crash dump driver initialized.\n");
-+      return 0;
-+}
-+
-+static void __exit
-+dump_cleanup(void)
-+{
-+      dump_okay = 0;
-+
-+      if (dump_config.dumper)
-+              dump_unconfigure();
-+
-+      /* arch-specific cleanup routine */
-+      __dump_cleanup();
-+
-+      /* ignore errors while unregistering -- since can't do anything */
-+      unregister_sysctl_table(sysctl_header);
-+      unregister_chrdev(CRASH_DUMP_MAJOR, "dump");
-+      dump_sysrq_unregister();
-+      notifier_chain_unregister(&panic_notifier_list, &panic_block);
-+      dump_function_ptr = NULL;
-+}
-+
-+EXPORT_SYMBOL(dump_register_compression);
-+EXPORT_SYMBOL(dump_unregister_compression);
-+EXPORT_SYMBOL(dump_register_device);
-+EXPORT_SYMBOL(dump_unregister_device);
-+EXPORT_SYMBOL(dump_config);
-+EXPORT_SYMBOL(dump_silence_level);
-+
-+EXPORT_SYMBOL(__dump_irq_enable);
-+EXPORT_SYMBOL(__dump_irq_restore);
-+
-+MODULE_AUTHOR("Matt D. Robinson <yakker@sourceforge.net>");
-+MODULE_DESCRIPTION("Linux Kernel Crash Dump (LKCD) driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(dump_init);
-+module_exit(dump_cleanup);
-Index: linux-2.6.0-test5/include/linux/dumpdev.h
-===================================================================
---- linux-2.6.0-test5.orig/include/linux/dumpdev.h     2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/include/linux/dumpdev.h  2003-09-26 14:27:08.000000000 +0800
-@@ -0,0 +1,161 @@
-+/*
-+ * Generic dump device interfaces for flexible system dump 
-+ * (Enables variation of dump target types e.g disk, network, memory)
-+ *
-+ * These interfaces have evolved based on discussions on lkcd-devel. 
-+ * Eventually the intent is to support primary and secondary or 
-+ * alternate targets registered at the same time, with scope for 
-+ * situation based failover or multiple dump devices used for parallel 
-+ * dump i/o.
-+ *
-+ * Started: Oct 2002 - Suparna Bhattacharya (suparna@in.ibm.com)
-+ *
-+ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
-+ * Copyright (C) 2002 International Business Machines Corp. 
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+#ifndef _LINUX_DUMPDEV_H
-+#define _LINUX_DUMPDEV_H
-+
-+#include <linux/kernel.h>
-+#include <linux/wait.h>
-+#include <linux/bio.h>
-+
-+/* Determined by the dump target (device) type */
-+
-+struct dump_dev;
-+
-+struct dump_dev_ops {
-+      int (*open)(struct dump_dev *, unsigned long); /* configure */
-+      int (*release)(struct dump_dev *); /* unconfigure */
-+      int (*silence)(struct dump_dev *); /* when dump starts */
-+      int (*resume)(struct dump_dev *); /* when dump is over */
-+      int (*seek)(struct dump_dev *, loff_t);
-+      /* trigger a write (async in nature typically) */
-+      int (*write)(struct dump_dev *, void *, unsigned long);
-+      /* not usually used during dump, but option available */
-+      int (*read)(struct dump_dev *, void *, unsigned long);
-+      /* use to poll for completion */
-+      int (*ready)(struct dump_dev *, void *); 
-+      int (*ioctl)(struct dump_dev *, unsigned int, unsigned long);
-+};
-+
-+struct dump_dev {
-+      char type_name[32]; /* block, net-poll etc */
-+      unsigned long device_id; /* interpreted differently for various types */
-+      struct dump_dev_ops *ops;
-+      struct list_head list;
-+      loff_t curr_offset;
-+};
-+
-+/*
-+ * dump_dev type variations: 
-+ */
-+
-+/* block */
-+struct dump_blockdev {
-+      struct dump_dev ddev;
-+      dev_t kdev_id;
-+      struct block_device *bdev;
-+      struct bio *bio;
-+      loff_t start_offset;
-+      loff_t limit;
-+      int err;
-+};
-+
-+static inline struct dump_blockdev *DUMP_BDEV(struct dump_dev *dev)
-+{
-+      return container_of(dev, struct dump_blockdev, ddev);
-+}
-+
-+
-+/* mem  - for internal use by soft-boot based dumper */
-+struct dump_memdev {
-+      struct dump_dev ddev;
-+      unsigned long indirect_map_root;
-+      unsigned long nr_free;
-+      struct page *curr_page;
-+      unsigned long *curr_map;
-+      unsigned long curr_map_offset;
-+      unsigned long last_offset;
-+      unsigned long last_used_offset;
-+      unsigned long last_bs_offset;
-+};    
-+
-+static inline struct dump_memdev *DUMP_MDEV(struct dump_dev *dev)
-+{
-+      return container_of(dev, struct dump_memdev, ddev);
-+}
-+
-+/* Todo/future - meant for raw dedicated interfaces e.g. mini-ide driver */
-+struct dump_rdev {
-+      struct dump_dev ddev;
-+      char name[32];
-+      int (*reset)(struct dump_rdev *, unsigned int, 
-+              unsigned long);
-+      /* ... to do ... */
-+};
-+
-+/* just to get the size right when saving config across a soft-reboot */
-+struct dump_anydev {
-+      union {
-+              struct dump_blockdev bddev;
-+              /* .. add other types here .. */
-+      };
-+};
-+
-+
-+
-+/* Dump device / target operation wrappers */
-+/* These assume that dump_dev is initiatized to dump_config.dumper->dev */
-+
-+extern struct dump_dev *dump_dev;
-+
-+static inline int dump_dev_open(unsigned long arg)
-+{
-+      return dump_dev->ops->open(dump_dev, arg);
-+}
-+
-+static inline int dump_dev_release(void)
-+{
-+      return dump_dev->ops->release(dump_dev);
-+}
-+
-+static inline int dump_dev_silence(void)
-+{
-+      return dump_dev->ops->silence(dump_dev);
-+}
-+
-+static inline int dump_dev_resume(void)
-+{
-+      return dump_dev->ops->resume(dump_dev);
-+}
-+
-+static inline int dump_dev_seek(loff_t offset)
-+{
-+      return dump_dev->ops->seek(dump_dev, offset);
-+}
-+
-+static inline int dump_dev_write(void *buf, unsigned long len)
-+{
-+      return dump_dev->ops->write(dump_dev, buf, len);
-+}
-+
-+static inline int dump_dev_ready(void *buf)
-+{
-+      return dump_dev->ops->ready(dump_dev, buf);
-+}
-+
-+static inline int dump_dev_ioctl(unsigned int cmd, unsigned long arg)
-+{
-+      if (!dump_dev->ops->ioctl)
-+              return -EINVAL;
-+      return dump_dev->ops->ioctl(dump_dev, cmd, arg);
-+}
-+
-+extern int dump_register_device(struct dump_dev *);
-+extern void dump_unregister_device(struct dump_dev *);
-+
-+#endif /*  _LINUX_DUMPDEV_H */
-Index: linux-2.6.0-test5/include/linux/dump.h
-===================================================================
---- linux-2.6.0-test5.orig/include/linux/dump.h        2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/include/linux/dump.h     2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,376 @@
-+/*
-+ * Kernel header file for Linux crash dumps.
-+ *
-+ * Created by: Matt Robinson (yakker@sgi.com)
-+ * Copyright 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
-+ *
-+ * vmdump.h to dump.h by: Matt D. Robinson (yakker@sourceforge.net)
-+ * Copyright 2001 - 2002 Matt D. Robinson.  All rights reserved.
-+ * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
-+ *
-+ * Most of this is the same old stuff from vmdump.h, except now we're
-+ * actually a stand-alone driver plugged into the block layer interface,
-+ * with the exception that we now allow for compression modes externally
-+ * loaded (e.g., someone can come up with their own).
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+/* This header file includes all structure definitions for crash dumps. */
-+#ifndef _DUMP_H
-+#define _DUMP_H
-+
-+#if defined(CONFIG_CRASH_DUMP) || defined (CONFIG_CRASH_DUMP_MODULE)
-+
-+#include <linux/list.h>
-+#include <linux/notifier.h>
-+#include <linux/dumpdev.h>
-+
-+/* 
-+ * Predefine default DUMP_PAGE constants, asm header may override.
-+ *
-+ * On ia64 discontinuous memory systems it's possible for the memory
-+ * banks to stop at 2**12 page alignments, the smallest possible page
-+ * size. But the system page size, PAGE_SIZE, is in fact larger.
-+ */
-+#define DUMP_PAGE_SHIFT       PAGE_SHIFT
-+#define DUMP_PAGE_MASK                PAGE_MASK
-+#define DUMP_PAGE_ALIGN(addr) PAGE_ALIGN(addr)
-+#define DUMP_HEADER_OFFSET    PAGE_SIZE
-+
-+/* keep DUMP_PAGE_SIZE constant to 4K = 1<<12
-+ * it may be different from PAGE_SIZE then.
-+ */
-+#define DUMP_PAGE_SIZE                4096
-+
-+/* 
-+ * Predefined default memcpy() to use when copying memory to the dump buffer.
-+ *
-+ * On ia64 there is a heads up function that can be called to let the prom
-+ * machine check monitor know that the current activity is risky and it should
-+ * ignore the fault (nofault). In this case the ia64 header will redefine this
-+ * macro to __dump_memcpy() and use it's arch specific version.
-+ */
-+#define DUMP_memcpy           memcpy
-+
-+/* necessary header files */
-+#include <asm/dump.h>                 /* for architecture-specific header */
-+
-+/* 
-+ * Size of the buffer that's used to hold:
-+ *
-+ *    1. the dump header (padded to fill the complete buffer)
-+ *    2. the possibly compressed page headers and data
-+ */
-+#define DUMP_BUFFER_SIZE      (64 * 1024)  /* size of dump buffer         */
-+#define DUMP_HEADER_SIZE      DUMP_BUFFER_SIZE
-+
-+/* standard header definitions */
-+#define DUMP_MAGIC_NUMBER     0xa8190173618f23edULL  /* dump magic number */
-+#define DUMP_MAGIC_LIVE               0xa8190173618f23cdULL  /* live magic number */
-+#define DUMP_VERSION_NUMBER   0x8     /* dump version number              */
-+#define DUMP_PANIC_LEN                0x100   /* dump panic string length         */
-+
-+/* dump levels - type specific stuff added later -- add as necessary */
-+#define DUMP_LEVEL_NONE               0x0     /* no dumping at all -- just bail   */
-+#define DUMP_LEVEL_HEADER     0x1     /* kernel dump header only          */
-+#define DUMP_LEVEL_KERN               0x2     /* dump header and kernel pages     */
-+#define DUMP_LEVEL_USED               0x4     /* dump header, kernel/user pages   */
-+#define DUMP_LEVEL_ALL_RAM    0x8     /* dump header, all RAM pages       */
-+#define DUMP_LEVEL_ALL                0x10    /* dump all memory RAM and firmware */
-+
-+
-+/* dump compression options -- add as necessary */
-+#define DUMP_COMPRESS_NONE    0x0     /* don't compress this dump         */
-+#define DUMP_COMPRESS_RLE     0x1     /* use RLE compression              */
-+#define DUMP_COMPRESS_GZIP    0x2     /* use GZIP compression             */
-+
-+/* dump flags - any dump-type specific flags -- add as necessary */
-+#define DUMP_FLAGS_NONE               0x0     /* no flags are set for this dump   */
-+#define DUMP_FLAGS_SOFTBOOT   0x2     /* 2 stage soft-boot based dump     */
-+
-+#define DUMP_FLAGS_TARGETMASK 0xf0000000 /* handle special case targets   */
-+#define DUMP_FLAGS_DISKDUMP   0x80000000 /* dump to local disk            */
-+#define DUMP_FLAGS_NETDUMP    0x40000000 /* dump over the network         */
-+
-+/* dump header flags -- add as necessary */
-+#define DUMP_DH_FLAGS_NONE    0x0     /* no flags set (error condition!)  */
-+#define DUMP_DH_RAW           0x1     /* raw page (no compression)        */
-+#define DUMP_DH_COMPRESSED    0x2     /* page is compressed               */
-+#define DUMP_DH_END           0x4     /* end marker on a full dump        */
-+#define DUMP_DH_TRUNCATED     0x8     /* dump is incomplete               */
-+#define DUMP_DH_TEST_PATTERN  0x10    /* dump page is a test pattern      */
-+#define DUMP_DH_NOT_USED      0x20    /* 1st bit not used in flags        */
-+
-+/* names for various dump parameters in /proc/kernel */
-+#define DUMP_ROOT_NAME                "sys/dump"
-+#define DUMP_DEVICE_NAME      "device"
-+#define DUMP_COMPRESS_NAME    "compress"
-+#define DUMP_LEVEL_NAME               "level"
-+#define DUMP_FLAGS_NAME               "flags"
-+#define DUMP_ADDR_NAME                "addr"
-+
-+#define DUMP_SYSRQ_KEY                'd'     /* key to use for MAGIC_SYSRQ key   */
-+
-+/* CTL_DUMP names: */
-+enum
-+{
-+      CTL_DUMP_DEVICE=1,
-+      CTL_DUMP_COMPRESS=3,
-+      CTL_DUMP_LEVEL=3,
-+      CTL_DUMP_FLAGS=4,
-+      CTL_DUMP_ADDR=5,
-+      CTL_DUMP_TEST=6,
-+};
-+
-+
-+/* page size for gzip compression -- buffered slightly beyond hardware PAGE_SIZE used by DUMP */
-+#define DUMP_DPC_PAGE_SIZE    (DUMP_PAGE_SIZE + 512)
-+
-+/* dump ioctl() control options */
-+#define DIOSDUMPDEV           1       /* set the dump device              */
-+#define DIOGDUMPDEV           2       /* get the dump device              */
-+#define DIOSDUMPLEVEL         3       /* set the dump level               */
-+#define DIOGDUMPLEVEL         4       /* get the dump level               */
-+#define DIOSDUMPFLAGS         5       /* set the dump flag parameters     */
-+#define DIOGDUMPFLAGS         6       /* get the dump flag parameters     */
-+#define DIOSDUMPCOMPRESS      7       /* set the dump compress level      */
-+#define DIOGDUMPCOMPRESS      8       /* get the dump compress level      */
-+
-+/* these ioctls are used only by netdump module */
-+#define DIOSTARGETIP          9       /* set the target m/c's ip          */
-+#define DIOGTARGETIP          10      /* get the target m/c's ip          */
-+#define DIOSTARGETPORT                11      /* set the target m/c's port        */
-+#define DIOGTARGETPORT                12      /* get the target m/c's port        */
-+#define DIOSSOURCEPORT                13      /* set the source m/c's port        */
-+#define DIOGSOURCEPORT                14      /* get the source m/c's port        */
-+#define DIOSETHADDR           15      /* set ethernet address             */
-+#define DIOGETHADDR           16      /* get ethernet address             */
-+
-+/*
-+ * Structure: __dump_header
-+ *  Function: This is the header dumped at the top of every valid crash
-+ *            dump.  
-+ */
-+struct __dump_header {
-+      /* the dump magic number -- unique to verify dump is valid */
-+      u64     dh_magic_number;
-+
-+      /* the version number of this dump */
-+      u32     dh_version;
-+
-+      /* the size of this header (in case we can't read it) */
-+      u32     dh_header_size;
-+
-+      /* the level of this dump (just a header?) */
-+      u32     dh_dump_level;
-+
-+      /* 
-+       * We assume dump_page_size to be 4K in every case.
-+       * Store here the configurable system page size (4K, 8K, 16K, etc.) 
-+       */
-+      u32     dh_page_size;
-+
-+      /* the size of all physical memory */
-+      u64     dh_memory_size;
-+
-+      /* the start of physical memory */
-+      u64     dh_memory_start;
-+
-+      /* the end of physical memory */
-+      u64     dh_memory_end;
-+
-+      /* the number of hardware/physical pages in this dump specifically */
-+      u32     dh_num_dump_pages;
-+
-+      /* the panic string, if available */
-+      char    dh_panic_string[DUMP_PANIC_LEN];
-+
-+      /* timeval depends on architecture, two long values */
-+      struct {
-+              u64 tv_sec;
-+              u64 tv_usec;
-+      } dh_time; /* the time of the system crash */
-+
-+      /* the NEW utsname (uname) information -- in character form */
-+      /* we do this so we don't have to include utsname.h         */
-+      /* plus it helps us be more architecture independent        */
-+      /* now maybe one day soon they'll make the [65] a #define!  */
-+      char    dh_utsname_sysname[65];
-+      char    dh_utsname_nodename[65];
-+      char    dh_utsname_release[65];
-+      char    dh_utsname_version[65];
-+      char    dh_utsname_machine[65];
-+      char    dh_utsname_domainname[65];
-+
-+      /* the address of current task (OLD = void *, NEW = u64) */
-+      u64     dh_current_task;
-+
-+      /* what type of compression we're using in this dump (if any) */
-+      u32     dh_dump_compress;
-+
-+      /* any additional flags */
-+      u32     dh_dump_flags;
-+
-+      /* any additional flags */
-+      u32     dh_dump_device;
-+} __attribute__((packed));
-+
-+/*
-+ * Structure: __dump_page
-+ *  Function: To act as the header associated to each physical page of
-+ *            memory saved in the system crash dump.  This allows for
-+ *            easy reassembly of each crash dump page.  The address bits
-+ *            are split to make things easier for 64-bit/32-bit system
-+ *            conversions.
-+ *
-+ * dp_byte_offset and dp_page_index are landmarks that are helpful when
-+ * looking at a hex dump of /dev/vmdump,
-+ */
-+struct __dump_page {
-+      /* the address of this dump page */
-+      u64     dp_address;
-+
-+      /* the size of this dump page */
-+      u32     dp_size;
-+
-+      /* flags (currently DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */
-+      u32     dp_flags;
-+} __attribute__((packed));
-+
-+/*
-+ * Structure: __lkcdinfo
-+ * Function:  This structure contains information needed for the lkcdutils
-+ *            package (particularly lcrash) to determine what information is
-+ *            associated to this kernel, specifically.
-+ */
-+struct __lkcdinfo {
-+      int     arch;
-+      int     ptrsz;
-+      int     byte_order;
-+      int     linux_release;
-+      int     page_shift;
-+      int     page_size;
-+      u64     page_mask;
-+      u64     page_offset;
-+      int     stack_offset;
-+};
-+
-+#ifdef __KERNEL__
-+
-+/*
-+ * Structure: __dump_compress
-+ *  Function: This is what an individual compression mechanism can use
-+ *            to plug in their own compression techniques.  It's always
-+ *            best to build these as individual modules so that people
-+ *            can put in whatever they want.
-+ */
-+struct __dump_compress {
-+      /* the list_head structure for list storage */
-+      struct list_head list;
-+
-+      /* the type of compression to use (DUMP_COMPRESS_XXX) */
-+      int compress_type;
-+      const char *compress_name;
-+
-+      /* the compression function to call */
-+      u16 (*compress_func)(const u8 *, u16, u8 *, u16);
-+};
-+
-+/* functions for dump compression registration */
-+extern void dump_register_compression(struct __dump_compress *);
-+extern void dump_unregister_compression(int);
-+
-+/*
-+ * Structure dump_mbank[]:
-+ *
-+ * For CONFIG_DISCONTIGMEM systems this array specifies the
-+ * memory banks/chunks that need to be dumped after a panic.
-+ *
-+ * For classic systems it specifies a single set of pages from
-+ * 0 to max_mapnr.
-+ */
-+struct __dump_mbank {
-+      u64     start;
-+      u64     end;
-+      int     type;
-+      int     pad1;
-+      long    pad2;
-+};
-+
-+#define DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY           1
-+#define DUMP_MBANK_TYPE_OTHER                         2
-+
-+#define MAXCHUNKS 256
-+extern int dump_mbanks;
-+extern struct __dump_mbank dump_mbank[MAXCHUNKS];
-+
-+/* notification event codes */
-+#define DUMP_BEGIN            0x0001  /* dump beginning */
-+#define DUMP_END              0x0002  /* dump ending */
-+
-+/* Scheduler soft spin control.
-+ *
-+ * 0 - no dump in progress
-+ * 1 - cpu0 is dumping, ...
-+ */
-+extern unsigned long dump_oncpu;
-+extern void dump_execute(const char *, const struct pt_regs *);
-+
-+/*
-+ *    Notifier list for kernel code which wants to be called
-+ *    at kernel dump. 
-+ */
-+extern struct notifier_block *dump_notifier_list;
-+static inline int register_dump_notifier(struct notifier_block *nb)
-+{
-+      return notifier_chain_register(&dump_notifier_list, nb);
-+}
-+static inline int unregister_dump_notifier(struct notifier_block * nb)
-+{
-+      return notifier_chain_unregister(&dump_notifier_list, nb);
-+}
-+
-+extern void (*dump_function_ptr)(const char *, const struct pt_regs *);
-+static inline void dump(char * str, struct pt_regs * regs)
-+{
-+      if (dump_function_ptr)
-+              dump_function_ptr(str, regs);
-+}
-+
-+/*
-+ * Common Arch Specific Functions should be declared here.
-+ * This allows the C compiler to detect discrepancies.
-+ */
-+extern void   __dump_open(void);
-+extern void   __dump_cleanup(void);
-+extern void   __dump_init(u64);
-+extern void   __dump_save_regs(struct pt_regs *, const struct pt_regs *);
-+extern int    __dump_configure_header(const struct pt_regs *);
-+extern void   __dump_irq_enable(void);
-+extern void   __dump_irq_restore(void);
-+extern int    __dump_page_valid(unsigned long index);
-+#ifdef CONFIG_SMP
-+extern void   __dump_save_other_cpus(void);
-+#else
-+#define       __dump_save_other_cpus()
-+#endif
-+
-+/* to track all used (compound + zero order) pages */
-+#define PageInuse(p)   (PageCompound(p) || page_count(p))
-+
-+#endif /* __KERNEL__ */
-+
-+#else /* !CONFIG_CRASH_DUMP */
-+
-+/* If not configured then make code disappear! */
-+#define register_dump_watchdog(x)     do { } while(0)
-+#define unregister_dump_watchdog(x)   do { } while(0)
-+#define register_dump_notifier(x)     do { } while(0)
-+#define unregister_dump_notifier(x)   do { } while(0)
-+#define dump_in_progress()            0
-+#define dump(x, y)                    do { } while(0)
-+
-+#endif        /* !CONFIG_CRASH_DUMP */
-+
-+#endif /* _DUMP_H */
-Index: linux-2.6.0-test5/include/linux/dump_netdev.h
-===================================================================
---- linux-2.6.0-test5.orig/include/linux/dump_netdev.h 2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/include/linux/dump_netdev.h      2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,82 @@
-+/*
-+ *  linux/drivers/net/netconsole.h
-+ *
-+ *  Copyright (C) 2001  Ingo Molnar <mingo@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 NETCONSOLE_VERSION 0x03
-+
-+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_GET_MAGIC = 9,
-+      COMM_START_WRITE_NETDUMP_ACK = 10,
-+      COMM_SYSRQ = 11,
-+};
-+
-+typedef struct netdump_req_s {
-+      u64 magic;
-+      u32 nr;
-+      u32 command;
-+      u32 from;
-+      u32 to;
-+} 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_START_WRITE_NETDUMP = 12,
-+      REPLY_SYSRQ = 13,
-+};
-+
-+typedef struct netdump_reply_s {
-+      u32 nr;
-+      u32 code;
-+      u32 info;
-+} reply_t;
-+
-+#define HEADER_LEN (1 + sizeof(reply_t))
-+
-+
-Index: linux-2.6.0-test5/include/asm-i386/dump.h
-===================================================================
---- linux-2.6.0-test5.orig/include/asm-i386/dump.h     2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/include/asm-i386/dump.h  2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,93 @@
-+/*
-+ * Kernel header file for Linux crash dumps.
-+ *
-+ * Created by: Matt Robinson (yakker@sgi.com)
-+ *
-+ * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+/* This header file holds the architecture specific crash dump header */
-+#ifndef _ASM_DUMP_H
-+#define _ASM_DUMP_H
-+
-+/* necessary header files */
-+#include <asm/ptrace.h>
-+#include <asm/page.h>
-+#include <linux/threads.h>
-+#include <linux/mm.h>
-+
-+/* definitions */
-+#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL   /* magic number            */
-+#define DUMP_ASM_VERSION_NUMBER       0x3     /* version number          */
-+
-+/* max number of cpus */
-+#define DUMP_MAX_NUM_CPUS 32
-+
-+/*
-+ * Structure: __dump_header_asm
-+ *  Function: This is the header for architecture-specific stuff.  It
-+ *            follows right after the dump header.
-+ */
-+struct __dump_header_asm {
-+      /* the dump magic number -- unique to verify dump is valid */
-+      u64             dha_magic_number;
-+
-+      /* the version number of this dump */
-+      u32             dha_version;
-+
-+      /* the size of this header (in case we can't read it) */
-+      u32             dha_header_size;
-+
-+      /* the esp for i386 systems */
-+      u32             dha_esp;
-+
-+      /* the eip for i386 systems */
-+      u32             dha_eip;
-+
-+      /* the dump registers */
-+      struct pt_regs  dha_regs;
-+
-+      /* smp specific */
-+      u32             dha_smp_num_cpus;
-+      u32             dha_dumping_cpu;
-+      struct pt_regs  dha_smp_regs[DUMP_MAX_NUM_CPUS];
-+      u32             dha_smp_current_task[DUMP_MAX_NUM_CPUS];
-+      u32             dha_stack[DUMP_MAX_NUM_CPUS];
-+      u32             dha_stack_ptr[DUMP_MAX_NUM_CPUS];
-+} __attribute__((packed));
-+
-+#ifdef __KERNEL__
-+
-+extern struct __dump_header_asm dump_header_asm;
-+
-+#ifdef CONFIG_SMP
-+extern cpumask_t irq_affinity[];
-+extern int (*dump_ipi_function_ptr)(struct pt_regs *);
-+extern void dump_send_ipi(void);
-+#else
-+#define dump_send_ipi() do { } while(0)
-+#endif
-+
-+static inline void get_current_regs(struct pt_regs *regs)
-+{
-+      __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx));
-+      __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx));
-+      __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx));
-+      __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi));
-+      __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi));
-+      __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp));
-+      __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax));
-+      __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp));
-+      __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss));
-+      __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs));
-+      __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds));
-+      __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes));
-+      __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags));
-+      regs->eip = (unsigned long)current_text_addr();
-+}
-+
-+#endif /* __KERNEL__ */
-+
-+#endif /* _ASM_DUMP_H */
-Index: linux-2.6.0-test5/init/kerntypes.c
-===================================================================
---- linux-2.6.0-test5.orig/init/kerntypes.c    2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/init/kerntypes.c 2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,31 @@
-+/*
-+ * kerntypes.c
-+ *
-+ * Copyright (C) 2000 Tom Morano (tjm@sgi.com) and
-+ *                    Matt D. Robinson (yakker@alacritech.com)
-+ *
-+ * Dummy module that includes headers for all kernel types of interest. 
-+ * The kernel type information is used by the lcrash utility when 
-+ * analyzing system crash dumps or the live system. Using the type 
-+ * information for the running system, rather than kernel header files,
-+ * makes for a more flexible and robust analysis tool.
-+ *
-+ * This source code is released under version 2 of the GNU GPL.
-+ */
-+
-+#include <linux/compile.h>
-+#include <linux/module.h>
-+#include <linux/mm.h>
-+#include <linux/config.h>
-+#include <linux/utsname.h>
-+#include <linux/dump.h>
-+
-+#ifdef LINUX_COMPILE_VERSION_ID_TYPE
-+/* Define version type for version validation of dump and kerntypes */
-+LINUX_COMPILE_VERSION_ID_TYPE;
-+#endif
-+
-+void
-+kerntypes_dummy(void)
-+{
-+}
-Index: linux-2.6.0-test5/drivers/dump/dump_methods.h
-===================================================================
---- linux-2.6.0-test5.orig/drivers/dump/dump_methods.h 2003-09-26 14:26:34.000000000 +0800
-+++ linux-2.6.0-test5/drivers/dump/dump_methods.h      2003-09-26 14:26:34.000000000 +0800
-@@ -0,0 +1,348 @@
-+/*
-+ * Generic interfaces for flexible system dump 
-+ *
-+ * Started: Oct 2002 -  Suparna Bhattacharya (suparna@in.ibm.com)
-+ *
-+ * Copyright (C) 2002 International Business Machines Corp. 
-+ *
-+ * This code is released under version 2 of the GNU GPL.
-+ */
-+
-+#ifndef _LINUX_DUMP_METHODS_H
-+#define _LINUX_DUMP_METHODS_H
-+
-+/*
-+ * Inspired by Matt Robinson's suggestion of introducing dump 
-+ * methods as a way to enable different crash dump facilities to 
-+ * coexist where each employs its own scheme or dumping policy.
-+ *
-+ * The code here creates a framework for flexible dump by defining 
-+ * a set of methods and providing associated helpers that differentiate
-+ * between the underlying mechanism (how to dump), overall scheme 
-+ * (sequencing of stages and data dumped and associated quiescing), 
-+ * output format (what the dump output looks like), target type 
-+ * (where to save the dump; see dumpdev.h), and selection policy 
-+ * (state/data to dump).
-+ * 
-+ * These sets of interfaces can be mixed and matched to build a 
-+ * dumper suitable for a given situation, allowing for 
-+ * flexibility as well appropriate degree of code reuse.
-+ * For example all features and options of lkcd (including
-+ * granular selective dumping in the near future) should be
-+ * available even when say, the 2 stage soft-boot based mechanism 
-+ * is used for taking disruptive dumps.
-+ *
-+ * Todo: Additionally modules or drivers may supply their own
-+ * custom dumpers which extend dump with module specific
-+ * information or hardware state, and can even tweak the
-+ * mechanism when it comes to saving state relevant to
-+ * them.
-+ */
-+
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/highmem.h>
-+#include <linux/dumpdev.h>
-+
-+#define MAX_PASSES    6
-+#define MAX_DEVS      4
-+
-+
-+/* To customise selection of pages to be dumped in a given pass/group */
-+struct dump_data_filter{
-+      char name[32];
-+      int (*selector)(int, unsigned long, unsigned long);
-+      ulong level_mask; /* dump level(s) for which this filter applies */
-+      loff_t start, end; /* location range applicable */
-+};
-+
-+
-+/* 
-+ * Determined by the kind of dump mechanism and appropriate 
-+ * overall scheme 
-+ */ 
-+struct dump_scheme_ops {
-+      /* sets aside memory, inits data structures etc */
-+      int (*configure)(unsigned long devid); 
-+      /* releases  resources */
-+      int (*unconfigure)(void); 
-+
-+      /* ordering of passes, invoking iterator */
-+      int (*sequencer)(void); 
-+        /* iterates over system data, selects and acts on data to dump */
-+      int (*iterator)(int, int (*)(unsigned long, unsigned long), 
-+              struct dump_data_filter *); 
-+        /* action when data is selected for dump */
-+      int (*save_data)(unsigned long, unsigned long); 
-+        /* action when data is to be excluded from dump */
-+      int (*skip_data)(unsigned long, unsigned long); 
-+      /* policies for space, multiple dump devices etc */
-+      int (*write_buffer)(void *, unsigned long); 
-+};
-+
-+struct dump_scheme {
-+      /* the name serves as an anchor to locate the scheme after reboot */
-+      char name[32]; 
-+      struct dump_scheme_ops *ops;
-+      struct list_head list;
-+};
-+
-+/* Quiescing/Silence levels (controls IPI callback behaviour) */
-+extern enum dump_silence_levels {
-+      DUMP_SOFT_SPIN_CPUS     = 1,
-+      DUMP_HARD_SPIN_CPUS     = 2,
-+      DUMP_HALT_CPUS          = 3,
-+} dump_silence_level;
-+
-+/* determined by the dump (file) format */
-+struct dump_fmt_ops {
-+      /* build header */
-+      int (*configure_header)(const char *, const struct pt_regs *); 
-+      int (*update_header)(void); /* update header and write it out */
-+      /* save curr context  */
-+      void (*save_context)(int, const struct pt_regs *, 
-+              struct task_struct *); 
-+      /* typically called by the save_data action */
-+      /* add formatted data to the dump buffer */
-+      int (*add_data)(unsigned long, unsigned long); 
-+      int (*update_end_marker)(void);
-+};
-+
-+struct dump_fmt {
-+      unsigned long magic; 
-+      char name[32];  /* lcrash, crash, elf-core etc */
-+      struct dump_fmt_ops *ops;
-+      struct list_head list;
-+};
-+
-+/* 
-+ * Modules will be able add their own data capture schemes by 
-+ * registering their own dumpers. Typically they would use the 
-+ * primary dumper as a template and tune it with their routines.
-+ * Still Todo.
-+ */
-+
-+/* The combined dumper profile (mechanism, scheme, dev, fmt) */
-+struct dumper {
-+      char name[32]; /* singlestage, overlay (stg1), passthru(stg2), pull */
-+      struct dump_scheme *scheme;
-+      struct dump_fmt *fmt;
-+      struct __dump_compress *compress;
-+      struct dump_data_filter *filter;
-+      struct dump_dev *dev; 
-+      /* state valid only for active dumper(s) - per instance */
-+      /* run time state/context */
-+      int curr_pass;
-+      unsigned long count;
-+      loff_t curr_offset; /* current logical offset into dump device */
-+      loff_t curr_loc; /* current memory location */
-+      void *curr_buf; /* current position in the dump buffer */
-+      void *dump_buf; /* starting addr of dump buffer */
-+      int header_dirty; /* whether the header needs to be written out */
-+      int header_len; 
-+      struct list_head dumper_list; /* links to other dumpers */
-+};    
-+
-+/* Starting point to get to the current configured state */
-+struct dump_config {
-+      ulong level;
-+      ulong flags;
-+      struct dumper *dumper;
-+      unsigned long dump_device;
-+      unsigned long dump_addr; /* relevant only for in-memory dumps */
-+      struct list_head dump_dev_list;
-+};    
-+
-+extern struct dump_config dump_config;
-+
-+/* Used to save the dump config across a reboot for 2-stage dumps: 
-+ * 
-+ * Note: The scheme, format, compression and device type should be 
-+ * registered at bootup, for this config to be sharable across soft-boot. 
-+ * The function addresses could have changed and become invalid, and
-+ * need to be set up again.
-+ */
-+struct dump_config_block {
-+      u64 magic; /* for a quick sanity check after reboot */
-+      struct dump_memdev memdev; /* handle to dump stored in memory */
-+      struct dump_config config;
-+      struct dumper dumper;
-+      struct dump_scheme scheme;
-+      struct dump_fmt fmt;
-+      struct __dump_compress compress;
-+      struct dump_data_filter filter_table[MAX_PASSES];
-+      struct dump_anydev dev[MAX_DEVS]; /* target dump device */
-+};
-+
-+
-+/* Wrappers that invoke the methods for the current (active) dumper */
-+
-+/* Scheme operations */
-+
-+static inline int dump_sequencer(void)
-+{
-+      return dump_config.dumper->scheme->ops->sequencer();
-+}
-+
-+static inline int dump_iterator(int pass, int (*action)(unsigned long, 
-+      unsigned long), struct dump_data_filter *filter)
-+{
-+      return dump_config.dumper->scheme->ops->iterator(pass, action, filter);
-+}
-+
-+#define dump_save_data dump_config.dumper->scheme->ops->save_data
-+#define dump_skip_data dump_config.dumper->scheme->ops->skip_data
-+
-+static inline int dump_write_buffer(void *buf, unsigned long len)
-+{
-+      return dump_config.dumper->scheme->ops->write_buffer(buf, len);
-+}
-+
-+static inline int dump_configure(unsigned long devid)
-+{
-+      return dump_config.dumper->scheme->ops->configure(devid);
-+}
-+
-+static inline int dump_unconfigure(void)
-+{
-+      return dump_config.dumper->scheme->ops->unconfigure();
-+}
-+
-+/* Format operations */
-+
-+static inline int dump_configure_header(const char *panic_str, 
-+      const struct pt_regs *regs)
-+{
-+      return dump_config.dumper->fmt->ops->configure_header(panic_str, regs);
-+}
-+
-+static inline void dump_save_context(int cpu, const struct pt_regs *regs, 
-+              struct task_struct *tsk)
-+{
-+      dump_config.dumper->fmt->ops->save_context(cpu, regs, tsk);
-+}
-+
-+static inline int dump_save_this_cpu(const struct pt_regs *regs)
-+{
-+      int cpu = smp_processor_id();
-+
-+      dump_save_context(cpu, regs, current);
-+      return 1;
-+}
-+
-+static inline int dump_update_header(void)
-+{
-+      return dump_config.dumper->fmt->ops->update_header();
-+}
-+
-+static inline int dump_update_end_marker(void)
-+{
-+      return dump_config.dumper->fmt->ops->update_end_marker();
-+}
-+
-+static inline int dump_add_data(unsigned long loc, unsigned long sz)
-+{
-+      return dump_config.dumper->fmt->ops->add_data(loc, sz);
-+}
-+
-+/* Compression operation */
-+static inline int dump_compress_data(char *src, int slen, char *dst)
-+{
-+      return dump_config.dumper->compress->compress_func(src, slen, 
-+              dst, DUMP_DPC_PAGE_SIZE);
-+}
-+
-+
-+/* Prototypes of some default implementations of dump methods */
-+
-+extern struct __dump_compress dump_none_compression;
-+
-+/* Default scheme methods (dump_scheme.c) */
-+
-+extern int dump_generic_sequencer(void);
-+extern int dump_page_iterator(int pass, int (*action)(unsigned long, unsigned
-+      long), struct dump_data_filter *filter);
-+extern int dump_generic_save_data(unsigned long loc, unsigned long sz);
-+extern int dump_generic_skip_data(unsigned long loc, unsigned long sz);
-+extern int dump_generic_write_buffer(void *buf, unsigned long len);
-+extern int dump_generic_configure(unsigned long);
-+extern int dump_generic_unconfigure(void);
-+
-+/* Default scheme template */
-+extern struct dump_scheme dump_scheme_singlestage;
-+
-+/* Default dump format methods */
-+
-+extern int dump_lcrash_configure_header(const char *panic_str, 
-+      const struct pt_regs *regs);
-+extern void dump_lcrash_save_context(int  cpu, const struct pt_regs *regs, 
-+      struct task_struct *tsk);
-+extern int dump_generic_update_header(void);
-+extern int dump_lcrash_add_data(unsigned long loc, unsigned long sz);
-+extern int dump_lcrash_update_end_marker(void);
-+
-+/* Default format (lcrash) template */
-+extern struct dump_fmt dump_fmt_lcrash;
-+
-+/* Default dump selection filter table */
-+
-+/* 
-+ * Entries listed in order of importance and correspond to passes
-+ * The last entry (with a level_mask of zero) typically reflects data that 
-+ * won't be dumped  -- this may for example be used to identify data 
-+ * that will be skipped for certain so the corresponding memory areas can be 
-+ * utilized as scratch space.
-+ */   
-+extern struct dump_data_filter dump_filter_table[];
-+
-+/* Some pre-defined dumpers */
-+extern struct dumper dumper_singlestage;
-+extern struct dumper dumper_stage1;
-+extern struct dumper dumper_stage2;
-+
-+/* These are temporary */
-+#define DUMP_MASK_HEADER      DUMP_LEVEL_HEADER
-+#define DUMP_MASK_KERN                DUMP_LEVEL_KERN
-+#define DUMP_MASK_USED                DUMP_LEVEL_USED
-+#define DUMP_MASK_UNUSED      DUMP_LEVEL_ALL_RAM
-+#define DUMP_MASK_REST                0 /* dummy for now */
-+
-+/* Helpers - move these to dump.h later ? */
-+
-+int dump_generic_execute(const char *panic_str, const struct pt_regs *regs);
-+extern int dump_ll_write(void *buf, unsigned long len); 
-+int dump_check_and_free_page(struct dump_memdev *dev, struct page *page);
-+
-+static inline void dumper_reset(void)
-+{
-+      dump_config.dumper->curr_buf = dump_config.dumper->dump_buf;
-+      dump_config.dumper->curr_loc = 0;
-+      dump_config.dumper->curr_offset = 0;
-+      dump_config.dumper->count = 0;
-+      dump_config.dumper->curr_pass = 0;
-+}
-+
-+/* 
-+ * May later be moulded to perform boot-time allocations so we can dump 
-+ * earlier during bootup 
-+ */
-+static inline void *dump_alloc_mem(unsigned long size)
-+{
-+      return kmalloc(size, GFP_KERNEL);
-+}
-+
-+static inline void dump_free_mem(void *buf)
-+{
-+      struct page *page;
-+
-+      /* ignore reserved pages (e.g. post soft boot stage) */
-+      if (buf && (page = virt_to_page(buf))) {
-+              if (PageReserved(page))
-+                      return;
-+      }
-+
-+      kfree(buf);
-+}
-+
-+
-+#endif /*  _LINUX_DUMP_METHODS_H */
-Index: linux-2.6.0-test5/Makefile
-===================================================================
---- linux-2.6.0-test5.orig/Makefile    2003-09-26 14:26:29.000000000 +0800
-+++ linux-2.6.0-test5/Makefile 2003-09-26 14:26:34.000000000 +0800
-@@ -289,6 +289,10 @@
- export MODVERDIR := .tmp_versions
-+ifeq ($(CONFIG_CRASH_DUMP),)
-+      CFLAGS += -g
-+endif
-+
- # The temporary file to save gcc -MD generated dependencies must not
- # contain a comma
- comma := ,