3 Index: linux-2.6.0-test5/drivers/dump/Makefile
4 ===================================================================
5 --- linux-2.6.0-test5.orig/drivers/dump/Makefile 2003-09-26 14:26:34.000000000 +0800
6 +++ linux-2.6.0-test5/drivers/dump/Makefile 2003-09-26 14:26:34.000000000 +0800
9 +# Makefile for the dump device drivers.
12 +dump-y := dump_setup.o dump_fmt.o dump_filters.o dump_scheme.o dump_execute.o
13 +dump-$(CONFIG_X86) += dump_i386.o
14 +dump-$(CONFIG_CRASH_DUMP_MEMDEV) += dump_memdev.o dump_overlay.o
15 +dump-objs += $(dump-y)
17 +obj-$(CONFIG_CRASH_DUMP) += dump.o
18 +obj-$(CONFIG_CRASH_DUMP_BLOCKDEV) += dump_blockdev.o
19 +obj-$(CONFIG_CRASH_DUMP_NETDEV) += dump_netdev.o
20 +obj-$(CONFIG_CRASH_DUMP_COMPRESS_RLE) += dump_rle.o
21 +obj-$(CONFIG_CRASH_DUMP_COMPRESS_GZIP) += dump_gzip.o
22 Index: linux-2.6.0-test5/drivers/dump/dump_blockdev.c
23 ===================================================================
24 --- linux-2.6.0-test5.orig/drivers/dump/dump_blockdev.c 2003-09-26 14:26:34.000000000 +0800
25 +++ linux-2.6.0-test5/drivers/dump/dump_blockdev.c 2003-09-26 14:29:10.000000000 +0800
28 + * Implements the dump driver interface for saving a dump to
29 + * a block device through the kernel's generic low level block i/o
32 + * Started: June 2002 - Mohamed Abbas <mohamed.abbas@intel.com>
33 + * Moved original lkcd kiobuf dump i/o code from dump_base.c
34 + * to use generic dump device interfaces
36 + * Sept 2002 - Bharata B. Rao <bharata@in.ibm.com>
37 + * Convert dump i/o to directly use bio instead of kiobuf for 2.5
39 + * Oct 2002 - Suparna Bhattacharya <suparna@in.ibm.com>
40 + * Rework to new dumpdev.h structures, implement open/close/
41 + * silence, misc fixes (blocknr removal, bio_add_page usage)
43 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
44 + * Copyright (C) 2001 - 2002 Matt D. Robinson. All rights reserved.
45 + * Copyright (C) 2002 International Business Machines Corp.
47 + * This code is released under version 2 of the GNU GPL.
50 +#include <linux/types.h>
51 +#include <linux/proc_fs.h>
52 +#include <linux/module.h>
53 +#include <linux/init.h>
54 +#include <linux/blkdev.h>
55 +#include <linux/bio.h>
56 +#include <asm/hardirq.h>
57 +#include <linux/dump.h>
58 +#include "dump_methods.h"
60 +extern void *dump_page_buf;
62 +/* The end_io callback for dump i/o completion */
64 +dump_bio_end_io(struct bio *bio, unsigned int bytes_done, int error)
66 + struct dump_blockdev *dump_bdev;
69 + /* some bytes still left to transfer */
70 + return 1; /* not complete */
73 + dump_bdev = (struct dump_blockdev *)bio->bi_private;
75 + printk("IO error while writing the dump, aborting\n");
78 + dump_bdev->err = error;
80 + /* no wakeup needed, since caller polls for completion */
84 +/* Check if the dump bio is already mapped to the specified buffer */
86 +dump_block_map_valid(struct dump_blockdev *dev, struct page *page,
89 + struct bio *bio = dev->bio;
90 + unsigned long bsize = 0;
93 + return 0; /* first time, not mapped */
96 + if ((bio_page(bio) != page) || (len > bio->bi_vcnt << PAGE_SHIFT))
97 + return 0; /* buffer not mapped */
99 + bsize = bdev_hardsect_size(bio->bi_bdev);
100 + if ((len & (PAGE_SIZE - 1)) || (len & bsize))
101 + return 0; /* alignment checks needed */
103 + /* quick check to decide if we need to redo bio_add_page */
104 + if (bdev_get_queue(bio->bi_bdev)->merge_bvec_fn)
105 + return 0; /* device may have other restrictions */
107 + return 1; /* already mapped */
111 + * Set up the dump bio for i/o from the specified buffer
112 + * Return value indicates whether the full buffer could be mapped or not
115 +dump_block_map(struct dump_blockdev *dev, void *buf, int len)
117 + struct page *page = virt_to_page(buf);
118 + struct bio *bio = dev->bio;
119 + unsigned long bsize = 0;
121 + bio->bi_bdev = dev->bdev;
122 + bio->bi_sector = (dev->start_offset + dev->ddev.curr_offset) >> 9;
123 + bio->bi_idx = 0; /* reset index to the beginning */
125 + if (dump_block_map_valid(dev, page, len)) {
126 + /* already mapped and usable rightaway */
127 + bio->bi_size = len; /* reset size to the whole bio */
129 + /* need to map the bio */
132 + bsize = bdev_hardsect_size(bio->bi_bdev);
134 + /* first a few sanity checks */
136 + printk("map: len less than hardsect size \n");
140 + if ((unsigned long)buf & bsize) {
141 + printk("map: not aligned \n");
145 + /* assume contig. page aligned low mem buffer( no vmalloc) */
146 + if ((page_address(page) != buf) || (len & (PAGE_SIZE - 1))) {
147 + printk("map: invalid buffer alignment!\n");
150 + /* finally we can go ahead and map it */
151 + while (bio->bi_size < len)
152 + if (bio_add_page(bio, page++, PAGE_SIZE, 0) == 0) {
156 + bio->bi_end_io = dump_bio_end_io;
157 + bio->bi_private = dev;
160 + if (bio->bi_size != len) {
161 + printk("map: bio size = %d not enough for len = %d!\n",
162 + bio->bi_size, len);
169 +dump_free_bio(struct bio *bio)
172 + kfree(bio->bi_io_vec);
177 + * Prepares the dump device so we can take a dump later.
178 + * The caller is expected to have filled up the kdev_id field in the
179 + * block dump dev structure.
181 + * At dump time when dump_block_write() is invoked it will be too
182 + * late to recover, so as far as possible make sure obvious errors
183 + * get caught right here and reported back to the caller.
186 +dump_block_open(struct dump_dev *dev, unsigned long arg)
188 + struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
189 + struct block_device *bdev;
191 + struct bio_vec *bvec;
193 + /* make sure this is a valid block device */
199 + /* get a corresponding block_dev struct for this */
200 + bdev = bdget((dev_t)arg);
206 + /* get the block device opened */
207 + if ((retval = blkdev_get(bdev, O_RDWR | O_LARGEFILE, 0, BDEV_RAW))) {
211 + if ((dump_bdev->bio = kmalloc(sizeof(struct bio), GFP_KERNEL))
213 + printk("Cannot allocate bio\n");
218 + bio_init(dump_bdev->bio);
220 + if ((bvec = kmalloc(sizeof(struct bio_vec) *
221 + (DUMP_BUFFER_SIZE >> PAGE_SHIFT), GFP_KERNEL)) == NULL) {
226 + /* assign the new dump dev structure */
227 + dump_bdev->kdev_id = new_decode_dev((dev_t)arg);
228 + dump_bdev->bdev = bdev;
230 + /* make a note of the limit */
231 + dump_bdev->limit = bdev->bd_inode->i_size;
233 + /* now make sure we can map the dump buffer */
234 + dump_bdev->bio->bi_io_vec = bvec;
235 + dump_bdev->bio->bi_max_vecs = DUMP_BUFFER_SIZE >> PAGE_SHIFT;
237 + retval = dump_block_map(dump_bdev, dump_config.dumper->dump_buf,
241 + printk("open: dump_block_map failed, ret %d\n", retval);
245 + printk("Block device (%d,%d) successfully configured for dumping\n",
246 + MAJOR(dump_bdev->kdev_id),
247 + MINOR(dump_bdev->kdev_id));
250 + /* after opening the block device, return */
253 +err3: dump_free_bio(dump_bdev->bio);
254 + dump_bdev->bio = NULL;
255 +err2: if (bdev) blkdev_put(bdev, BDEV_RAW);
257 +err1: if (bdev) bdput(bdev);
258 + dump_bdev->bdev = NULL;
263 + * Close the dump device and release associated resources
264 + * Invoked when unconfiguring the dump device.
267 +dump_block_release(struct dump_dev *dev)
269 + struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
271 + /* release earlier bdev if present */
272 + if (dump_bdev->bdev) {
273 + blkdev_put(dump_bdev->bdev, BDEV_RAW);
274 + dump_bdev->bdev = NULL;
277 + dump_free_bio(dump_bdev->bio);
278 + dump_bdev->bio = NULL;
285 + * Prepare the dump device for use (silence any ongoing activity
286 + * and quiesce state) when the system crashes.
289 +dump_block_silence(struct dump_dev *dev)
291 + struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
292 + struct request_queue *q = bdev_get_queue(dump_bdev->bdev);
295 + /* If we can't get request queue lock, refuse to take the dump */
296 + if (!spin_trylock(q->queue_lock))
299 + ret = elv_queue_empty(q);
300 + spin_unlock(q->queue_lock);
302 + /* For now we assume we have the device to ourselves */
303 + /* Just a quick sanity check */
305 + /* i/o in flight - safer to quit */
310 + * Move to a softer level of silencing where no spin_lock_irqs
311 + * are held on other cpus
313 + dump_silence_level = DUMP_SOFT_SPIN_CPUS;
315 + __dump_irq_enable();
317 + printk("Dumping to block device (%d,%d) on CPU %d ...\n",
318 + MAJOR(dump_bdev->kdev_id), MINOR(dump_bdev->kdev_id),
319 + smp_processor_id());
325 + * Invoked when dumping is done. This is the time to put things back
326 + * (i.e. undo the effects of dump_block_silence) so the device is
327 + * available for normal use.
330 +dump_block_resume(struct dump_dev *dev)
332 + __dump_irq_restore();
338 + * Seek to the specified offset in the dump device.
339 + * Makes sure this is a valid offset, otherwise returns an error.
342 +dump_block_seek(struct dump_dev *dev, loff_t off)
344 + struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
345 + loff_t offset = off + dump_bdev->start_offset;
347 + if (offset & ( PAGE_SIZE - 1)) {
348 + printk("seek: non-page aligned\n");
352 + if (offset & (bdev_hardsect_size(dump_bdev->bdev) - 1)) {
353 + printk("seek: not sector aligned \n");
357 + if (offset > dump_bdev->limit) {
358 + printk("seek: not enough space left on device!\n");
361 + dev->curr_offset = off;
366 + * Write out a buffer after checking the device limitations,
367 + * sector sizes, etc. Assumes the buffer is in directly mapped
368 + * kernel address space (not vmalloc'ed).
370 + * Returns: number of bytes written or -ERRNO.
373 +dump_block_write(struct dump_dev *dev, void *buf,
376 + struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
377 + loff_t offset = dev->curr_offset + dump_bdev->start_offset;
378 + int retval = -ENOSPC;
380 + if (offset >= dump_bdev->limit) {
381 + printk("write: not enough space left on device!\n");
385 + /* don't write more blocks than our max limit */
386 + if (offset + len > dump_bdev->limit)
387 + len = dump_bdev->limit - offset;
390 + retval = dump_block_map(dump_bdev, buf, len);
392 + printk("write: dump_block_map failed! err %d\n", retval);
397 + * Write out the data to disk.
398 + * Assumes the entire buffer mapped to a single bio, which we can
399 + * submit and wait for io completion. In the future, may consider
400 + * increasing the dump buffer size and submitting multiple bio s
401 + * for better throughput.
403 + dump_bdev->err = -EAGAIN;
404 + submit_bio(WRITE, dump_bdev->bio);
406 + dump_bdev->ddev.curr_offset += len;
413 + * Name: dump_block_ready()
414 + * Func: check if the last dump i/o is over and ready for next request
417 +dump_block_ready(struct dump_dev *dev, void *buf)
419 + struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
420 + request_queue_t *q = bdev_get_queue(dump_bdev->bio->bi_bdev);
422 + /* check for io completion */
423 + if (dump_bdev->err == -EAGAIN) {
428 + if (dump_bdev->err) {
429 + printk("dump i/o err\n");
430 + return dump_bdev->err;
437 +struct dump_dev_ops dump_blockdev_ops = {
438 + .open = dump_block_open,
439 + .release = dump_block_release,
440 + .silence = dump_block_silence,
441 + .resume = dump_block_resume,
442 + .seek = dump_block_seek,
443 + .write = dump_block_write,
444 + /* .read not implemented */
445 + .ready = dump_block_ready
448 +static struct dump_blockdev default_dump_blockdev = {
449 + .ddev = {.type_name = "blockdev", .ops = &dump_blockdev_ops,
452 + * leave enough room for the longest swap header possibly written
453 + * written by mkswap (likely the largest page size supported by
456 + .start_offset = DUMP_HEADER_OFFSET,
458 + /* assume the rest of the fields are zeroed by default */
461 +struct dump_blockdev *dump_blockdev = &default_dump_blockdev;
464 +dump_blockdev_init(void)
466 + if (dump_register_device(&dump_blockdev->ddev) < 0) {
467 + printk("block device driver registration failed\n");
471 + printk("block device driver for LKCD registered\n");
476 +dump_blockdev_cleanup(void)
478 + dump_unregister_device(&dump_blockdev->ddev);
479 + printk("block device driver for LKCD unregistered\n");
482 +MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
483 +MODULE_DESCRIPTION("Block Dump Driver for Linux Kernel Crash Dump (LKCD)");
484 +MODULE_LICENSE("GPL");
486 +module_init(dump_blockdev_init);
487 +module_exit(dump_blockdev_cleanup);
488 Index: linux-2.6.0-test5/drivers/dump/dump_execute.c
489 ===================================================================
490 --- linux-2.6.0-test5.orig/drivers/dump/dump_execute.c 2003-09-26 14:26:34.000000000 +0800
491 +++ linux-2.6.0-test5/drivers/dump/dump_execute.c 2003-09-26 14:26:34.000000000 +0800
494 + * The file has the common/generic dump execution code
496 + * Started: Oct 2002 - Suparna Bhattacharya <suparna@in.ibm.com>
497 + * Split and rewrote high level dump execute code to make use
498 + * of dump method interfaces.
500 + * Derived from original code in dump_base.c created by
501 + * Matt Robinson <yakker@sourceforge.net>)
503 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
504 + * Copyright (C) 2001 - 2002 Matt D. Robinson. All rights reserved.
505 + * Copyright (C) 2002 International Business Machines Corp.
507 + * Assumes dumper and dump config settings are in place
508 + * (invokes corresponding dumper specific routines as applicable)
510 + * This code is released under version 2 of the GNU GPL.
512 +#include <linux/kernel.h>
513 +#include <linux/notifier.h>
514 +#include <linux/dump.h>
515 +#include "dump_methods.h"
517 +struct notifier_block *dump_notifier_list; /* dump started/ended callback */
519 +/* Dump progress indicator */
523 + static const char twiddle[4] = { '|', '\\', '-', '/' };
524 + printk("%c\b", twiddle[i&3]);
527 +/* Make the device ready and write out the header */
528 +int dump_begin(void)
532 + /* dump_dev = dump_config.dumper->dev; */
534 + if ((err = dump_dev_silence())) {
535 + /* quiesce failed, can't risk continuing */
536 + /* Todo/Future: switch to alternate dump scheme if possible */
537 + printk("dump silence dev failed ! error %d\n", err);
541 + pr_debug("Writing dump header\n");
542 + if ((err = dump_update_header())) {
543 + printk("dump update header failed ! error %d\n", err);
548 + dump_config.dumper->curr_offset = DUMP_BUFFER_SIZE;
554 + * Write the dump terminator, a final header update and let go of
555 + * exclusive use of the device for dump.
557 +int dump_complete(void)
561 + if (dump_config.level != DUMP_LEVEL_HEADER) {
562 + if ((ret = dump_update_end_marker())) {
563 + printk("dump update end marker error %d\n", ret);
565 + if ((ret = dump_update_header())) {
566 + printk("dump update header error %d\n", ret);
569 + ret = dump_dev_resume();
574 +/* Saves all dump data */
575 +int dump_execute_savedump(void)
577 + int ret = 0, err = 0;
579 + if ((ret = dump_begin())) {
583 + if (dump_config.level != DUMP_LEVEL_HEADER) {
584 + ret = dump_sequencer();
586 + if ((err = dump_complete())) {
587 + printk("Dump complete failed. Error %d\n", err);
593 +/* Does all the real work: Capture and save state */
594 +int dump_generic_execute(const char *panic_str, const struct pt_regs *regs)
598 + if ((ret = dump_configure_header(panic_str, regs))) {
599 + printk("dump config header failed ! error %d\n", ret);
603 + /* tell interested parties that a dump is about to start */
604 + notifier_call_chain(&dump_notifier_list, DUMP_BEGIN,
605 + &dump_config.dump_device);
607 + if (dump_config.level != DUMP_LEVEL_NONE)
608 + ret = dump_execute_savedump();
610 + pr_debug("dumped %ld blocks of %d bytes each\n",
611 + dump_config.dumper->count, DUMP_BUFFER_SIZE);
613 + /* tell interested parties that a dump has completed */
614 + notifier_call_chain(&dump_notifier_list, DUMP_END,
615 + &dump_config.dump_device);
619 Index: linux-2.6.0-test5/drivers/dump/dump_filters.c
620 ===================================================================
621 --- linux-2.6.0-test5.orig/drivers/dump/dump_filters.c 2003-09-26 14:26:34.000000000 +0800
622 +++ linux-2.6.0-test5/drivers/dump/dump_filters.c 2003-09-26 14:26:34.000000000 +0800
625 + * Default filters to select data to dump for various passes.
627 + * Started: Oct 2002 - Suparna Bhattacharya <suparna@in.ibm.com>
628 + * Split and rewrote default dump selection logic to generic dump
629 + * method interfaces
630 + * Derived from a portion of dump_base.c created by
631 + * Matt Robinson <yakker@sourceforge.net>)
633 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
634 + * Copyright (C) 2001 - 2002 Matt D. Robinson. All rights reserved.
635 + * Copyright (C) 2002 International Business Machines Corp.
637 + * Used during single-stage dumping and during stage 1 of the 2-stage scheme
638 + * (Stage 2 of the 2-stage scheme uses the fully transparent filters
639 + * i.e. passthru filters in dump_overlay.c)
641 + * Future: Custom selective dump may involve a different set of filters.
643 + * This code is released under version 2 of the GNU GPL.
646 +#include <linux/kernel.h>
647 +#include <linux/bootmem.h>
648 +#include <linux/mm.h>
649 +#include <linux/slab.h>
650 +#include <linux/dump.h>
651 +#include "dump_methods.h"
654 +/* Copied from mm/bootmem.c - FIXME */
655 +/* return the number of _pages_ that will be allocated for the boot bitmap */
656 +unsigned long dump_calc_bootmap_pages (void)
658 + unsigned long mapsize;
659 + unsigned long pages = num_physpages;
661 + mapsize = (pages+7)/8;
662 + mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK;
663 + mapsize >>= PAGE_SHIFT;
669 +#define DUMP_PFN_SAFETY_MARGIN 1024 /* 4 MB */
671 +extern unsigned long min_low_pfn;
674 +int dump_low_page(struct page *p)
676 + return page_to_pfn(p) < min_low_pfn + dump_calc_bootmap_pages()
677 + + 1 + DUMP_PFN_SAFETY_MARGIN;
680 +static inline int kernel_page(struct page *p)
682 + /* FIXME: Need to exclude hugetlb pages. Clue: reserved but inuse */
683 + return PageReserved(p) || (!PageLRU(p) && PageInuse(p));
686 +static inline int user_page(struct page *p)
688 + return PageInuse(p) && (!PageReserved(p) && PageLRU(p));
691 +static inline int unreferenced_page(struct page *p)
693 + return !PageInuse(p) && !PageReserved(p);
697 +/* loc marks the beginning of a range of pages */
698 +int dump_filter_kernpages(int pass, unsigned long loc, unsigned long sz)
700 + struct page *page = (struct page *)loc;
701 + /* if any of the pages is a kernel page, select this set */
703 + if (dump_low_page(page) || kernel_page(page))
712 +/* loc marks the beginning of a range of pages */
713 +int dump_filter_userpages(int pass, unsigned long loc, unsigned long sz)
715 + struct page *page = (struct page *)loc;
717 + /* select if the set has any user page, and no kernel pages */
719 + if (user_page(page) && !dump_low_page(page)) {
721 + } else if (kernel_page(page) || dump_low_page(page)) {
732 +/* loc marks the beginning of a range of pages */
733 +int dump_filter_unusedpages(int pass, unsigned long loc, unsigned long sz)
735 + struct page *page = (struct page *)loc;
737 + /* select if the set does not have any used pages */
739 + if (!unreferenced_page(page) || dump_low_page(page)) {
748 +/* dummy: last (non-existent) pass */
749 +int dump_filter_none(int pass, unsigned long loc, unsigned long sz)
754 +/* TBD: resolve level bitmask ? */
755 +struct dump_data_filter dump_filter_table[] = {
756 + { .name = "kern", .selector = dump_filter_kernpages,
757 + .level_mask = DUMP_MASK_KERN},
758 + { .name = "user", .selector = dump_filter_userpages,
759 + .level_mask = DUMP_MASK_USED},
760 + { .name = "unused", .selector = dump_filter_unusedpages,
761 + .level_mask = DUMP_MASK_UNUSED},
762 + { .name = "none", .selector = dump_filter_none,
763 + .level_mask = DUMP_MASK_REST},
764 + { .name = "", .selector = NULL, .level_mask = 0}
767 Index: linux-2.6.0-test5/drivers/dump/dump_fmt.c
768 ===================================================================
769 --- linux-2.6.0-test5.orig/drivers/dump/dump_fmt.c 2003-09-26 14:26:34.000000000 +0800
770 +++ linux-2.6.0-test5/drivers/dump/dump_fmt.c 2003-09-26 14:26:34.000000000 +0800
773 + * Implements the routines which handle the format specific
774 + * aspects of dump for the default dump format.
776 + * Used in single stage dumping and stage 1 of soft-boot based dumping
777 + * Saves data in LKCD (lcrash) format
779 + * Previously a part of dump_base.c
781 + * Started: Oct 2002 - Suparna Bhattacharya <suparna@in.ibm.com>
782 + * Split off and reshuffled LKCD dump format code around generic
783 + * dump method interfaces.
785 + * Derived from original code created by
786 + * Matt Robinson <yakker@sourceforge.net>)
788 + * Contributions from SGI, IBM, HP, MCL, and others.
790 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
791 + * Copyright (C) 2000 - 2002 TurboLinux, Inc. All rights reserved.
792 + * Copyright (C) 2001 - 2002 Matt D. Robinson. All rights reserved.
793 + * Copyright (C) 2002 International Business Machines Corp.
795 + * This code is released under version 2 of the GNU GPL.
798 +#include <linux/types.h>
799 +#include <linux/kernel.h>
800 +#include <linux/time.h>
801 +#include <linux/sched.h>
802 +#include <linux/ptrace.h>
803 +#include <linux/utsname.h>
804 +#include <asm/dump.h>
805 +#include <linux/dump.h>
806 +#include "dump_methods.h"
809 + * SYSTEM DUMP LAYOUT
811 + * System dumps are currently the combination of a dump header and a set
812 + * of data pages which contain the system memory. The layout of the dump
813 + * (for full dumps) is as follows:
815 + * +-----------------------------+
816 + * | generic dump header |
817 + * +-----------------------------+
818 + * | architecture dump header |
819 + * +-----------------------------+
821 + * +-----------------------------+
823 + * +-----------------------------+
825 + * +-----------------------------+
827 + * +-----------------------------+
833 + * +-----------------------------+
834 + * | PAGE_END header |
835 + * +-----------------------------+
837 + * There are two dump headers, the first which is architecture
838 + * independent, and the other which is architecture dependent. This
839 + * allows different architectures to dump different data structures
840 + * which are specific to their chipset, CPU, etc.
842 + * After the dump headers come a succession of dump page headers along
843 + * with dump pages. The page header contains information about the page
844 + * size, any flags associated with the page (whether it's compressed or
845 + * not), and the address of the page. After the page header is the page
846 + * data, which is either compressed (or not). Each page of data is
847 + * dumped in succession, until the final dump header (PAGE_END) is
848 + * placed at the end of the dump, assuming the dump device isn't out
851 + * This mechanism allows for multiple compression types, different
852 + * types of data structures, different page ordering, etc., etc., etc.
853 + * It's a very straightforward mechanism for dumping system memory.
856 +struct __dump_header dump_header; /* the primary dump header */
857 +struct __dump_header_asm dump_header_asm; /* the arch-specific dump header */
860 + * Set up common header fields (mainly the arch indep section)
861 + * Per-cpu state is handled by lcrash_save_context
862 + * Returns the size of the header in bytes.
864 +static int lcrash_init_dump_header(const char *panic_str)
866 + struct timeval dh_time;
867 + struct sysinfo info;
869 + /* make sure the dump header isn't TOO big */
870 + if ((sizeof(struct __dump_header) +
871 + sizeof(struct __dump_header_asm)) > DUMP_BUFFER_SIZE) {
872 + printk("lcrash_init_header(): combined "
873 + "headers larger than DUMP_BUFFER_SIZE!\n");
877 + /* initialize the dump headers to zero */
878 + memset(&dump_header, 0, sizeof(dump_header));
879 + memset(&dump_header_asm, 0, sizeof(dump_header_asm));
881 + /* configure dump header values */
882 + dump_header.dh_magic_number = DUMP_MAGIC_NUMBER;
883 + dump_header.dh_version = DUMP_VERSION_NUMBER;
884 + dump_header.dh_memory_start = PAGE_OFFSET;
885 + dump_header.dh_memory_end = DUMP_MAGIC_NUMBER;
886 + dump_header.dh_header_size = sizeof(struct __dump_header);
888 + dump_header.dh_memory_size = (u64)info.totalram;
889 + dump_header.dh_page_size = PAGE_SIZE;
890 + dump_header.dh_dump_level = dump_config.level;
891 + dump_header.dh_current_task = (unsigned long) current;
892 + dump_header.dh_dump_compress = dump_config.dumper->compress->
894 + dump_header.dh_dump_flags = dump_config.flags;
895 + dump_header.dh_dump_device = dump_config.dumper->dev->device_id;
898 + dump_header.dh_num_bytes = 0;
900 + dump_header.dh_num_dump_pages = 0;
901 + do_gettimeofday(&dh_time);
902 + dump_header.dh_time.tv_sec = dh_time.tv_sec;
903 + dump_header.dh_time.tv_usec = dh_time.tv_usec;
905 + memcpy((void *)&(dump_header.dh_utsname_sysname),
906 + (const void *)&(system_utsname.sysname), __NEW_UTS_LEN + 1);
907 + memcpy((void *)&(dump_header.dh_utsname_nodename),
908 + (const void *)&(system_utsname.nodename), __NEW_UTS_LEN + 1);
909 + memcpy((void *)&(dump_header.dh_utsname_release),
910 + (const void *)&(system_utsname.release), __NEW_UTS_LEN + 1);
911 + memcpy((void *)&(dump_header.dh_utsname_version),
912 + (const void *)&(system_utsname.version), __NEW_UTS_LEN + 1);
913 + memcpy((void *)&(dump_header.dh_utsname_machine),
914 + (const void *)&(system_utsname.machine), __NEW_UTS_LEN + 1);
915 + memcpy((void *)&(dump_header.dh_utsname_domainname),
916 + (const void *)&(system_utsname.domainname), __NEW_UTS_LEN + 1);
919 + memcpy((void *)&(dump_header.dh_panic_string),
920 + (const void *)panic_str, DUMP_PANIC_LEN);
923 + dump_header_asm.dha_magic_number = DUMP_ASM_MAGIC_NUMBER;
924 + dump_header_asm.dha_version = DUMP_ASM_VERSION_NUMBER;
925 + dump_header_asm.dha_header_size = sizeof(dump_header_asm);
927 + dump_header_asm.dha_smp_num_cpus = num_online_cpus();
928 + pr_debug("smp_num_cpus in header %d\n",
929 + dump_header_asm.dha_smp_num_cpus);
931 + dump_header_asm.dha_dumping_cpu = smp_processor_id();
933 + return sizeof(dump_header) + sizeof(dump_header_asm);
937 +int dump_lcrash_configure_header(const char *panic_str,
938 + const struct pt_regs *regs)
942 + dump_config.dumper->header_len = lcrash_init_dump_header(panic_str);
944 + /* capture register states for all processors */
945 + dump_save_this_cpu(regs);
946 + __dump_save_other_cpus(); /* side effect:silence cpus */
948 + /* configure architecture-specific dump header values */
949 + if ((retval = __dump_configure_header(regs)))
952 + dump_config.dumper->header_dirty++;
956 +/* save register and task context */
957 +void dump_lcrash_save_context(int cpu, const struct pt_regs *regs,
958 + struct task_struct *tsk)
960 + dump_header_asm.dha_smp_current_task[cpu] = (uint32_t) tsk;
962 + __dump_save_regs(&dump_header_asm.dha_smp_regs[cpu], regs);
964 + /* take a snapshot of the stack */
965 + /* doing this enables us to tolerate slight drifts on this cpu */
966 + if (dump_header_asm.dha_stack[cpu]) {
967 + memcpy((void *)dump_header_asm.dha_stack[cpu],
968 + tsk->thread_info, THREAD_SIZE);
970 + dump_header_asm.dha_stack_ptr[cpu] = (uint32_t)(tsk->thread_info);
973 +/* write out the header */
974 +int dump_write_header(void)
976 + int retval = 0, size;
977 + void *buf = dump_config.dumper->dump_buf;
979 + /* accounts for DUMP_HEADER_OFFSET if applicable */
980 + if ((retval = dump_dev_seek(0))) {
981 + printk("Unable to seek to dump header offset: %d\n",
986 + memcpy(buf, (void *)&dump_header, sizeof(dump_header));
987 + size = sizeof(dump_header);
988 + memcpy(buf + size, (void *)&dump_header_asm, sizeof(dump_header_asm));
989 + size += sizeof(dump_header_asm);
990 + size = PAGE_ALIGN(size);
991 + retval = dump_ll_write(buf , size);
994 + return (retval >= 0) ? ENOSPC : retval;
999 +int dump_generic_update_header(void)
1003 + if (dump_config.dumper->header_dirty) {
1004 + if ((err = dump_write_header())) {
1005 + printk("dump write header failed !err %d\n", err);
1007 + dump_config.dumper->header_dirty = 0;
1014 +static inline int is_curr_stack_page(struct page *page, unsigned long size)
1016 + unsigned long thread_addr = (unsigned long)current_thread_info();
1017 + unsigned long addr = (unsigned long)page_address(page);
1019 + return !PageHighMem(page) && (addr < thread_addr + THREAD_SIZE)
1020 + && (addr + size > thread_addr);
1023 +static inline int is_dump_page(struct page *page, unsigned long size)
1025 + unsigned long addr = (unsigned long)page_address(page);
1026 + unsigned long dump_buf = (unsigned long)dump_config.dumper->dump_buf;
1028 + return !PageHighMem(page) && (addr < dump_buf + DUMP_BUFFER_SIZE)
1029 + && (addr + size > dump_buf);
1032 +int dump_allow_compress(struct page *page, unsigned long size)
1035 + * Don't compress the page if any part of it overlaps
1036 + * with the current stack or dump buffer (since the contents
1037 + * in these could be changing while compression is going on)
1039 + return !is_curr_stack_page(page, size) && !is_dump_page(page, size);
1042 +void lcrash_init_pageheader(struct __dump_page *dp, struct page *page,
1045 + memset(dp, sizeof(struct __dump_page), 0);
1049 + dp->dp_address = page_to_pfn(page) << PAGE_SHIFT;
1052 + dp->dp_page_index = dump_header.dh_num_dump_pages;
1053 + dp->dp_byte_offset = dump_header.dh_num_bytes + DUMP_BUFFER_SIZE
1054 + + DUMP_HEADER_OFFSET; /* ?? */
1055 +#endif /* DUMP_DEBUG */
1058 +int dump_lcrash_add_data(unsigned long loc, unsigned long len)
1060 + struct page *page = (struct page *)loc;
1061 + void *addr, *buf = dump_config.dumper->curr_buf;
1062 + struct __dump_page *dp = (struct __dump_page *)buf;
1065 + if (buf > dump_config.dumper->dump_buf + DUMP_BUFFER_SIZE)
1068 + lcrash_init_pageheader(dp, page, len);
1069 + buf += sizeof(struct __dump_page);
1072 + addr = kmap_atomic(page, KM_DUMP);
1073 + size = bytes = (len > PAGE_SIZE) ? PAGE_SIZE : len;
1074 + /* check for compression */
1075 + if (dump_allow_compress(page, bytes)) {
1076 + size = dump_compress_data((char *)addr, bytes, (char *)buf);
1078 + /* set the compressed flag if the page did compress */
1079 + if (size && (size < bytes)) {
1080 + dp->dp_flags |= DUMP_DH_COMPRESSED;
1082 + /* compression failed -- default to raw mode */
1083 + dp->dp_flags |= DUMP_DH_RAW;
1084 + memcpy(buf, addr, bytes);
1087 + /* memset(buf, 'A', size); temporary: testing only !! */
1088 + kunmap_atomic(addr, KM_DUMP);
1089 + dp->dp_size += size;
1095 + /* now update the header */
1097 + dump_header.dh_num_bytes += dp->dp_size + sizeof(*dp);
1099 + dump_header.dh_num_dump_pages++;
1100 + dump_config.dumper->header_dirty++;
1102 + dump_config.dumper->curr_buf = buf;
1107 +int dump_lcrash_update_end_marker(void)
1109 + struct __dump_page *dp =
1110 + (struct __dump_page *)dump_config.dumper->curr_buf;
1111 + unsigned long left;
1114 + lcrash_init_pageheader(dp, NULL, 0);
1115 + dp->dp_flags |= DUMP_DH_END; /* tbd: truncation test ? */
1117 + /* now update the header */
1119 + dump_header.dh_num_bytes += sizeof(*dp);
1121 + dump_config.dumper->curr_buf += sizeof(*dp);
1122 + left = dump_config.dumper->curr_buf - dump_config.dumper->dump_buf;
1127 + if ((ret = dump_dev_seek(dump_config.dumper->curr_offset))) {
1128 + printk("Seek failed at offset 0x%llx\n",
1129 + dump_config.dumper->curr_offset);
1133 + if (DUMP_BUFFER_SIZE > left)
1134 + memset(dump_config.dumper->curr_buf, 'm',
1135 + DUMP_BUFFER_SIZE - left);
1137 + if ((ret = dump_ll_write(dump_config.dumper->dump_buf,
1138 + DUMP_BUFFER_SIZE)) < DUMP_BUFFER_SIZE) {
1139 + return (ret < 0) ? ret : -ENOSPC;
1142 + dump_config.dumper->curr_offset += DUMP_BUFFER_SIZE;
1144 + if (left > DUMP_BUFFER_SIZE) {
1145 + left -= DUMP_BUFFER_SIZE;
1146 + memcpy(dump_config.dumper->dump_buf,
1147 + dump_config.dumper->dump_buf + DUMP_BUFFER_SIZE, left);
1148 + dump_config.dumper->curr_buf -= DUMP_BUFFER_SIZE;
1157 +/* Default Formatter (lcrash) */
1158 +struct dump_fmt_ops dump_fmt_lcrash_ops = {
1159 + .configure_header = dump_lcrash_configure_header,
1160 + .update_header = dump_generic_update_header,
1161 + .save_context = dump_lcrash_save_context,
1162 + .add_data = dump_lcrash_add_data,
1163 + .update_end_marker = dump_lcrash_update_end_marker
1166 +struct dump_fmt dump_fmt_lcrash = {
1168 + .ops = &dump_fmt_lcrash_ops
1171 Index: linux-2.6.0-test5/drivers/dump/dump_gzip.c
1172 ===================================================================
1173 --- linux-2.6.0-test5.orig/drivers/dump/dump_gzip.c 2003-09-26 14:26:34.000000000 +0800
1174 +++ linux-2.6.0-test5/drivers/dump/dump_gzip.c 2003-09-26 14:26:34.000000000 +0800
1177 + * GZIP Compression functions for kernel crash dumps.
1179 + * Created by: Matt Robinson (yakker@sourceforge.net)
1180 + * Copyright 2001 Matt D. Robinson. All rights reserved.
1182 + * This code is released under version 2 of the GNU GPL.
1186 +#include <linux/config.h>
1187 +#include <linux/module.h>
1188 +#include <linux/sched.h>
1189 +#include <linux/fs.h>
1190 +#include <linux/file.h>
1191 +#include <linux/init.h>
1192 +#include <linux/slab.h>
1193 +#include <linux/dump.h>
1194 +#include <linux/zlib.h>
1195 +#include <linux/vmalloc.h>
1197 +static void *deflate_workspace;
1200 + * Name: dump_compress_gzip()
1201 + * Func: Compress a DUMP_PAGE_SIZE page using gzip-style algorithms (the.
1202 + * deflate functions similar to what's used in PPP).
1205 +dump_compress_gzip(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
1207 + /* error code and dump stream */
1209 + z_stream dump_stream;
1211 + dump_stream.workspace = deflate_workspace;
1213 + if ((err = zlib_deflateInit(&dump_stream, Z_BEST_COMPRESSION)) != Z_OK) {
1214 + /* fall back to RLE compression */
1215 + printk("dump_compress_gzip(): zlib_deflateInit() "
1216 + "failed (%d)!\n", err);
1220 + /* use old (page of memory) and size (DUMP_PAGE_SIZE) as in-streams */
1221 + dump_stream.next_in = (u8 *) old;
1222 + dump_stream.avail_in = oldsize;
1224 + /* out streams are new (dpcpage) and new size (DUMP_DPC_PAGE_SIZE) */
1225 + dump_stream.next_out = new;
1226 + dump_stream.avail_out = newsize;
1228 + /* deflate the page -- check for error */
1229 + err = zlib_deflate(&dump_stream, Z_FINISH);
1230 + if (err != Z_STREAM_END) {
1231 + /* zero is return code here */
1232 + (void)zlib_deflateEnd(&dump_stream);
1233 + printk("dump_compress_gzip(): zlib_deflate() failed (%d)!\n",
1238 + /* let's end the deflated compression stream */
1239 + if ((err = zlib_deflateEnd(&dump_stream)) != Z_OK) {
1240 + printk("dump_compress_gzip(): zlib_deflateEnd() "
1241 + "failed (%d)!\n", err);
1244 + /* return the compressed byte total (if it's smaller) */
1245 + if (dump_stream.total_out >= oldsize) {
1248 + return dump_stream.total_out;
1251 +/* setup the gzip compression functionality */
1252 +static struct __dump_compress dump_gzip_compression = {
1253 + .compress_type = DUMP_COMPRESS_GZIP,
1254 + .compress_func = dump_compress_gzip,
1255 + .compress_name = "GZIP",
1259 + * Name: dump_compress_gzip_init()
1260 + * Func: Initialize gzip as a compression mechanism.
1263 +dump_compress_gzip_init(void)
1265 + deflate_workspace = vmalloc(zlib_deflate_workspacesize());
1266 + if (!deflate_workspace) {
1267 + printk("dump_compress_gzip_init(): Failed to "
1268 + "alloc %d bytes for deflate workspace\n",
1269 + zlib_deflate_workspacesize());
1272 + dump_register_compression(&dump_gzip_compression);
1277 + * Name: dump_compress_gzip_cleanup()
1278 + * Func: Remove gzip as a compression mechanism.
1281 +dump_compress_gzip_cleanup(void)
1283 + vfree(deflate_workspace);
1284 + dump_unregister_compression(DUMP_COMPRESS_GZIP);
1287 +/* module initialization */
1288 +module_init(dump_compress_gzip_init);
1289 +module_exit(dump_compress_gzip_cleanup);
1291 +MODULE_LICENSE("GPL");
1292 +MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
1293 +MODULE_DESCRIPTION("Gzip compression module for crash dump driver");
1294 Index: linux-2.6.0-test5/drivers/dump/dump_i386.c
1295 ===================================================================
1296 --- linux-2.6.0-test5.orig/drivers/dump/dump_i386.c 2003-09-26 14:26:34.000000000 +0800
1297 +++ linux-2.6.0-test5/drivers/dump/dump_i386.c 2003-09-26 14:26:34.000000000 +0800
1300 + * Architecture specific (i386) functions for Linux crash dumps.
1302 + * Created by: Matt Robinson (yakker@sgi.com)
1304 + * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
1306 + * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com)
1307 + * Copyright 2000 TurboLinux, Inc. All rights reserved.
1309 + * This code is released under version 2 of the GNU GPL.
1313 + * The hooks for dumping the kernel virtual memory to disk are in this
1314 + * file. Any time a modification is made to the virtual memory mechanism,
1315 + * these routines must be changed to use the new mechanisms.
1317 +#include <linux/init.h>
1318 +#include <linux/types.h>
1319 +#include <linux/kernel.h>
1320 +#include <linux/smp.h>
1321 +#include <linux/fs.h>
1322 +#include <linux/vmalloc.h>
1323 +#include <linux/mm.h>
1324 +#include <linux/dump.h>
1325 +#include "dump_methods.h"
1326 +#include <linux/irq.h>
1328 +#include <asm/processor.h>
1329 +#include <asm/e820.h>
1330 +#include <asm/hardirq.h>
1331 +#include <asm/nmi.h>
1333 +static __s32 saved_irq_count; /* saved preempt_count() flags */
1336 +alloc_dha_stack(void)
1341 + if (dump_header_asm.dha_stack[0])
1344 + ptr = vmalloc(THREAD_SIZE * num_online_cpus());
1346 + printk("vmalloc for dha_stacks failed\n");
1350 + for (i = 0; i < num_online_cpus(); i++) {
1351 + dump_header_asm.dha_stack[i] = (u32)((unsigned long)ptr +
1352 + (i * THREAD_SIZE));
1358 +free_dha_stack(void)
1360 + if (dump_header_asm.dha_stack[0]) {
1361 + vfree((void *)dump_header_asm.dha_stack[0]);
1362 + dump_header_asm.dha_stack[0] = 0;
1369 +__dump_save_regs(struct pt_regs *dest_regs, const struct pt_regs *regs)
1371 + *dest_regs = *regs;
1373 + /* In case of panic dumps, we collects regs on entry to panic.
1374 + * so, we shouldn't 'fix' ssesp here again. But it is hard to
1375 + * tell just looking at regs whether ssesp need fixing. We make
1376 + * this decision by looking at xss in regs. If we have better
1377 + * means to determine that ssesp are valid (by some flag which
1378 + * tells that we are here due to panic dump), then we can use
1379 + * that instead of this kludge.
1381 + if (!user_mode(regs)) {
1382 + if ((0xffff & regs->xss) == __KERNEL_DS)
1383 + /* already fixed up */
1385 + dest_regs->esp = (unsigned long)&(regs->esp);
1386 + __asm__ __volatile__ ("movw %%ss, %%ax;"
1387 + :"=a"(dest_regs->xss));
1393 +extern cpumask_t irq_affinity[];
1394 +extern irq_desc_t irq_desc[];
1395 +extern void dump_send_ipi(void);
1397 +static int dump_expect_ipi[NR_CPUS];
1398 +static atomic_t waiting_for_dump_ipi;
1399 +static cpumask_t saved_affinity[NR_IRQS];
1401 +extern void stop_this_cpu(void *); /* exported by i386 kernel */
1404 +dump_nmi_callback(struct pt_regs *regs, int cpu)
1406 + if (!dump_expect_ipi[cpu])
1409 + dump_expect_ipi[cpu] = 0;
1411 + dump_save_this_cpu(regs);
1412 + atomic_dec(&waiting_for_dump_ipi);
1415 + switch (dump_silence_level) {
1416 + case DUMP_HARD_SPIN_CPUS: /* Spin until dump is complete */
1417 + while (dump_oncpu) {
1418 + barrier(); /* paranoia */
1419 + if (dump_silence_level != DUMP_HARD_SPIN_CPUS)
1420 + goto level_changed;
1422 + cpu_relax(); /* kill time nicely */
1426 + case DUMP_HALT_CPUS: /* Execute halt */
1427 + stop_this_cpu(NULL);
1430 + case DUMP_SOFT_SPIN_CPUS:
1431 + /* Mark the task so it spins in schedule */
1432 + set_tsk_thread_flag(current, TIF_NEED_RESCHED);
1439 +/* save registers on other processors */
1441 +__dump_save_other_cpus(void)
1443 + int i, cpu = smp_processor_id();
1444 + int other_cpus = num_online_cpus()-1;
1446 + if (other_cpus > 0) {
1447 + atomic_set(&waiting_for_dump_ipi, other_cpus);
1449 + for (i = 0; i < NR_CPUS; i++) {
1450 + dump_expect_ipi[i] = (i != cpu && cpu_online(i));
1453 + /* short circuit normal NMI handling temporarily */
1454 + set_nmi_callback(dump_nmi_callback);
1458 + /* may be we dont need to wait for NMI to be processed.
1459 + just write out the header at the end of dumping, if
1460 + this IPI is not processed until then, there probably
1461 + is a problem and we just fail to capture state of
1463 + while(atomic_read(&waiting_for_dump_ipi) > 0) {
1467 + unset_nmi_callback();
1472 + * Routine to save the old irq affinities and change affinities of all irqs to
1473 + * the dumping cpu.
1476 +set_irq_affinity(void)
1479 + int cpu = smp_processor_id();
1481 + memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(cpumask_t));
1482 + for (i = 0; i < NR_IRQS; i++) {
1483 + if (irq_desc[i].handler == NULL)
1485 + irq_affinity[i] = cpumask_of_cpu(cpu);
1486 + if (irq_desc[i].handler->set_affinity != NULL)
1487 + irq_desc[i].handler->set_affinity(i, irq_affinity[i]);
1492 + * Restore old irq affinities.
1495 +reset_irq_affinity(void)
1499 + memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long));
1500 + for (i = 0; i < NR_IRQS; i++) {
1501 + if (irq_desc[i].handler == NULL)
1503 + if (irq_desc[i].handler->set_affinity != NULL)
1504 + irq_desc[i].handler->set_affinity(i, saved_affinity[i]);
1508 +#else /* !CONFIG_SMP */
1509 +#define set_irq_affinity() do { } while (0)
1510 +#define reset_irq_affinity() do { } while (0)
1511 +#define save_other_cpu_states() do { } while (0)
1512 +#endif /* !CONFIG_SMP */
1515 + * Kludge - dump from interrupt context is unreliable (Fixme)
1517 + * We do this so that softirqs initiated for dump i/o
1518 + * get processed and we don't hang while waiting for i/o
1519 + * to complete or in any irq synchronization attempt.
1521 + * This is not quite legal of course, as it has the side
1522 + * effect of making all interrupts & softirqs triggered
1523 + * while dump is in progress complete before currently
1524 + * pending softirqs and the currently executing interrupt
1530 + saved_irq_count = irq_count();
1531 + preempt_count() &= ~(HARDIRQ_MASK|SOFTIRQ_MASK);
1535 +irq_bh_restore(void)
1537 + preempt_count() |= saved_irq_count;
1541 + * Name: __dump_irq_enable
1542 + * Func: Reset system so interrupts are enabled.
1543 + * This is used for dump methods that require interrupts
1544 + * Eventually, all methods will have interrupts disabled
1545 + * and this code can be removed.
1547 + * Change irq affinities
1548 + * Re-enable interrupts
1551 +__dump_irq_enable(void)
1553 + set_irq_affinity();
1555 + local_irq_enable();
1559 + * Name: __dump_irq_restore
1560 + * Func: Resume the system state in an architecture-specific way.
1564 +__dump_irq_restore(void)
1566 + local_irq_disable();
1567 + reset_irq_affinity();
1572 + * Name: __dump_configure_header()
1573 + * Func: Meant to fill in arch specific header fields except per-cpu state
1574 + * already captured via __dump_save_context for all CPUs.
1577 +__dump_configure_header(const struct pt_regs *regs)
1583 + * Name: __dump_init()
1584 + * Func: Initialize the dumping routine process.
1587 +__dump_init(uint64_t local_memory_start)
1593 + * Name: __dump_open()
1594 + * Func: Open the dump device (architecture specific).
1599 + alloc_dha_stack();
1603 + * Name: __dump_cleanup()
1604 + * Func: Free any architecture specific data structures. This is called
1605 + * when the dump module is being removed.
1608 +__dump_cleanup(void)
1613 +extern int pfn_is_ram(unsigned long);
1616 + * Name: __dump_page_valid()
1617 + * Func: Check if page is valid to dump.
1620 +__dump_page_valid(unsigned long index)
1622 + if (!pfn_valid(index))
1625 + return pfn_is_ram(index);
1628 Index: linux-2.6.0-test5/drivers/dump/dump_memdev.c
1629 ===================================================================
1630 --- linux-2.6.0-test5.orig/drivers/dump/dump_memdev.c 2003-09-26 14:26:34.000000000 +0800
1631 +++ linux-2.6.0-test5/drivers/dump/dump_memdev.c 2003-09-26 14:26:34.000000000 +0800
1634 + * Implements the dump driver interface for saving a dump in available
1635 + * memory areas. The saved pages may be written out to persistent storage
1636 + * after a soft reboot.
1638 + * Started: Oct 2002 - Suparna Bhattacharya <suparna@in.ibm.com>
1640 + * Copyright (C) 2002 International Business Machines Corp.
1642 + * This code is released under version 2 of the GNU GPL.
1644 + * The approach of tracking pages containing saved dump using map pages
1645 + * allocated as needed has been derived from the Mission Critical Linux
1646 + * mcore dump implementation.
1648 + * Credits and a big thanks for letting the lkcd project make use of
1649 + * the excellent piece of work and also helping with clarifications
1650 + * and tips along the way are due to:
1651 + * Dave Winchell <winchell@mclx.com> (primary author of mcore)
1652 + * Jeff Moyer <moyer@mclx.com>
1653 + * Josh Huber <huber@mclx.com>
1655 + * For those familiar with the mcore code, the main differences worth
1656 + * noting here (besides the dump device abstraction) result from enabling
1657 + * "high" memory pages (pages not permanently mapped in the kernel
1658 + * address space) to be used for saving dump data (because of which a
1659 + * simple virtual address based linked list cannot be used anymore for
1660 + * managing free pages), an added level of indirection for faster
1661 + * lookups during the post-boot stage, and the idea of pages being
1662 + * made available as they get freed up while dump to memory progresses
1663 + * rather than one time before starting the dump. The last point enables
1664 + * a full memory snapshot to be saved starting with an initial set of
1665 + * bootstrap pages given a good compression ratio. (See dump_overlay.c)
1670 + * -----------------MEMORY LAYOUT ------------------
1671 + * The memory space consists of a set of discontiguous pages, and
1672 + * discontiguous map pages as well, rooted in a chain of indirect
1673 + * map pages (also discontiguous). Except for the indirect maps
1674 + * (which must be preallocated in advance), the rest of the pages
1675 + * could be in high memory.
1678 + * | --------- -------- --------
1679 + * --> | . . +|--->| . +|------->| . . | indirect
1680 + * --|--|--- ---|---- --|-|--- maps
1682 + * ------ ------ ------- ------ -------
1683 + * | . | | . | | . . | | . | | . . | maps
1684 + * --|--- --|--- --|--|-- --|--- ---|-|--
1685 + * page page page page page page page data
1688 + * Writes to the dump device happen sequentially in append mode.
1689 + * The main reason for the existence of the indirect map is
1690 + * to enable a quick way to lookup a specific logical offset in
1691 + * the saved data post-soft-boot, e.g. to writeout pages
1692 + * with more critical data first, even though such pages
1693 + * would have been compressed and copied last, being the lowest
1694 + * ranked candidates for reuse due to their criticality.
1695 + * (See dump_overlay.c)
1697 +#include <linux/mm.h>
1698 +#include <linux/highmem.h>
1699 +#include <linux/bootmem.h>
1700 +#include <linux/dump.h>
1701 +#include "dump_methods.h"
1703 +#define DUMP_MAP_SZ (PAGE_SIZE / sizeof(unsigned long)) /* direct map size */
1704 +#define DUMP_IND_MAP_SZ DUMP_MAP_SZ - 1 /* indirect map size */
1705 +#define DUMP_NR_BOOTSTRAP 64 /* no of bootstrap pages */
1707 +extern int dump_low_page(struct page *);
1709 +/* check if the next entry crosses a page boundary */
1710 +static inline int is_last_map_entry(unsigned long *map)
1712 + unsigned long addr = (unsigned long)(map + 1);
1714 + return (!(addr & (PAGE_SIZE - 1)));
1717 +/* Todo: should have some validation checks */
1718 +/* The last entry in the indirect map points to the next indirect map */
1719 +/* Indirect maps are referred to directly by virtual address */
1720 +static inline unsigned long *next_indirect_map(unsigned long *map)
1722 + return (unsigned long *)map[DUMP_IND_MAP_SZ];
1725 +#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
1726 +/* Called during early bootup - fixme: make this __init */
1727 +void dump_early_reserve_map(struct dump_memdev *dev)
1729 + unsigned long *map1, *map2;
1730 + loff_t off = 0, last = dev->last_used_offset >> PAGE_SHIFT;
1733 + printk("Reserve bootmap space holding previous dump of %lld pages\n",
1735 + map1= (unsigned long *)dev->indirect_map_root;
1737 + while (map1 && (off < last)) {
1738 + reserve_bootmem(virt_to_phys((void *)map1), PAGE_SIZE);
1739 + for (i=0; (i < DUMP_MAP_SZ - 1) && map1[i] && (off < last);
1740 + i++, off += DUMP_MAP_SZ) {
1741 + pr_debug("indirect map[%d] = 0x%lx\n", i, map1[i]);
1742 + if (map1[i] >= max_low_pfn)
1744 + reserve_bootmem(map1[i] << PAGE_SHIFT, PAGE_SIZE);
1745 + map2 = pfn_to_kaddr(map1[i]);
1746 + for (j = 0 ; (j < DUMP_MAP_SZ) && map2[j] &&
1747 + (off + j < last); j++) {
1748 + pr_debug("\t map[%d][%d] = 0x%lx\n", i, j,
1750 + if (map2[j] < max_low_pfn) {
1751 + reserve_bootmem(map2[j] << PAGE_SHIFT,
1756 + map1 = next_indirect_map(map1);
1758 + dev->nr_free = 0; /* these pages don't belong to this boot */
1762 +/* mark dump pages so that they aren't used by this kernel */
1763 +void dump_mark_map(struct dump_memdev *dev)
1765 + unsigned long *map1, *map2;
1766 + loff_t off = 0, last = dev->last_used_offset >> PAGE_SHIFT;
1767 + struct page *page;
1770 + printk("Dump: marking pages in use by previous dump\n");
1771 + map1= (unsigned long *)dev->indirect_map_root;
1773 + while (map1 && (off < last)) {
1774 + page = virt_to_page(map1);
1775 + set_page_count(page, 1);
1776 + for (i=0; (i < DUMP_MAP_SZ - 1) && map1[i] && (off < last);
1777 + i++, off += DUMP_MAP_SZ) {
1778 + pr_debug("indirect map[%d] = 0x%lx\n", i, map1[i]);
1779 + page = pfn_to_page(map1[i]);
1780 + set_page_count(page, 1);
1781 + map2 = kmap_atomic(page, KM_DUMP);
1782 + for (j = 0 ; (j < DUMP_MAP_SZ) && map2[j] &&
1783 + (off + j < last); j++) {
1784 + pr_debug("\t map[%d][%d] = 0x%lx\n", i, j,
1786 + page = pfn_to_page(map2[j]);
1787 + set_page_count(page, 1);
1790 + map1 = next_indirect_map(map1);
1796 + * Given a logical offset into the mem device lookup the
1797 + * corresponding page
1798 + * loc is specified in units of pages
1799 + * Note: affects curr_map (even in the case where lookup fails)
1801 +struct page *dump_mem_lookup(struct dump_memdev *dump_mdev, unsigned long loc)
1803 + unsigned long *map;
1804 + unsigned long i, index = loc / DUMP_MAP_SZ;
1805 + struct page *page = NULL;
1806 + unsigned long curr_pfn, curr_map, *curr_map_ptr = NULL;
1808 + map = (unsigned long *)dump_mdev->indirect_map_root;
1812 + if (loc > dump_mdev->last_offset >> PAGE_SHIFT)
1816 + * first locate the right indirect map
1817 + * in the chain of indirect maps
1819 + for (i = 0; i + DUMP_IND_MAP_SZ < index ; i += DUMP_IND_MAP_SZ) {
1820 + if (!(map = next_indirect_map(map)))
1823 + /* then the right direct map */
1824 + /* map entries are referred to by page index */
1825 + if ((curr_map = map[index - i])) {
1826 + page = pfn_to_page(curr_map);
1827 + /* update the current traversal index */
1828 + /* dump_mdev->curr_map = &map[index - i];*/
1829 + curr_map_ptr = &map[index - i];
1833 + map = kmap_atomic(page, KM_DUMP);
1837 + /* and finally the right entry therein */
1838 + /* data pages are referred to by page index */
1839 + i = index * DUMP_MAP_SZ;
1840 + if ((curr_pfn = map[loc - i])) {
1841 + page = pfn_to_page(curr_pfn);
1842 + dump_mdev->curr_map = curr_map_ptr;
1843 + dump_mdev->curr_map_offset = loc - i;
1844 + dump_mdev->ddev.curr_offset = loc << PAGE_SHIFT;
1848 + kunmap_atomic(map, KM_DUMP);
1854 + * Retrieves a pointer to the next page in the dump device
1855 + * Used during the lookup pass post-soft-reboot
1857 +struct page *dump_mem_next_page(struct dump_memdev *dev)
1860 + unsigned long *map;
1861 + struct page *page = NULL;
1863 + if (dev->ddev.curr_offset + PAGE_SIZE >= dev->last_offset) {
1867 + if ((i = (unsigned long)(++dev->curr_map_offset)) >= DUMP_MAP_SZ) {
1868 + /* move to next map */
1869 + if (is_last_map_entry(++dev->curr_map)) {
1870 + /* move to the next indirect map page */
1871 + printk("dump_mem_next_page: go to next indirect map\n");
1872 + dev->curr_map = (unsigned long *)*dev->curr_map;
1873 + if (!dev->curr_map)
1876 + i = dev->curr_map_offset = 0;
1877 + pr_debug("dump_mem_next_page: next map 0x%lx, entry 0x%lx\n",
1878 + dev->curr_map, *dev->curr_map);
1882 + if (*dev->curr_map) {
1883 + map = kmap_atomic(pfn_to_page(*dev->curr_map), KM_DUMP);
1885 + page = pfn_to_page(map[i]);
1886 + kunmap_atomic(map, KM_DUMP);
1887 + dev->ddev.curr_offset += PAGE_SIZE;
1893 +/* Copied from dump_filters.c */
1894 +static inline int kernel_page(struct page *p)
1896 + /* FIXME: Need to exclude hugetlb pages. Clue: reserved but inuse */
1897 + return PageReserved(p) || (!PageLRU(p) && PageInuse(p));
1900 +static inline int user_page(struct page *p)
1902 + return PageInuse(p) && (!PageReserved(p) && PageLRU(p));
1905 +int dump_reused_by_boot(struct page *page)
1910 + * if < __end + bootmem_bootmap_pages for this boot + allowance
1911 + * if overwritten by initrd (how to check ?)
1912 + * Also, add more checks in early boot code
1913 + * e.g. bootmem bootmap alloc verify not overwriting dump, and if
1914 + * so then realloc or move the dump pages out accordingly.
1917 + /* Temporary proof of concept hack, avoid overwriting kern pages */
1919 + return (kernel_page(page) || dump_low_page(page) || user_page(page));
1923 +/* Uses the free page passed in to expand available space */
1924 +int dump_mem_add_space(struct dump_memdev *dev, struct page *page)
1926 + struct page *map_page;
1927 + unsigned long *map;
1930 + if (!dev->curr_map)
1931 + return -ENOMEM; /* must've exhausted indirect map */
1933 + if (!*dev->curr_map || dev->curr_map_offset >= DUMP_MAP_SZ) {
1934 + /* add map space */
1935 + *dev->curr_map = page_to_pfn(page);
1936 + dev->curr_map_offset = 0;
1940 + /* add data space */
1941 + i = dev->curr_map_offset;
1942 + map_page = pfn_to_page(*dev->curr_map);
1943 + map = (unsigned long *)kmap_atomic(map_page, KM_DUMP);
1944 + map[i] = page_to_pfn(page);
1945 + kunmap_atomic(map, KM_DUMP);
1946 + dev->curr_map_offset = ++i;
1947 + dev->last_offset += PAGE_SIZE;
1948 + if (i >= DUMP_MAP_SZ) {
1949 + /* move to next map */
1950 + if (is_last_map_entry(++dev->curr_map)) {
1951 + /* move to the next indirect map page */
1952 + pr_debug("dump_mem_add_space: using next"
1953 + "indirect map\n");
1954 + dev->curr_map = (unsigned long *)*dev->curr_map;
1961 +/* Caution: making a dest page invalidates existing contents of the page */
1962 +int dump_check_and_free_page(struct dump_memdev *dev, struct page *page)
1967 + * the page can be used as a destination only if we are sure
1968 + * it won't get overwritten by the soft-boot, and is not
1969 + * critical for us right now.
1971 + if (dump_reused_by_boot(page))
1974 + if ((err = dump_mem_add_space(dev, page))) {
1975 + printk("Warning: Unable to extend memdev space. Err %d\n",
1985 +/* Set up the initial maps and bootstrap space */
1986 +/* Must be called only after any previous dump is written out */
1987 +int dump_mem_open(struct dump_dev *dev, unsigned long devid)
1989 + struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
1990 + unsigned long nr_maps, *map, *prev_map = &dump_mdev->indirect_map_root;
1992 + struct page *page;
1993 + unsigned long i = 0;
1996 + /* Todo: sanity check for unwritten previous dump */
1998 + /* allocate pages for indirect map (non highmem area) */
1999 + nr_maps = num_physpages / DUMP_MAP_SZ; /* maps to cover entire mem */
2000 + for (i = 0; i < nr_maps; i += DUMP_IND_MAP_SZ) {
2001 + if (!(map = (unsigned long *)dump_alloc_mem(PAGE_SIZE))) {
2002 + printk("Unable to alloc indirect map %ld\n",
2003 + i / DUMP_IND_MAP_SZ);
2007 + *prev_map = (unsigned long)map;
2008 + prev_map = &map[DUMP_IND_MAP_SZ];
2011 + dump_mdev->curr_map = (unsigned long *)dump_mdev->indirect_map_root;
2012 + dump_mdev->curr_map_offset = 0;
2015 + * allocate a few bootstrap pages: at least 1 map and 1 data page
2016 + * plus enough to save the dump header
2020 + if (!(addr = dump_alloc_mem(PAGE_SIZE))) {
2021 + printk("Unable to alloc bootstrap page %ld\n", i);
2025 + page = virt_to_page(addr);
2026 + if (dump_low_page(page)) {
2027 + dump_free_mem(addr);
2031 + if (dump_mem_add_space(dump_mdev, page)) {
2032 + printk("Warning: Unable to extend memdev "
2033 + "space. Err %d\n", err);
2034 + dump_free_mem(addr);
2038 + } while (i < DUMP_NR_BOOTSTRAP);
2040 + printk("dump memdev init: %ld maps, %ld bootstrap pgs, %ld free pgs\n",
2041 + nr_maps, i, dump_mdev->last_offset >> PAGE_SHIFT);
2043 + dump_mdev->last_bs_offset = dump_mdev->last_offset;
2048 +/* Releases all pre-alloc'd pages */
2049 +int dump_mem_release(struct dump_dev *dev)
2051 + struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
2052 + struct page *page, *map_page;
2053 + unsigned long *map, *prev_map;
2057 + if (!dump_mdev->nr_free)
2060 + pr_debug("dump_mem_release\n");
2061 + page = dump_mem_lookup(dump_mdev, 0);
2062 + for (i = 0; page && (i < DUMP_NR_BOOTSTRAP - 1); i++) {
2063 + if (PageHighMem(page))
2065 + addr = page_address(page);
2067 + printk("page_address(%p) = NULL\n", page);
2070 + pr_debug("Freeing page at 0x%lx\n", addr);
2071 + dump_free_mem(addr);
2072 + if (dump_mdev->curr_map_offset >= DUMP_MAP_SZ - 1) {
2073 + map_page = pfn_to_page(*dump_mdev->curr_map);
2074 + if (PageHighMem(map_page))
2076 + page = dump_mem_next_page(dump_mdev);
2077 + addr = page_address(map_page);
2079 + printk("page_address(%p) = NULL\n",
2083 + pr_debug("Freeing map page at 0x%lx\n", addr);
2084 + dump_free_mem(addr);
2087 + page = dump_mem_next_page(dump_mdev);
2091 + /* now for the last used bootstrap page used as a map page */
2092 + if ((i < DUMP_NR_BOOTSTRAP) && (*dump_mdev->curr_map)) {
2093 + map_page = pfn_to_page(*dump_mdev->curr_map);
2094 + if ((map_page) && !PageHighMem(map_page)) {
2095 + addr = page_address(map_page);
2097 + printk("page_address(%p) = NULL\n", map_page);
2099 + pr_debug("Freeing map page at 0x%lx\n", addr);
2100 + dump_free_mem(addr);
2106 + printk("Freed %d bootstrap pages\n", i);
2108 + /* free the indirect maps */
2109 + map = (unsigned long *)dump_mdev->indirect_map_root;
2114 + map = next_indirect_map(map);
2115 + dump_free_mem(prev_map);
2119 + printk("Freed %d indirect map(s)\n", i);
2121 + /* Reset the indirect map */
2122 + dump_mdev->indirect_map_root = 0;
2123 + dump_mdev->curr_map = 0;
2125 + /* Reset the free list */
2126 + dump_mdev->nr_free = 0;
2128 + dump_mdev->last_offset = dump_mdev->ddev.curr_offset = 0;
2129 + dump_mdev->last_used_offset = 0;
2130 + dump_mdev->curr_map = NULL;
2131 + dump_mdev->curr_map_offset = 0;
2137 + * It is critical for this to be very strict. Cannot afford
2138 + * to have anything running and accessing memory while we overwrite
2139 + * memory (potential risk of data corruption).
2140 + * If in doubt (e.g if a cpu is hung and not responding) just give
2141 + * up and refuse to proceed with this scheme.
2143 + * Note: I/O will only happen after soft-boot/switchover, so we can
2144 + * safely disable interrupts and force stop other CPUs if this is
2145 + * going to be a disruptive dump, no matter what they
2146 + * are in the middle of.
2149 + * ATM Most of this is already taken care of in the nmi handler
2150 + * We may halt the cpus rightaway if we know this is going to be disruptive
2151 + * For now, since we've limited ourselves to overwriting free pages we
2152 + * aren't doing much here. Eventually, we'd have to wait to make sure other
2153 + * cpus aren't using memory we could be overwriting
2155 +int dump_mem_silence(struct dump_dev *dev)
2157 + struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
2159 + if (dump_mdev->last_offset > dump_mdev->last_bs_offset) {
2160 + /* prefer to run lkcd config & start with a clean slate */
2166 +extern int dump_overlay_resume(void);
2168 +/* Trigger the next stage of dumping */
2169 +int dump_mem_resume(struct dump_dev *dev)
2171 + dump_overlay_resume();
2176 + * Allocate mem dev pages as required and copy buffer contents into it.
2177 + * Fails if the no free pages are available
2178 + * Keeping it simple and limited for starters (can modify this over time)
2179 + * Does not handle holes or a sparse layout
2180 + * Data must be in multiples of PAGE_SIZE
2182 +int dump_mem_write(struct dump_dev *dev, void *buf, unsigned long len)
2184 + struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
2185 + struct page *page;
2186 + unsigned long n = 0;
2188 + unsigned long *saved_curr_map, saved_map_offset;
2191 + pr_debug("dump_mem_write: offset 0x%llx, size %ld\n",
2192 + dev->curr_offset, len);
2194 + if (dev->curr_offset + len > dump_mdev->last_offset) {
2195 + printk("Out of space to write\n");
2199 + if ((len & (PAGE_SIZE - 1)) || (dev->curr_offset & (PAGE_SIZE - 1)))
2200 + return -EINVAL; /* not aligned in units of page size */
2202 + saved_curr_map = dump_mdev->curr_map;
2203 + saved_map_offset = dump_mdev->curr_map_offset;
2204 + page = dump_mem_lookup(dump_mdev, dev->curr_offset >> PAGE_SHIFT);
2206 + for (n = len; (n > 0) && page; n -= PAGE_SIZE, buf += PAGE_SIZE ) {
2207 + addr = kmap_atomic(page, KM_DUMP);
2208 + /* memset(addr, 'x', PAGE_SIZE); */
2209 + memcpy(addr, buf, PAGE_SIZE);
2210 + kunmap_atomic(addr, KM_DUMP);
2211 + /* dev->curr_offset += PAGE_SIZE; */
2212 + page = dump_mem_next_page(dump_mdev);
2215 + dump_mdev->curr_map = saved_curr_map;
2216 + dump_mdev->curr_map_offset = saved_map_offset;
2218 + if (dump_mdev->last_used_offset < dev->curr_offset)
2219 + dump_mdev->last_used_offset = dev->curr_offset;
2221 + return (len - n) ? (len - n) : ret ;
2224 +/* dummy - always ready */
2225 +int dump_mem_ready(struct dump_dev *dev, void *buf)
2231 + * Should check for availability of space to write upto the offset
2232 + * affects only the curr_offset; last_offset untouched
2233 + * Keep it simple: Only allow multiples of PAGE_SIZE for now
2235 +int dump_mem_seek(struct dump_dev *dev, loff_t offset)
2237 + struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
2239 + if (offset & (PAGE_SIZE - 1))
2240 + return -EINVAL; /* allow page size units only for now */
2242 + /* Are we exceeding available space ? */
2243 + if (offset > dump_mdev->last_offset) {
2244 + printk("dump_mem_seek failed for offset 0x%llx\n",
2249 + dump_mdev->ddev.curr_offset = offset;
2253 +struct dump_dev_ops dump_memdev_ops = {
2254 + .open = dump_mem_open,
2255 + .release = dump_mem_release,
2256 + .silence = dump_mem_silence,
2257 + .resume = dump_mem_resume,
2258 + .seek = dump_mem_seek,
2259 + .write = dump_mem_write,
2260 + .read = NULL, /* not implemented at the moment */
2261 + .ready = dump_mem_ready
2264 +static struct dump_memdev default_dump_memdev = {
2265 + .ddev = {.type_name = "memdev", .ops = &dump_memdev_ops,
2266 + .device_id = 0x14}
2267 + /* assume the rest of the fields are zeroed by default */
2270 +/* may be overwritten if a previous dump exists */
2271 +struct dump_memdev *dump_memdev = &default_dump_memdev;
2273 Index: linux-2.6.0-test5/drivers/dump/dump_netdev.c
2274 ===================================================================
2275 --- linux-2.6.0-test5.orig/drivers/dump/dump_netdev.c 2003-09-26 14:26:34.000000000 +0800
2276 +++ linux-2.6.0-test5/drivers/dump/dump_netdev.c 2003-09-26 14:26:34.000000000 +0800
2279 + * Implements the dump driver interface for saving a dump via network
2282 + * Some of this code has been taken/adapted from Ingo Molnar's netconsole
2283 + * code. LKCD team expresses its thanks to Ingo.
2285 + * Started: June 2002 - Mohamed Abbas <mohamed.abbas@intel.com>
2286 + * Adapted netconsole code to implement LKCD dump over the network.
2288 + * Nov 2002 - Bharata B. Rao <bharata@in.ibm.com>
2289 + * Innumerable code cleanups, simplification and some fixes.
2290 + * Netdump configuration done by ioctl instead of using module parameters.
2292 + * Copyright (C) 2001 Ingo Molnar <mingo@redhat.com>
2293 + * Copyright (C) 2002 International Business Machines Corp.
2295 + * This code is released under version 2 of the GNU GPL.
2298 +#include <net/tcp.h>
2299 +#include <net/udp.h>
2300 +#include <linux/delay.h>
2301 +#include <linux/random.h>
2302 +#include <linux/reboot.h>
2303 +#include <linux/module.h>
2304 +#include <linux/dump.h>
2305 +#include <linux/dump_netdev.h>
2307 +#include <asm/unaligned.h>
2309 +static int startup_handshake;
2310 +static int page_counter;
2311 +static struct net_device *dump_ndev;
2312 +static struct in_device *dump_in_dev;
2313 +static u16 source_port, target_port;
2314 +static u32 source_ip, target_ip;
2315 +static unsigned char daddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
2316 +static spinlock_t dump_skb_lock = SPIN_LOCK_UNLOCKED;
2317 +static int dump_nr_skbs;
2318 +static struct sk_buff *dump_skb;
2319 +static unsigned long flags_global;
2320 +static int netdump_in_progress;
2321 +static char device_name[IFNAMSIZ];
2324 + * security depends on the trusted path between the netconsole
2325 + * server and netconsole client, since none of the packets are
2326 + * encrypted. The random magic number protects the protocol
2327 + * against spoofing.
2329 +static u64 dump_magic;
2331 +#define MAX_UDP_CHUNK 1460
2332 +#define MAX_PRINT_CHUNK (MAX_UDP_CHUNK-HEADER_LEN)
2335 + * We maintain a small pool of fully-sized skbs,
2336 + * to make sure the message gets out even in
2337 + * extreme OOM situations.
2339 +#define DUMP_MAX_SKBS 32
2341 +#define MAX_SKB_SIZE \
2342 + (MAX_UDP_CHUNK + sizeof(struct udphdr) + \
2343 + sizeof(struct iphdr) + sizeof(struct ethhdr))
2346 +dump_refill_skbs(void)
2348 + struct sk_buff *skb;
2349 + unsigned long flags;
2351 + spin_lock_irqsave(&dump_skb_lock, flags);
2352 + while (dump_nr_skbs < DUMP_MAX_SKBS) {
2353 + skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
2357 + skb->next = dump_skb;
2363 + spin_unlock_irqrestore(&dump_skb_lock, flags);
2367 +sk_buff * dump_get_skb(void)
2369 + struct sk_buff *skb;
2370 + unsigned long flags;
2372 + spin_lock_irqsave(&dump_skb_lock, flags);
2375 + dump_skb = skb->next;
2379 + spin_unlock_irqrestore(&dump_skb_lock, flags);
2385 + * Zap completed output skbs.
2388 +zap_completion_queue(void)
2391 + unsigned long flags;
2392 + int cpu = smp_processor_id();
2393 + struct softnet_data *softnet_data;
2396 + softnet_data = &__get_cpu_var(softnet_data);
2398 + if (softnet_data[cpu].completion_queue) {
2399 + struct sk_buff *clist;
2401 + local_irq_save(flags);
2402 + clist = softnet_data[cpu].completion_queue;
2403 + softnet_data[cpu].completion_queue = NULL;
2404 + local_irq_restore(flags);
2406 + while (clist != NULL) {
2407 + struct sk_buff *skb = clist;
2408 + clist = clist->next;
2411 + if (count > 10000)
2412 + printk("Error in sk list\n");
2418 +dump_send_skb(struct net_device *dev, const char *msg, unsigned int msg_len,
2422 + int total_len, eth_len, ip_len, udp_len, count = 0;
2423 + struct sk_buff *skb;
2424 + struct udphdr *udph;
2425 + struct iphdr *iph;
2426 + struct ethhdr *eth;
2428 + udp_len = msg_len + HEADER_LEN + sizeof(*udph);
2429 + ip_len = eth_len = udp_len + sizeof(*iph);
2430 + total_len = eth_len + ETH_HLEN;
2433 + zap_completion_queue();
2434 + if (dump_nr_skbs < DUMP_MAX_SKBS)
2435 + dump_refill_skbs();
2437 + skb = alloc_skb(total_len, GFP_ATOMIC);
2439 + skb = dump_get_skb();
2442 + if (once && (count == 1000000)) {
2443 + printk("possibly FATAL: out of netconsole "
2444 + "skbs!!! will keep retrying.\n");
2447 + dev->poll_controller(dev);
2452 + atomic_set(&skb->users, 1);
2453 + skb_reserve(skb, total_len - msg_len - HEADER_LEN);
2454 + skb->data[0] = NETCONSOLE_VERSION;
2456 + put_unaligned(htonl(reply->nr), (u32 *) (skb->data + 1));
2457 + put_unaligned(htonl(reply->code), (u32 *) (skb->data + 5));
2458 + put_unaligned(htonl(reply->info), (u32 *) (skb->data + 9));
2460 + memcpy(skb->data + HEADER_LEN, msg, msg_len);
2461 + skb->len += msg_len + HEADER_LEN;
2463 + udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
2464 + udph->source = source_port;
2465 + udph->dest = target_port;
2466 + udph->len = htons(udp_len);
2469 + iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
2474 + iph->tot_len = htons(ip_len);
2476 + iph->frag_off = 0;
2478 + iph->protocol = IPPROTO_UDP;
2480 + iph->saddr = source_ip;
2481 + iph->daddr = target_ip;
2482 + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
2484 + eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
2486 + eth->h_proto = htons(ETH_P_IP);
2487 + memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
2488 + memcpy(eth->h_dest, daddr, dev->addr_len);
2492 + spin_lock(&dev->xmit_lock);
2493 + dev->xmit_lock_owner = smp_processor_id();
2498 + if (netif_queue_stopped(dev)) {
2499 + dev->xmit_lock_owner = -1;
2500 + spin_unlock(&dev->xmit_lock);
2502 + dev->poll_controller(dev);
2503 + zap_completion_queue();
2509 + dev->hard_start_xmit(skb, dev);
2511 + dev->xmit_lock_owner = -1;
2512 + spin_unlock(&dev->xmit_lock);
2515 +static unsigned short
2516 +udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr,
2517 + unsigned long base)
2519 + return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base);
2523 +udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
2524 + unsigned short ulen, u32 saddr, u32 daddr)
2526 + if (uh->check == 0) {
2527 + skb->ip_summed = CHECKSUM_UNNECESSARY;
2528 + } else if (skb->ip_summed == CHECKSUM_HW) {
2529 + skb->ip_summed = CHECKSUM_UNNECESSARY;
2530 + if (!udp_check(uh, ulen, saddr, daddr, skb->csum))
2532 + skb->ip_summed = CHECKSUM_NONE;
2534 + if (skb->ip_summed != CHECKSUM_UNNECESSARY)
2535 + skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen,
2537 + /* Probably, we should checksum udp header (it should be in cache
2538 + * in any case) and data in tiny packets (< rx copybreak).
2543 +static __inline__ int
2544 +__udp_checksum_complete(struct sk_buff *skb)
2546 + return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len,
2551 +int udp_checksum_complete(struct sk_buff *skb)
2553 + return skb->ip_summed != CHECKSUM_UNNECESSARY &&
2554 + __udp_checksum_complete(skb);
2561 +dump_rx_hook(struct sk_buff *skb)
2564 + struct iphdr *iph;
2565 + struct udphdr *uh;
2566 + __u32 len, saddr, daddr, ulen;
2570 + * First check if were are dumping or doing startup handshake, if
2571 + * not quickly return.
2573 + if (!netdump_in_progress)
2574 + return NET_RX_SUCCESS;
2576 + if (skb->dev->type != ARPHRD_ETHER)
2579 + proto = ntohs(skb->mac.ethernet->h_proto);
2580 + if (proto != ETH_P_IP)
2583 + if (skb->pkt_type == PACKET_OTHERHOST)
2586 + if (skb_shared(skb))
2589 + /* IP header correctness testing: */
2590 + iph = (struct iphdr *)skb->data;
2591 + if (!pskb_may_pull(skb, sizeof(struct iphdr)))
2594 + if (iph->ihl < 5 || iph->version != 4)
2597 + if (!pskb_may_pull(skb, iph->ihl*4))
2600 + if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
2603 + len = ntohs(iph->tot_len);
2604 + if (skb->len < len || len < iph->ihl*4)
2607 + saddr = iph->saddr;
2608 + daddr = iph->daddr;
2609 + if (iph->protocol != IPPROTO_UDP)
2612 + if (source_ip != daddr)
2615 + if (target_ip != saddr)
2618 + len -= iph->ihl*4;
2619 + uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
2620 + ulen = ntohs(uh->len);
2622 + if (ulen != len || ulen < (sizeof(*uh) + sizeof(*__req)))
2625 + if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0)
2628 + if (udp_checksum_complete(skb))
2631 + if (source_port != uh->dest)
2634 + if (target_port != uh->source)
2637 + __req = (req_t *)(uh + 1);
2638 + if ((ntohl(__req->command) != COMM_GET_MAGIC) &&
2639 + (ntohl(__req->command) != COMM_HELLO) &&
2640 + (ntohl(__req->command) != COMM_START_WRITE_NETDUMP_ACK) &&
2641 + (ntohl(__req->command) != COMM_START_NETDUMP_ACK) &&
2642 + (memcmp(&__req->magic, &dump_magic, sizeof(dump_magic)) != 0))
2645 + req.magic = ntohl(__req->magic);
2646 + req.command = ntohl(__req->command);
2647 + req.from = ntohl(__req->from);
2648 + req.to = ntohl(__req->to);
2649 + req.nr = ntohl(__req->nr);
2652 + return NET_RX_DROP;
2656 +dump_send_mem(struct net_device *dev, req_t *req, const char* buff, size_t len)
2660 + int nr_chunks = len/1024;
2663 + reply.nr = req->nr;
2666 + if ( nr_chunks <= 0)
2668 + for (i = 0; i < nr_chunks; i++) {
2669 + unsigned int offset = i*1024;
2670 + reply.code = REPLY_MEM;
2671 + reply.info = offset;
2672 + dump_send_skb(dev, buff + offset, 1024, &reply);
2675 +static void dump_do_sysrq(int key)
2677 + struct pt_regs regs;
2679 + get_current_regs(®s);
2680 + handle_sysrq(key, ®s, NULL, NULL);
2684 + * This function waits for the client to acknowledge the receipt
2685 + * of the netdump startup reply, with the possibility of packets
2686 + * getting lost. We resend the startup packet if no ACK is received,
2687 + * after a 1 second delay.
2689 + * (The client can test the success of the handshake via the HELLO
2690 + * command, and send ACKs until we enter netdump mode.)
2693 +dump_handshake(struct dump_dev *net_dev)
2699 + if (startup_handshake) {
2700 + sprintf(tmp, "NETDUMP start, waiting for start-ACK.\n");
2701 + reply.code = REPLY_START_NETDUMP;
2705 + sprintf(tmp, "NETDUMP start, waiting for start-ACK.\n");
2706 + reply.code = REPLY_START_WRITE_NETDUMP;
2707 + reply.nr = net_dev->curr_offset;
2708 + reply.info = net_dev->curr_offset;
2711 + /* send 300 handshake packets before declaring failure */
2712 + for (i = 0; i < 300; i++) {
2713 + dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
2716 + for (j = 0; j < 10000; j++) {
2718 + dump_ndev->poll_controller(dump_ndev);
2719 + zap_completion_queue();
2725 + * if there is no new request, try sending the handshaking
2732 + * check if the new request is of the expected type,
2733 + * if so, return, else try sending the handshaking
2736 + if (startup_handshake) {
2737 + if (req.command == COMM_HELLO || req.command ==
2738 + COMM_START_NETDUMP_ACK) {
2745 + if (req.command == COMM_SEND_MEM) {
2757 +do_netdump(struct dump_dev *net_dev, const char* buff, size_t len)
2762 + int repeatCounter, counter, total_loop;
2764 + netdump_in_progress = 1;
2766 + if (dump_handshake(net_dev) < 0) {
2767 + printk("network dump failed due to handshake failure\n");
2772 + * Ideally startup handshake should be done during dump configuration,
2773 + * i.e., in dump_net_open(). This will be done when I figure out
2774 + * the dependency between startup handshake, subsequent write and
2775 + * various commands wrt to net-server.
2777 + if (startup_handshake)
2778 + startup_handshake = 0;
2781 + repeatCounter = 0;
2785 + dump_ndev->poll_controller(dump_ndev);
2786 + zap_completion_queue();
2791 + if (repeatCounter > 5) {
2793 + if (counter > 10000) {
2794 + if (total_loop >= 100000) {
2795 + printk("Time OUT LEAVE NOW\n");
2799 + printk("Try number %d out of "
2800 + "10 before Time Out\n",
2805 + repeatCounter = 0;
2809 + repeatCounter = 0;
2813 + switch (req.command) {
2817 + case COMM_SEND_MEM:
2818 + dump_send_mem(dump_ndev, &req, buff, len);
2822 + case COMM_START_WRITE_NETDUMP_ACK:
2827 + sprintf(tmp, "Hello, this is netdump version "
2828 + "0.%02d\n", NETCONSOLE_VERSION);
2829 + reply.code = REPLY_HELLO;
2830 + reply.nr = req.nr;
2831 + reply.info = net_dev->curr_offset;
2832 + dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
2835 + case COMM_GET_PAGE_SIZE:
2836 + sprintf(tmp, "PAGE_SIZE: %ld\n", PAGE_SIZE);
2837 + reply.code = REPLY_PAGE_SIZE;
2838 + reply.nr = req.nr;
2839 + reply.info = PAGE_SIZE;
2840 + dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
2843 + case COMM_GET_NR_PAGES:
2844 + reply.code = REPLY_NR_PAGES;
2845 + reply.nr = req.nr;
2846 + reply.info = num_physpages;
2847 + reply.info = page_counter;
2848 + sprintf(tmp, "Number of pages: %ld\n", num_physpages);
2849 + dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
2852 + case COMM_GET_MAGIC:
2853 + reply.code = REPLY_MAGIC;
2854 + reply.nr = req.nr;
2855 + reply.info = NETCONSOLE_VERSION;
2856 + dump_send_skb(dump_ndev, (char *)&dump_magic,
2857 + sizeof(dump_magic), &reply);
2860 + dump_do_sysrq(req.from);
2861 + reply.code = REPLY_SYSRQ;
2862 + reply.nr = req.nr;
2863 + reply.info = req.from;
2864 + sprintf(tmp, "SYSRQ command %d \n", req.from);
2865 + dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
2868 + reply.code = REPLY_ERROR;
2869 + reply.nr = req.nr;
2870 + reply.info = req.command;
2871 + sprintf(tmp, "Got unknown command code %d!\n",
2873 + dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
2878 + netdump_in_progress = 0;
2883 +dump_validate_config(void)
2885 + source_ip = dump_in_dev->ifa_list->ifa_local;
2887 + printk("network device %s has no local address, "
2888 + "aborting.\n", device_name);
2892 +#define IP(x) ((unsigned char *)&source_ip)[x]
2893 + printk("Source %d.%d.%d.%d", IP(0), IP(1), IP(2), IP(3));
2896 + if (!source_port) {
2897 + printk("source_port parameter not specified, aborting.\n");
2900 + printk(":%i\n", source_port);
2901 + source_port = htons(source_port);
2904 + printk("target_ip parameter not specified, aborting.\n");
2908 +#define IP(x) ((unsigned char *)&target_ip)[x]
2909 + printk("Target %d.%d.%d.%d", IP(0), IP(1), IP(2), IP(3));
2912 + if (!target_port) {
2913 + printk("target_port parameter not specified, aborting.\n");
2916 + printk(":%i\n", target_port);
2917 + target_port = htons(target_port);
2919 + printk("Target Ethernet Address %02x:%02x:%02x:%02x:%02x:%02x",
2920 + daddr[0], daddr[1], daddr[2], daddr[3], daddr[4], daddr[5]);
2922 + if ((daddr[0] & daddr[1] & daddr[2] & daddr[3] & daddr[4] &
2924 + printk("(Broadcast)");
2930 + * Prepares the dump device so we can take a dump later.
2931 + * Validates the netdump configuration parameters.
2933 + * TODO: Network connectivity check should be done here.
2936 +dump_net_open(struct dump_dev *net_dev, unsigned long arg)
2940 + /* get the interface name */
2941 + if (copy_from_user(device_name, (void *)arg, IFNAMSIZ))
2944 + if (!(dump_ndev = dev_get_by_name(device_name))) {
2945 + printk("network device %s does not exist, aborting.\n",
2950 + if (!dump_ndev->poll_controller) {
2951 + printk("network device %s does not implement polling yet, "
2952 + "aborting.\n", device_name);
2953 + retval = -1; /* return proper error */
2957 + if (!(dump_in_dev = in_dev_get(dump_ndev))) {
2958 + printk("network device %s is not an IP protocol device, "
2959 + "aborting.\n", device_name);
2964 + if ((retval = dump_validate_config()) < 0)
2967 + net_dev->curr_offset = 0;
2968 + printk("Network device %s successfully configured for dumping\n",
2972 + in_dev_put(dump_in_dev);
2974 + dev_put(dump_ndev);
2979 + * Close the dump device and release associated resources
2980 + * Invoked when unconfiguring the dump device.
2983 +dump_net_release(struct dump_dev *net_dev)
2986 + in_dev_put(dump_in_dev);
2988 + dev_put(dump_ndev);
2993 + * Prepare the dump device for use (silence any ongoing activity
2994 + * and quiesce state) when the system crashes.
2997 +dump_net_silence(struct dump_dev *net_dev)
2999 + local_irq_save(flags_global);
3000 + dump_ndev->rx_hook = dump_rx_hook;
3001 + startup_handshake = 1;
3002 + net_dev->curr_offset = 0;
3003 + printk("Dumping to network device %s on CPU %d ...\n", device_name,
3004 + smp_processor_id());
3009 + * Invoked when dumping is done. This is the time to put things back
3010 + * (i.e. undo the effects of dump_block_silence) so the device is
3011 + * available for normal use.
3014 +dump_net_resume(struct dump_dev *net_dev)
3023 + sprintf(tmp, "NETDUMP end.\n");
3024 + for( indx = 0; indx < 6; indx++) {
3025 + reply.code = REPLY_END_NETDUMP;
3028 + dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
3030 + printk("NETDUMP END!\n");
3031 + local_irq_restore(flags_global);
3032 + dump_ndev->rx_hook = NULL;
3033 + startup_handshake = 0;
3038 + * Seek to the specified offset in the dump device.
3039 + * Makes sure this is a valid offset, otherwise returns an error.
3042 +dump_net_seek(struct dump_dev *net_dev, loff_t off)
3045 + * For now using DUMP_HEADER_OFFSET as hard coded value,
3046 + * See dump_block_seekin dump_blockdev.c to know how to
3047 + * do this properly.
3049 + net_dev->curr_offset = off + DUMP_HEADER_OFFSET;
3057 +dump_net_write(struct dump_dev *net_dev, void *buf, unsigned long len)
3062 + cnt = len/ PAGE_SIZE;
3064 + for (i = 0; i < cnt; i++) {
3065 + off = i* PAGE_SIZE;
3066 + ret = do_netdump(net_dev, buf+off, PAGE_SIZE);
3069 + net_dev->curr_offset = net_dev->curr_offset + PAGE_SIZE;
3075 + * check if the last dump i/o is over and ready for next request
3078 +dump_net_ready(struct dump_dev *net_dev, void *buf)
3084 + * ioctl function used for configuring network dump
3087 +dump_net_ioctl(struct dump_dev *net_dev, unsigned int cmd, unsigned long arg)
3090 + case DIOSTARGETIP:
3093 + case DIOSTARGETPORT:
3094 + target_port = (u16)arg;
3096 + case DIOSSOURCEPORT:
3097 + source_port = (u16)arg;
3100 + return copy_from_user(daddr, (void *)arg, 6);
3102 + case DIOGTARGETIP:
3103 + case DIOGTARGETPORT:
3104 + case DIOGSOURCEPORT:
3113 +struct dump_dev_ops dump_netdev_ops = {
3114 + .open = dump_net_open,
3115 + .release = dump_net_release,
3116 + .silence = dump_net_silence,
3117 + .resume = dump_net_resume,
3118 + .seek = dump_net_seek,
3119 + .write = dump_net_write,
3120 + /* .read not implemented */
3121 + .ready = dump_net_ready,
3122 + .ioctl = dump_net_ioctl
3125 +static struct dump_dev default_dump_netdev = {
3126 + .type_name = "networkdev",
3127 + .ops = &dump_netdev_ops,
3132 +dump_netdev_init(void)
3134 + default_dump_netdev.curr_offset = 0;
3136 + if (dump_register_device(&default_dump_netdev) < 0) {
3137 + printk("network dump device driver registration failed\n");
3140 + printk("network device driver for LKCD registered\n");
3142 + get_random_bytes(&dump_magic, sizeof(dump_magic));
3147 +dump_netdev_cleanup(void)
3149 + dump_unregister_device(&default_dump_netdev);
3152 +MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
3153 +MODULE_DESCRIPTION("Network Dump Driver for Linux Kernel Crash Dump (LKCD)");
3154 +MODULE_LICENSE("GPL");
3156 +module_init(dump_netdev_init);
3157 +module_exit(dump_netdev_cleanup);
3158 Index: linux-2.6.0-test5/drivers/dump/dump_overlay.c
3159 ===================================================================
3160 --- linux-2.6.0-test5.orig/drivers/dump/dump_overlay.c 2003-09-26 14:26:34.000000000 +0800
3161 +++ linux-2.6.0-test5/drivers/dump/dump_overlay.c 2003-09-26 14:26:34.000000000 +0800
3164 + * Two-stage soft-boot based dump scheme methods (memory overlay
3165 + * with post soft-boot writeout)
3167 + * Started: Oct 2002 - Suparna Bhattacharya <suparna@in.ibm.com>
3169 + * This approach of saving the dump in memory and writing it
3170 + * out after a softboot without clearing memory is derived from the
3171 + * Mission Critical Linux dump implementation. Credits and a big
3172 + * thanks for letting the lkcd project make use of the excellent
3173 + * piece of work and also for helping with clarifications and
3174 + * tips along the way are due to:
3175 + * Dave Winchell <winchell@mclx.com> (primary author of mcore)
3177 + * Jeff Moyer <moyer@mclx.com>
3178 + * Josh Huber <huber@mclx.com>
3180 + * For those familiar with the mcore implementation, the key
3181 + * differences/extensions here are in allowing entire memory to be
3182 + * saved (in compressed form) through a careful ordering scheme
3183 + * on both the way down as well on the way up after boot, the latter
3184 + * for supporting the LKCD notion of passes in which most critical
3185 + * data is the first to be saved to the dump device. Also the post
3186 + * boot writeout happens from within the kernel rather than driven
3189 + * The sequence is orchestrated through the abstraction of "dumpers",
3190 + * one for the first stage which then sets up the dumper for the next
3191 + * stage, providing for a smooth and flexible reuse of the singlestage
3192 + * dump scheme methods and a handle to pass dump device configuration
3193 + * information across the soft boot.
3195 + * Copyright (C) 2002 International Business Machines Corp.
3197 + * This code is released under version 2 of the GNU GPL.
3201 + * Disruptive dumping using the second kernel soft-boot option
3202 + * for issuing dump i/o operates in 2 stages:
3204 + * (1) - Saves the (compressed & formatted) dump in memory using a
3205 + * carefully ordered overlay scheme designed to capture the
3206 + * entire physical memory or selective portions depending on
3207 + * dump config settings,
3208 + * - Registers the stage 2 dumper and
3209 + * - Issues a soft reboot w/o clearing memory.
3211 + * The overlay scheme starts with a small bootstrap free area
3212 + * and follows a reverse ordering of passes wherein it
3213 + * compresses and saves data starting with the least critical
3214 + * areas first, thus freeing up the corresponding pages to
3215 + * serve as destination for subsequent data to be saved, and
3216 + * so on. With a good compression ratio, this makes it feasible
3217 + * to capture an entire physical memory dump without significantly
3218 + * reducing memory available during regular operation.
3220 + * (2) Post soft-reboot, runs through the saved memory dump and
3221 + * writes it out to disk, this time around, taking care to
3222 + * save the more critical data first (i.e. pages which figure
3223 + * in early passes for a regular dump). Finally issues a
3226 + * Since the data was saved in memory after selection/filtering
3227 + * and formatted as per the chosen output dump format, at this
3228 + * stage the filter and format actions are just dummy (or
3229 + * passthrough) actions, except for influence on ordering of
3233 +#include <linux/types.h>
3234 +#include <linux/kernel.h>
3235 +#include <linux/highmem.h>
3236 +#include <linux/bootmem.h>
3237 +#include <linux/dump.h>
3238 +#include "dump_methods.h"
3240 +extern struct list_head dumper_list_head;
3241 +extern struct dump_memdev *dump_memdev;
3242 +extern struct dumper dumper_stage2;
3243 +struct dump_config_block *dump_saved_config = NULL;
3244 +extern struct dump_blockdev *dump_blockdev;
3245 +static struct dump_memdev *saved_dump_memdev = NULL;
3246 +static struct dumper *saved_dumper = NULL;
3249 +extern void dump_display_map(struct dump_memdev *);
3252 +struct dumper *dumper_by_name(char *name)
3255 + struct dumper *dumper;
3256 + list_for_each_entry(dumper, &dumper_list_head, dumper_list)
3257 + if (!strncmp(dumper->name, name, 32))
3263 + /* Temporary proof of concept */
3264 + if (!strncmp(dumper_stage2.name, name, 32))
3265 + return &dumper_stage2;
3270 +#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
3271 +extern void dump_early_reserve_map(struct dump_memdev *);
3273 +void crashdump_reserve(void)
3275 + extern unsigned long crashdump_addr;
3277 + if (crashdump_addr == 0xdeadbeef)
3280 + /* reserve dump config and saved dump pages */
3281 + dump_saved_config = (struct dump_config_block *)crashdump_addr;
3282 + /* magic verification */
3283 + if (dump_saved_config->magic != DUMP_MAGIC_LIVE) {
3284 + printk("Invalid dump magic. Ignoring dump\n");
3285 + dump_saved_config = NULL;
3289 + printk("Dump may be available from previous boot\n");
3291 + reserve_bootmem(virt_to_phys((void *)crashdump_addr),
3292 + PAGE_ALIGN(sizeof(struct dump_config_block)));
3293 + dump_early_reserve_map(&dump_saved_config->memdev);
3299 + * Loads the dump configuration from a memory block saved across soft-boot
3300 + * The ops vectors need fixing up as the corresp. routines may have
3301 + * relocated in the new soft-booted kernel.
3303 +int dump_load_config(struct dump_config_block *config)
3305 + struct dumper *dumper;
3306 + struct dump_data_filter *filter_table, *filter;
3307 + struct dump_dev *dev;
3310 + if (config->magic != DUMP_MAGIC_LIVE)
3311 + return -ENOENT; /* not a valid config */
3313 + /* initialize generic config data */
3314 + memcpy(&dump_config, &config->config, sizeof(dump_config));
3316 + /* initialize dumper state */
3317 + if (!(dumper = dumper_by_name(config->dumper.name))) {
3318 + printk("dumper name mismatch\n");
3319 + return -ENOENT; /* dumper mismatch */
3322 + /* verify and fixup schema */
3323 + if (strncmp(dumper->scheme->name, config->scheme.name, 32)) {
3324 + printk("dumper scheme mismatch\n");
3325 + return -ENOENT; /* mismatch */
3327 + config->scheme.ops = dumper->scheme->ops;
3328 + config->dumper.scheme = &config->scheme;
3330 + /* verify and fixup filter operations */
3331 + filter_table = dumper->filter;
3332 + for (i = 0, filter = config->filter_table;
3333 + ((i < MAX_PASSES) && filter_table[i].selector);
3335 + if (strncmp(filter_table[i].name, filter->name, 32)) {
3336 + printk("dump filter mismatch\n");
3337 + return -ENOENT; /* filter name mismatch */
3339 + filter->selector = filter_table[i].selector;
3341 + config->dumper.filter = config->filter_table;
3343 + /* fixup format */
3344 + if (strncmp(dumper->fmt->name, config->fmt.name, 32)) {
3345 + printk("dump format mismatch\n");
3346 + return -ENOENT; /* mismatch */
3348 + config->fmt.ops = dumper->fmt->ops;
3349 + config->dumper.fmt = &config->fmt;
3351 + /* fixup target device */
3352 + dev = (struct dump_dev *)(&config->dev[0]);
3353 + if (dumper->dev == NULL) {
3354 + pr_debug("Vanilla dumper - assume default\n");
3355 + if (dump_dev == NULL)
3357 + dumper->dev = dump_dev;
3360 + if (strncmp(dumper->dev->type_name, dev->type_name, 32)) {
3361 + printk("dump dev type mismatch %s instead of %s\n",
3362 + dev->type_name, dumper->dev->type_name);
3363 + return -ENOENT; /* mismatch */
3365 + dev->ops = dumper->dev->ops;
3366 + config->dumper.dev = dev;
3368 + /* fixup memory device containing saved dump pages */
3369 + /* assume statically init'ed dump_memdev */
3370 + config->memdev.ddev.ops = dump_memdev->ddev.ops;
3371 + /* switch to memdev from prev boot */
3372 + saved_dump_memdev = dump_memdev; /* remember current */
3373 + dump_memdev = &config->memdev;
3375 + /* Make this the current primary dumper */
3376 + dump_config.dumper = &config->dumper;
3381 +/* Saves the dump configuration in a memory block for use across a soft-boot */
3382 +int dump_save_config(struct dump_config_block *config)
3384 + printk("saving dump config settings\n");
3386 + /* dump config settings */
3387 + memcpy(&config->config, &dump_config, sizeof(dump_config));
3389 + /* dumper state */
3390 + memcpy(&config->dumper, dump_config.dumper, sizeof(struct dumper));
3391 + memcpy(&config->scheme, dump_config.dumper->scheme,
3392 + sizeof(struct dump_scheme));
3393 + memcpy(&config->fmt, dump_config.dumper->fmt, sizeof(struct dump_fmt));
3394 + memcpy(&config->dev[0], dump_config.dumper->dev,
3395 + sizeof(struct dump_anydev));
3396 + memcpy(&config->filter_table, dump_config.dumper->filter,
3397 + sizeof(struct dump_data_filter)*MAX_PASSES);
3399 + /* handle to saved mem pages */
3400 + memcpy(&config->memdev, dump_memdev, sizeof(struct dump_memdev));
3402 + config->magic = DUMP_MAGIC_LIVE;
3407 +int dump_init_stage2(struct dump_config_block *saved_config)
3411 + pr_debug("dump_init_stage2\n");
3412 + /* Check if dump from previous boot exists */
3413 + if (saved_config) {
3414 + printk("loading dumper from previous boot \n");
3415 + /* load and configure dumper from previous boot */
3416 + if ((err = dump_load_config(saved_config)))
3419 + if (!dump_oncpu) {
3420 + if ((err = dump_configure(dump_config.dump_device))) {
3421 + printk("Stage 2 dump configure failed\n");
3427 + dump_dev = dump_config.dumper->dev;
3428 + /* write out the dump */
3429 + err = dump_generic_execute(NULL, NULL);
3431 + dump_saved_config = NULL;
3433 + if (!dump_oncpu) {
3434 + dump_unconfigure();
3440 + /* no dump to write out */
3441 + printk("no dumper from previous boot \n");
3446 +extern void dump_mem_markpages(struct dump_memdev *);
3448 +int dump_switchover_stage(void)
3452 + /* trigger stage 2 rightaway - in real life would be after soft-boot */
3453 + /* dump_saved_config would be a boot param */
3454 + saved_dump_memdev = dump_memdev;
3455 + saved_dumper = dump_config.dumper;
3456 + ret = dump_init_stage2(dump_saved_config);
3457 + dump_memdev = saved_dump_memdev;
3458 + dump_config.dumper = saved_dumper;
3462 +int dump_activate_softboot(void)
3466 + /* temporary - switchover to writeout previously saved dump */
3467 + err = dump_switchover_stage(); /* non-disruptive case */
3469 + dump_config.dumper = &dumper_stage1; /* set things back */
3473 + dump_silence_level = DUMP_HALT_CPUS;
3474 + /* wait till we become the only cpu */
3475 + /* maybe by checking for online cpus ? */
3477 + /* now call into kexec */
3480 + * should we call reboot notifiers ? inappropriate for panic ?
3481 + * what about device_shutdown() ?
3482 + * is explicit bus master disabling needed or can we do that
3483 + * through driverfs ?
3488 +/* --- DUMP SCHEME ROUTINES --- */
3490 +static inline int dump_buf_pending(struct dumper *dumper)
3492 + return (dumper->curr_buf - dumper->dump_buf);
3495 +/* Invoked during stage 1 of soft-reboot based dumping */
3496 +int dump_overlay_sequencer(void)
3498 + struct dump_data_filter *filter = dump_config.dumper->filter;
3499 + struct dump_data_filter *filter2 = dumper_stage2.filter;
3500 + int pass = 0, err = 0, save = 0;
3501 + int (*action)(unsigned long, unsigned long);
3503 + /* Make sure gzip compression is being used */
3504 + if (dump_config.dumper->compress->compress_type != DUMP_COMPRESS_GZIP) {
3505 + printk(" Please set GZIP compression \n");
3509 + /* start filling in dump data right after the header */
3510 + dump_config.dumper->curr_offset =
3511 + PAGE_ALIGN(dump_config.dumper->header_len);
3513 + /* Locate the last pass */
3514 + for (;filter->selector; filter++, pass++);
3517 + * Start from the end backwards: overlay involves a reverse
3518 + * ordering of passes, since less critical pages are more
3519 + * likely to be reusable as scratch space once we are through
3522 + for (--pass, --filter; pass >= 0; pass--, filter--)
3524 + /* Assumes passes are exclusive (even across dumpers) */
3525 + /* Requires care when coding the selection functions */
3526 + if ((save = filter->level_mask & dump_config.level))
3527 + action = dump_save_data;
3529 + action = dump_skip_data;
3531 + /* Remember the offset where this pass started */
3532 + /* The second stage dumper would use this */
3533 + if (dump_buf_pending(dump_config.dumper) & (PAGE_SIZE - 1)) {
3534 + pr_debug("Starting pass %d with pending data\n", pass);
3535 + pr_debug("filling dummy data to page-align it\n");
3536 + dump_config.dumper->curr_buf = (void *)PAGE_ALIGN(
3537 + (unsigned long)dump_config.dumper->curr_buf);
3540 + filter2[pass].start = dump_config.dumper->curr_offset
3541 + + dump_buf_pending(dump_config.dumper);
3543 + err = dump_iterator(pass, action, filter);
3545 + filter2[pass].end = dump_config.dumper->curr_offset
3546 + + dump_buf_pending(dump_config.dumper);
3549 + printk("dump_overlay_seq: failure %d in pass %d\n",
3553 + printk("\n %d overlay pages %s of %d each in pass %d\n",
3554 + err, save ? "saved" : "skipped", DUMP_PAGE_SIZE, pass);
3560 +/* from dump_memdev.c */
3561 +extern struct page *dump_mem_lookup(struct dump_memdev *dev, unsigned long loc);
3562 +extern struct page *dump_mem_next_page(struct dump_memdev *dev);
3564 +static inline struct page *dump_get_saved_page(loff_t loc)
3566 + return (dump_mem_lookup(dump_memdev, loc >> PAGE_SHIFT));
3569 +static inline struct page *dump_next_saved_page(void)
3571 + return (dump_mem_next_page(dump_memdev));
3575 + * Iterates over list of saved dump pages. Invoked during second stage of
3576 + * soft boot dumping
3578 + * Observation: If additional selection is desired at this stage then
3579 + * a different iterator could be written which would advance
3580 + * to the next page header everytime instead of blindly picking up
3581 + * the data. In such a case loc would be interpreted differently.
3582 + * At this moment however a blind pass seems sufficient, cleaner and
3585 +int dump_saved_data_iterator(int pass, int (*action)(unsigned long,
3586 + unsigned long), struct dump_data_filter *filter)
3588 + loff_t loc = filter->start;
3589 + struct page *page;
3590 + unsigned long count = 0;
3594 + printk("pass %d, start off 0x%llx end offset 0x%llx\n", pass,
3595 + filter->start, filter->end);
3597 + /* loc will get treated as logical offset into stage 1 */
3598 + page = dump_get_saved_page(loc);
3600 + for (; loc < filter->end; loc += PAGE_SIZE) {
3601 + dump_config.dumper->curr_loc = loc;
3603 + printk("no more saved data for pass %d\n", pass);
3606 + sz = (loc + PAGE_SIZE > filter->end) ? filter->end - loc :
3609 + if (page && filter->selector(pass, (unsigned long)page,
3611 + pr_debug("mem offset 0x%llx\n", loc);
3612 + if ((err = action((unsigned long)page, sz)))
3616 + /* clear the contents of page */
3617 + /* fixme: consider using KM_DUMP instead */
3618 + clear_highpage(page);
3621 + page = dump_next_saved_page();
3624 + return err ? err : count;
3627 +static inline int dump_overlay_pages_done(struct page *page, int nr)
3631 + for (; nr ; page++, nr--) {
3632 + if (dump_check_and_free_page(dump_memdev, page))
3638 +int dump_overlay_save_data(unsigned long loc, unsigned long len)
3641 + struct page *page = (struct page *)loc;
3642 + static unsigned long cnt = 0;
3644 + if ((err = dump_generic_save_data(loc, len)))
3647 + if (dump_overlay_pages_done(page, len >> PAGE_SHIFT)) {
3649 + if (!(cnt & 0x7f))
3650 + pr_debug("released page 0x%lx\n", page_to_pfn(page));
3657 +int dump_overlay_skip_data(unsigned long loc, unsigned long len)
3659 + struct page *page = (struct page *)loc;
3661 + dump_overlay_pages_done(page, len >> PAGE_SHIFT);
3665 +int dump_overlay_resume(void)
3670 + * switch to stage 2 dumper, save dump_config_block
3671 + * and then trigger a soft-boot
3673 + dumper_stage2.header_len = dump_config.dumper->header_len;
3674 + dump_config.dumper = &dumper_stage2;
3675 + if ((err = dump_save_config(dump_saved_config)))
3678 + dump_dev = dump_config.dumper->dev;
3681 + err = dump_switchover_stage(); /* plugs into soft boot mechanism */
3682 + dump_config.dumper = &dumper_stage1; /* set things back */
3686 +int dump_overlay_configure(unsigned long devid)
3688 + struct dump_dev *dev;
3689 + struct dump_config_block *saved_config = dump_saved_config;
3692 + /* If there is a previously saved dump, write it out first */
3693 + if (saved_config) {
3694 + printk("Processing old dump pending writeout\n");
3695 + err = dump_switchover_stage();
3697 + printk("failed to writeout saved dump\n");
3700 + dump_free_mem(saved_config); /* testing only: not after boot */
3703 + dev = dumper_stage2.dev = dump_config.dumper->dev;
3704 + /* From here on the intermediate dump target is memory-only */
3705 + dump_dev = dump_config.dumper->dev = &dump_memdev->ddev;
3706 + if ((err = dump_generic_configure(0))) {
3707 + printk("dump generic configure failed: err %d\n", err);
3711 + dumper_stage2.dump_buf = dump_config.dumper->dump_buf;
3713 + /* Sanity check on the actual target dump device */
3714 + if (!dev || (err = dev->ops->open(dev, devid))) {
3717 + /* TBD: should we release the target if this is soft-boot only ? */
3719 + /* alloc a dump config block area to save across reboot */
3720 + if (!(dump_saved_config = dump_alloc_mem(sizeof(struct
3721 + dump_config_block)))) {
3722 + printk("dump config block alloc failed\n");
3723 + /* undo configure */
3724 + dump_generic_unconfigure();
3727 + dump_config.dump_addr = (unsigned long)dump_saved_config;
3728 + printk("Dump config block of size %d set up at 0x%lx\n",
3729 + sizeof(*dump_saved_config), (unsigned long)dump_saved_config);
3733 +int dump_overlay_unconfigure(void)
3735 + struct dump_dev *dev = dumper_stage2.dev;
3738 + pr_debug("dump_overlay_unconfigure\n");
3739 + /* Close the secondary device */
3740 + dev->ops->release(dev);
3741 + pr_debug("released secondary device\n");
3743 + err = dump_generic_unconfigure();
3744 + pr_debug("Unconfigured generic portions\n");
3745 + dump_free_mem(dump_saved_config);
3746 + dump_saved_config = NULL;
3747 + pr_debug("Freed saved config block\n");
3748 + dump_dev = dump_config.dumper->dev = dumper_stage2.dev;
3750 + printk("Unconfigured overlay dumper\n");
3754 +int dump_staged_unconfigure(void)
3757 + struct dump_config_block *saved_config = dump_saved_config;
3758 + struct dump_dev *dev;
3760 + pr_debug("dump_staged_unconfigure\n");
3761 + err = dump_generic_unconfigure();
3763 + /* now check if there is a saved dump waiting to be written out */
3764 + if (saved_config) {
3765 + printk("Processing saved dump pending writeout\n");
3766 + if ((err = dump_switchover_stage())) {
3767 + printk("Error in commiting saved dump at 0x%lx\n",
3768 + (unsigned long)saved_config);
3769 + printk("Old dump may hog memory\n");
3771 + dump_free_mem(saved_config);
3772 + pr_debug("Freed saved config block\n");
3774 + dump_saved_config = NULL;
3776 + dev = &dump_memdev->ddev;
3777 + dev->ops->release(dev);
3779 + printk("Unconfigured second stage dumper\n");
3784 +/* ----- PASSTHRU FILTER ROUTINE --------- */
3786 +/* transparent - passes everything through */
3787 +int dump_passthru_filter(int pass, unsigned long loc, unsigned long sz)
3792 +/* ----- PASSTRU FORMAT ROUTINES ---- */
3795 +int dump_passthru_configure_header(const char *panic_str, const struct pt_regs *regs)
3797 + dump_config.dumper->header_dirty++;
3801 +/* Copies bytes of data from page(s) to the specified buffer */
3802 +int dump_copy_pages(void *buf, struct page *page, unsigned long sz)
3804 + unsigned long len = 0, bytes;
3807 + while (len < sz) {
3808 + addr = kmap_atomic(page, KM_DUMP);
3809 + bytes = (sz > len + PAGE_SIZE) ? PAGE_SIZE : sz - len;
3810 + memcpy(buf, addr, bytes);
3811 + kunmap_atomic(addr, KM_DUMP);
3816 + /* memset(dump_config.dumper->curr_buf, 0x57, len); temporary */
3821 +int dump_passthru_update_header(void)
3823 + long len = dump_config.dumper->header_len;
3824 + struct page *page;
3825 + void *buf = dump_config.dumper->dump_buf;
3828 + if (!dump_config.dumper->header_dirty)
3831 + pr_debug("Copying header of size %ld bytes from memory\n", len);
3832 + if (len > DUMP_BUFFER_SIZE)
3835 + page = dump_mem_lookup(dump_memdev, 0);
3836 + for (; (len > 0) && page; buf += PAGE_SIZE, len -= PAGE_SIZE) {
3837 + if ((err = dump_copy_pages(buf, page, PAGE_SIZE)))
3839 + page = dump_mem_next_page(dump_memdev);
3842 + printk("Incomplete header saved in mem\n");
3846 + if ((err = dump_dev_seek(0))) {
3847 + printk("Unable to seek to dump header offset\n");
3850 + err = dump_ll_write(dump_config.dumper->dump_buf,
3851 + buf - dump_config.dumper->dump_buf);
3852 + if (err < dump_config.dumper->header_len)
3853 + return (err < 0) ? err : -ENOSPC;
3855 + dump_config.dumper->header_dirty = 0;
3859 +static loff_t next_dph_offset = 0;
3861 +static int dph_valid(struct __dump_page *dph)
3863 + if ((dph->dp_address & (PAGE_SIZE - 1)) || (dph->dp_flags
3864 + > DUMP_DH_COMPRESSED) || (!dph->dp_flags) ||
3865 + (dph->dp_size > PAGE_SIZE)) {
3866 + printk("dp->address = 0x%llx, dp->size = 0x%x, dp->flag = 0x%x\n",
3867 + dph->dp_address, dph->dp_size, dph->dp_flags);
3873 +int dump_verify_lcrash_data(void *buf, unsigned long sz)
3875 + struct __dump_page *dph;
3877 + /* sanity check for page headers */
3878 + while (next_dph_offset + sizeof(*dph) < sz) {
3879 + dph = (struct __dump_page *)(buf + next_dph_offset);
3880 + if (!dph_valid(dph)) {
3881 + printk("Invalid page hdr at offset 0x%llx\n",
3885 + next_dph_offset += dph->dp_size + sizeof(*dph);
3888 + next_dph_offset -= sz;
3893 + * TBD/Later: Consider avoiding the copy by using a scatter/gather
3894 + * vector representation for the dump buffer
3896 +int dump_passthru_add_data(unsigned long loc, unsigned long sz)
3898 + struct page *page = (struct page *)loc;
3899 + void *buf = dump_config.dumper->curr_buf;
3902 + if ((err = dump_copy_pages(buf, page, sz))) {
3903 + printk("dump_copy_pages failed");
3907 + if ((err = dump_verify_lcrash_data(buf, sz))) {
3908 + printk("dump_verify_lcrash_data failed\n");
3909 + printk("Invalid data for pfn 0x%lx\n", page_to_pfn(page));
3910 + printk("Page flags 0x%lx\n", page->flags);
3911 + printk("Page count 0x%x\n", atomic_read(&page->count));
3915 + dump_config.dumper->curr_buf = buf + sz;
3921 +/* Stage 1 dumper: Saves compressed dump in memory and soft-boots system */
3923 +/* Scheme to overlay saved data in memory for writeout after a soft-boot */
3924 +struct dump_scheme_ops dump_scheme_overlay_ops = {
3925 + .configure = dump_overlay_configure,
3926 + .unconfigure = dump_overlay_unconfigure,
3927 + .sequencer = dump_overlay_sequencer,
3928 + .iterator = dump_page_iterator,
3929 + .save_data = dump_overlay_save_data,
3930 + .skip_data = dump_overlay_skip_data,
3931 + .write_buffer = dump_generic_write_buffer
3934 +struct dump_scheme dump_scheme_overlay = {
3935 + .name = "overlay",
3936 + .ops = &dump_scheme_overlay_ops
3940 +/* Stage 1 must use a good compression scheme - default to gzip */
3941 +extern struct __dump_compress dump_gzip_compression;
3943 +struct dumper dumper_stage1 = {
3945 + .scheme = &dump_scheme_overlay,
3946 + .fmt = &dump_fmt_lcrash,
3947 + .compress = &dump_none_compression, /* needs to be gzip */
3948 + .filter = dump_filter_table,
3952 +/* Stage 2 dumper: Activated after softboot to write out saved dump to device */
3954 +/* Formatter that transfers data as is (transparent) w/o further conversion */
3955 +struct dump_fmt_ops dump_fmt_passthru_ops = {
3956 + .configure_header = dump_passthru_configure_header,
3957 + .update_header = dump_passthru_update_header,
3958 + .save_context = NULL, /* unused */
3959 + .add_data = dump_passthru_add_data,
3960 + .update_end_marker = dump_lcrash_update_end_marker
3963 +struct dump_fmt dump_fmt_passthru = {
3964 + .name = "passthru",
3965 + .ops = &dump_fmt_passthru_ops
3968 +/* Filter that simply passes along any data within the range (transparent)*/
3969 +/* Note: The start and end ranges in the table are filled in at run-time */
3971 +extern int dump_filter_none(int pass, unsigned long loc, unsigned long sz);
3973 +struct dump_data_filter dump_passthru_filtertable[MAX_PASSES] = {
3974 +{.name = "passkern", .selector = dump_passthru_filter,
3975 + .level_mask = DUMP_MASK_KERN },
3976 +{.name = "passuser", .selector = dump_passthru_filter,
3977 + .level_mask = DUMP_MASK_USED },
3978 +{.name = "passunused", .selector = dump_passthru_filter,
3979 + .level_mask = DUMP_MASK_UNUSED },
3980 +{.name = "none", .selector = dump_filter_none,
3981 + .level_mask = DUMP_MASK_REST }
3985 +/* Scheme to handle data staged / preserved across a soft-boot */
3986 +struct dump_scheme_ops dump_scheme_staged_ops = {
3987 + .configure = dump_generic_configure,
3988 + .unconfigure = dump_staged_unconfigure,
3989 + .sequencer = dump_generic_sequencer,
3990 + .iterator = dump_saved_data_iterator,
3991 + .save_data = dump_generic_save_data,
3992 + .skip_data = dump_generic_skip_data,
3993 + .write_buffer = dump_generic_write_buffer
3996 +struct dump_scheme dump_scheme_staged = {
3998 + .ops = &dump_scheme_staged_ops
4001 +/* The stage 2 dumper comprising all these */
4002 +struct dumper dumper_stage2 = {
4004 + .scheme = &dump_scheme_staged,
4005 + .fmt = &dump_fmt_passthru,
4006 + .compress = &dump_none_compression,
4007 + .filter = dump_passthru_filtertable,
4011 Index: linux-2.6.0-test5/drivers/dump/dump_rle.c
4012 ===================================================================
4013 --- linux-2.6.0-test5.orig/drivers/dump/dump_rle.c 2003-09-26 14:26:34.000000000 +0800
4014 +++ linux-2.6.0-test5/drivers/dump/dump_rle.c 2003-09-26 14:26:34.000000000 +0800
4017 + * RLE Compression functions for kernel crash dumps.
4019 + * Created by: Matt Robinson (yakker@sourceforge.net)
4020 + * Copyright 2001 Matt D. Robinson. All rights reserved.
4022 + * This code is released under version 2 of the GNU GPL.
4026 +#include <linux/config.h>
4027 +#include <linux/module.h>
4028 +#include <linux/sched.h>
4029 +#include <linux/fs.h>
4030 +#include <linux/file.h>
4031 +#include <linux/init.h>
4032 +#include <linux/dump.h>
4035 + * Name: dump_compress_rle()
4036 + * Func: Compress a DUMP_PAGE_SIZE (hardware) page down to something more
4037 + * reasonable, if possible. This is the same routine we use in IRIX.
4040 +dump_compress_rle(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
4042 + u16 ri, wi, count = 0;
4043 + u_char value = 0, cur_byte;
4046 + * If the block should happen to "compress" to larger than the
4047 + * buffer size, allocate a larger one and change cur_buf_size.
4052 + while (ri < oldsize) {
4054 + cur_byte = value = old[ri];
4057 + if (count == 255) {
4058 + if (wi + 3 > oldsize) {
4062 + new[wi++] = count;
4063 + new[wi++] = value;
4064 + value = cur_byte = old[ri];
4067 + if ((cur_byte = old[ri]) == value) {
4071 + if (wi + 3 > oldsize) {
4075 + new[wi++] = count;
4076 + new[wi++] = value;
4077 + } else if (count == 1) {
4079 + if (wi + 3 > oldsize) {
4086 + if (wi + 2 > oldsize) {
4089 + new[wi++] = value;
4090 + new[wi++] = value;
4092 + } else { /* count == 0 */
4094 + if (wi + 2 > oldsize) {
4097 + new[wi++] = value;
4098 + new[wi++] = value;
4100 + if (wi + 1 > oldsize) {
4103 + new[wi++] = value;
4105 + } /* if count > 1 */
4110 + } /* if byte == value */
4112 + } /* if count == 255 */
4114 + } /* if ri == 0 */
4119 + if (wi + 3 > oldsize) {
4123 + new[wi++] = count;
4124 + new[wi++] = value;
4125 + } else if (count == 1) {
4127 + if (wi + 3 > oldsize)
4133 + if (wi + 2 > oldsize)
4135 + new[wi++] = value;
4136 + new[wi++] = value;
4138 + } else { /* count == 0 */
4140 + if (wi + 2 > oldsize)
4142 + new[wi++] = value;
4143 + new[wi++] = value;
4145 + if (wi + 1 > oldsize)
4147 + new[wi++] = value;
4149 + } /* if count > 1 */
4156 +/* setup the rle compression functionality */
4157 +static struct __dump_compress dump_rle_compression = {
4158 + .compress_type = DUMP_COMPRESS_RLE,
4159 + .compress_func = dump_compress_rle,
4160 + .compress_name = "RLE",
4164 + * Name: dump_compress_rle_init()
4165 + * Func: Initialize rle compression for dumping.
4168 +dump_compress_rle_init(void)
4170 + dump_register_compression(&dump_rle_compression);
4175 + * Name: dump_compress_rle_cleanup()
4176 + * Func: Remove rle compression for dumping.
4179 +dump_compress_rle_cleanup(void)
4181 + dump_unregister_compression(DUMP_COMPRESS_RLE);
4184 +/* module initialization */
4185 +module_init(dump_compress_rle_init);
4186 +module_exit(dump_compress_rle_cleanup);
4188 +MODULE_LICENSE("GPL");
4189 +MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
4190 +MODULE_DESCRIPTION("RLE compression module for crash dump driver");
4191 Index: linux-2.6.0-test5/drivers/dump/dump_scheme.c
4192 ===================================================================
4193 --- linux-2.6.0-test5.orig/drivers/dump/dump_scheme.c 2003-09-26 14:26:34.000000000 +0800
4194 +++ linux-2.6.0-test5/drivers/dump/dump_scheme.c 2003-09-26 14:26:34.000000000 +0800
4197 + * Default single stage dump scheme methods
4199 + * Previously a part of dump_base.c
4201 + * Started: Oct 2002 - Suparna Bhattacharya <suparna@in.ibm.com>
4202 + * Split and rewrote LKCD dump scheme to generic dump method
4204 + * Derived from original code created by
4205 + * Matt Robinson <yakker@sourceforge.net>)
4207 + * Contributions from SGI, IBM, HP, MCL, and others.
4209 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
4210 + * Copyright (C) 2001 - 2002 Matt D. Robinson. All rights reserved.
4211 + * Copyright (C) 2002 International Business Machines Corp.
4213 + * This code is released under version 2 of the GNU GPL.
4217 + * Implements the default dump scheme, i.e. single-stage gathering and
4218 + * saving of dump data directly to the target device, which operates in
4219 + * a push mode, where the dumping system decides what data it saves
4220 + * taking into account pre-specified dump config options.
4222 + * Aside: The 2-stage dump scheme, where there is a soft-reset between
4223 + * the gathering and saving phases, also reuses some of these
4224 + * default routines (see dump_overlay.c)
4226 +#include <linux/types.h>
4227 +#include <linux/kernel.h>
4228 +#include <linux/mm.h>
4229 +#include <linux/slab.h>
4230 +#include <linux/delay.h>
4231 +#include <linux/reboot.h>
4232 +#include <linux/nmi.h>
4233 +#include <linux/dump.h>
4234 +#include "dump_methods.h"
4236 +extern int panic_timeout; /* time before reboot */
4238 +extern void dump_speedo(int);
4240 +/* Default sequencer used during single stage dumping */
4241 +/* Also invoked during stage 2 of soft-boot based dumping */
4242 +int dump_generic_sequencer(void)
4244 + struct dump_data_filter *filter = dump_config.dumper->filter;
4245 + int pass = 0, err = 0, save = 0;
4246 + int (*action)(unsigned long, unsigned long);
4249 + * We want to save the more critical data areas first in
4250 + * case we run out of space, encounter i/o failures, or get
4251 + * interrupted otherwise and have to give up midway
4252 + * So, run through the passes in increasing order
4254 + for (;filter->selector; filter++, pass++)
4256 + /* Assumes passes are exclusive (even across dumpers) */
4257 + /* Requires care when coding the selection functions */
4258 + if ((save = filter->level_mask & dump_config.level))
4259 + action = dump_save_data;
4261 + action = dump_skip_data;
4263 + if ((err = dump_iterator(pass, action, filter)) < 0)
4266 + printk("\n %d dump pages %s of %d each in pass %d\n",
4267 + err, save ? "saved" : "skipped", DUMP_PAGE_SIZE, pass);
4271 + return (err < 0) ? err : 0;
4274 +static inline struct page *dump_get_page(loff_t loc)
4276 + unsigned long page_index = loc >> PAGE_SHIFT;
4278 + /* todo: complete this to account for ia64/discontig mem */
4279 + /* todo: and to check for validity, ram page, no i/o mem etc */
4280 + /* need to use pfn/physaddr equiv of kern_addr_valid */
4281 + if (__dump_page_valid(page_index))
4282 + return pfn_to_page(page_index);
4288 +/* Default iterator: for singlestage and stage 1 of soft-boot dumping */
4289 +/* Iterates over range of physical memory pages in DUMP_PAGE_SIZE increments */
4290 +int dump_page_iterator(int pass, int (*action)(unsigned long, unsigned long),
4291 + struct dump_data_filter *filter)
4293 + /* Todo : fix unit, type */
4295 + int count = 0, err = 0;
4296 + struct page *page;
4298 + /* Todo: Add membanks code */
4299 + /* TBD: Check if we need to address DUMP_PAGE_SIZE < PAGE_SIZE */
4301 + for (loc = filter->start; loc < filter->end; loc += DUMP_PAGE_SIZE) {
4302 + dump_config.dumper->curr_loc = loc;
4303 + page = dump_get_page(loc);
4304 + if (page && filter->selector(pass, (unsigned long) page,
4305 + DUMP_PAGE_SIZE)) {
4306 + if ((err = action((unsigned long)page, DUMP_PAGE_SIZE)))
4308 + printk("dump_page_iterator: err %d for loc "
4309 + "0x%llx, in pass %d\n", err, loc, pass);
4316 + return err ? err : count;
4320 + * Base function that saves the selected block of data in the dump
4321 + * Action taken when iterator decides that data needs to be saved
4323 +int dump_generic_save_data(unsigned long loc, unsigned long sz)
4326 + void *dump_buf = dump_config.dumper->dump_buf;
4327 + int left, bytes, ret;
4329 + if ((ret = dump_add_data(loc, sz))) {
4332 + buf = dump_config.dumper->curr_buf;
4334 + /* If we've filled up the buffer write it out */
4335 + if ((left = buf - dump_buf) >= DUMP_BUFFER_SIZE) {
4336 + bytes = dump_write_buffer(dump_buf, DUMP_BUFFER_SIZE);
4337 + if (bytes < DUMP_BUFFER_SIZE) {
4338 + printk("dump_write_buffer failed %d\n", bytes);
4339 + return bytes ? -ENOSPC : bytes;
4344 + /* -- A few chores to do from time to time -- */
4345 + dump_config.dumper->count++;
4347 + if (!(dump_config.dumper->count & 0x3f)) {
4348 + /* Update the header every one in a while */
4349 + memset((void *)dump_buf, 'b', DUMP_BUFFER_SIZE);
4350 + if ((ret = dump_update_header()) < 0) {
4351 + /* issue warning */
4356 + touch_nmi_watchdog();
4357 + } else if (!(dump_config.dumper->count & 0x7)) {
4358 + /* Show progress so the user knows we aren't hung */
4359 + dump_speedo(dump_config.dumper->count >> 3);
4361 + /* Todo: Touch/Refresh watchdog */
4363 + /* --- Done with periodic chores -- */
4366 + * extra bit of copying to simplify verification
4367 + * in the second kernel boot based scheme
4369 + memcpy(dump_buf - DUMP_PAGE_SIZE, dump_buf +
4370 + DUMP_BUFFER_SIZE - DUMP_PAGE_SIZE, DUMP_PAGE_SIZE);
4372 + /* now adjust the leftover bits back to the top of the page */
4373 + /* this case would not arise during stage 2 (passthru) */
4374 + memset(dump_buf, 'z', DUMP_BUFFER_SIZE);
4376 + memcpy(dump_buf, dump_buf + DUMP_BUFFER_SIZE, left);
4378 + buf -= DUMP_BUFFER_SIZE;
4379 + dump_config.dumper->curr_buf = buf;
4385 +int dump_generic_skip_data(unsigned long loc, unsigned long sz)
4387 + /* dummy by default */
4392 + * Common low level routine to write a buffer to current dump device
4393 + * Expects checks for space etc to have been taken care of by the caller
4394 + * Operates serially at the moment for simplicity.
4395 + * TBD/Todo: Consider batching for improved throughput
4397 +int dump_ll_write(void *buf, unsigned long len)
4399 + long transferred = 0, last_transfer = 0;
4402 + /* make sure device is ready */
4403 + while ((ret = dump_dev_ready(NULL)) == -EAGAIN);
4405 + printk("dump_dev_ready failed !err %d\n", ret);
4410 + if ((last_transfer = dump_dev_write(buf, len)) <= 0) {
4411 + ret = last_transfer;
4412 + printk("dump_dev_write failed !err %d\n",
4416 + /* wait till complete */
4417 + while ((ret = dump_dev_ready(buf)) == -EAGAIN)
4421 + printk("i/o failed !err %d\n", ret);
4425 + len -= last_transfer;
4426 + buf += last_transfer;
4427 + transferred += last_transfer;
4429 + return (ret < 0) ? ret : transferred;
4432 +/* default writeout routine for single dump device */
4433 +/* writes out the dump data ensuring enough space is left for the end marker */
4434 +int dump_generic_write_buffer(void *buf, unsigned long len)
4439 + /* check for space */
4440 + if ((err = dump_dev_seek(dump_config.dumper->curr_offset + len +
4441 + 2*DUMP_BUFFER_SIZE)) < 0) {
4442 + printk("dump_write_buffer: insuff space after offset 0x%llx\n",
4443 + dump_config.dumper->curr_offset);
4446 + /* alignment check would happen as a side effect of this */
4447 + if ((err = dump_dev_seek(dump_config.dumper->curr_offset)) < 0)
4450 + written = dump_ll_write(buf, len);
4454 + if (written < len)
4455 + written = written ? -ENOSPC : written;
4457 + dump_config.dumper->curr_offset += len;
4462 +int dump_generic_configure(unsigned long devid)
4464 + struct dump_dev *dev = dump_config.dumper->dev;
4465 + struct dump_data_filter *filter;
4469 + /* Allocate the dump buffer and initialize dumper state */
4470 + /* Assume that we get aligned addresses */
4471 + if (!(buf = dump_alloc_mem(DUMP_BUFFER_SIZE + 3 * DUMP_PAGE_SIZE)))
4474 + if ((unsigned long)buf & (PAGE_SIZE - 1)) {
4475 + /* sanity check for page aligned address */
4476 + dump_free_mem(buf);
4477 + return -ENOMEM; /* fixme: better error code */
4480 + /* Initialize the rest of the fields */
4481 + dump_config.dumper->dump_buf = buf + DUMP_PAGE_SIZE;
4484 + /* Open the dump device */
4488 + if ((ret = dev->ops->open(dev, devid))) {
4492 + /* Initialise the memory ranges in the dump filter */
4493 + for (filter = dump_config.dumper->filter ;filter->selector; filter++) {
4494 + if (!filter->start && !filter->end) {
4495 + filter->start = 0;
4496 + filter->end = num_physpages << PAGE_SHIFT;
4503 +int dump_generic_unconfigure(void)
4505 + struct dump_dev *dev = dump_config.dumper->dev;
4506 + void *buf = dump_config.dumper->dump_buf;
4509 + pr_debug("Generic unconfigure\n");
4510 + /* Close the dump device */
4511 + if (dev && (ret = dev->ops->release(dev)))
4514 + printk("Closed dump device\n");
4517 + dump_free_mem((buf - DUMP_PAGE_SIZE));
4519 + dump_config.dumper->curr_buf = dump_config.dumper->dump_buf = NULL;
4520 + pr_debug("Released dump buffer\n");
4526 +/* Set up the default dump scheme */
4528 +struct dump_scheme_ops dump_scheme_singlestage_ops = {
4529 + .configure = dump_generic_configure,
4530 + .unconfigure = dump_generic_unconfigure,
4531 + .sequencer = dump_generic_sequencer,
4532 + .iterator = dump_page_iterator,
4533 + .save_data = dump_generic_save_data,
4534 + .skip_data = dump_generic_skip_data,
4535 + .write_buffer = dump_generic_write_buffer,
4538 +struct dump_scheme dump_scheme_singlestage = {
4539 + .name = "single-stage",
4540 + .ops = &dump_scheme_singlestage_ops
4543 +/* The single stage dumper comprising all these */
4544 +struct dumper dumper_singlestage = {
4545 + .name = "single-stage",
4546 + .scheme = &dump_scheme_singlestage,
4547 + .fmt = &dump_fmt_lcrash,
4548 + .compress = &dump_none_compression,
4549 + .filter = dump_filter_table,
4553 Index: linux-2.6.0-test5/drivers/dump/dump_setup.c
4554 ===================================================================
4555 --- linux-2.6.0-test5.orig/drivers/dump/dump_setup.c 2003-09-26 14:26:34.000000000 +0800
4556 +++ linux-2.6.0-test5/drivers/dump/dump_setup.c 2003-09-26 14:26:34.000000000 +0800
4559 + * Standard kernel function entry points for Linux crash dumps.
4561 + * Created by: Matt Robinson (yakker@sourceforge.net)
4562 + * Contributions from SGI, IBM, HP, MCL, and others.
4564 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
4565 + * Copyright (C) 2000 - 2002 TurboLinux, Inc. All rights reserved.
4566 + * Copyright (C) 2001 - 2002 Matt D. Robinson. All rights reserved.
4567 + * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
4569 + * This code is released under version 2 of the GNU GPL.
4573 + * -----------------------------------------------------------------------
4577 + * This dump code goes back to SGI's first attempts at dumping system
4578 + * memory on SGI systems running IRIX. A few developers at SGI needed
4579 + * a way to take this system dump and analyze it, and created 'icrash',
4580 + * or IRIX Crash. The mechanism (the dumps and 'icrash') were used
4581 + * by support people to generate crash reports when a system failure
4582 + * occurred. This was vital for large system configurations that
4583 + * couldn't apply patch after patch after fix just to hope that the
4584 + * problems would go away. So the system memory, along with the crash
4585 + * dump analyzer, allowed support people to quickly figure out what the
4586 + * problem was on the system with the crash dump.
4588 + * In comes Linux. SGI started moving towards the open source community,
4589 + * and upon doing so, SGI wanted to take its support utilities into Linux
4590 + * with the hopes that they would end up the in kernel and user space to
4591 + * be used by SGI's customers buying SGI Linux systems. One of the first
4592 + * few products to be open sourced by SGI was LKCD, or Linux Kernel Crash
4593 + * Dumps. LKCD comprises of a patch to the kernel to enable system
4594 + * dumping, along with 'lcrash', or Linux Crash, to analyze the system
4595 + * memory dump. A few additional system scripts and kernel modifications
4596 + * are also included to make the dump mechanism and dump data easier to
4597 + * process and use.
4599 + * As soon as LKCD was released into the open source community, a number
4600 + * of larger companies started to take advantage of it. Today, there are
4601 + * many community members that contribute to LKCD, and it continues to
4602 + * flourish and grow as an open source project.
4608 + * This is the list of system tunables (via /proc) that are available
4609 + * for Linux systems. All the read, write, etc., functions are listed
4610 + * here. Currently, there are a few different tunables for dumps:
4612 + * dump_device (used to be dumpdev):
4613 + * The device for dumping the memory pages out to. This
4614 + * may be set to the primary swap partition for disruptive dumps,
4615 + * and must be an unused partition for non-disruptive dumps.
4616 + * Todo: In the case of network dumps, this may be interpreted
4617 + * as the IP address of the netdump server to connect to.
4619 + * dump_compress (used to be dump_compress_pages):
4620 + * This is the flag which indicates which compression mechanism
4621 + * to use. This is a BITMASK, not an index (0,1,2,4,8,16,etc.).
4622 + * This is the current set of values:
4624 + * 0: DUMP_COMPRESS_NONE -- Don't compress any pages.
4625 + * 1: DUMP_COMPRESS_RLE -- This uses RLE compression.
4626 + * 2: DUMP_COMPRESS_GZIP -- This uses GZIP compression.
4629 + * The amount of effort the dump module should make to save
4630 + * information for post crash analysis. This value is now
4631 + * a BITMASK value, not an index:
4633 + * 0: Do nothing, no dumping. (DUMP_LEVEL_NONE)
4635 + * 1: Print out the dump information to the dump header, and
4636 + * write it out to the dump_device. (DUMP_LEVEL_HEADER)
4638 + * 2: Write out the dump header and all kernel memory pages.
4639 + * (DUMP_LEVEL_KERN)
4641 + * 4: Write out the dump header and all kernel and user
4642 + * memory pages. (DUMP_LEVEL_USED)
4644 + * 8: Write out the dump header and all conventional/cached
4645 + * memory (RAM) pages in the system (kernel, user, free).
4646 + * (DUMP_LEVEL_ALL_RAM)
4648 + * 16: Write out everything, including non-conventional memory
4649 + * like firmware, proms, I/O registers, uncached memory.
4650 + * (DUMP_LEVEL_ALL)
4652 + * The dump_level will default to 1.
4655 + * These are the flags to use when talking about dumps. There
4656 + * are lots of possibilities. This is a BITMASK value, not an index.
4658 + * -----------------------------------------------------------------------
4661 +#include <linux/kernel.h>
4662 +#include <linux/delay.h>
4663 +#include <linux/reboot.h>
4664 +#include <linux/fs.h>
4665 +#include <linux/dump.h>
4666 +#include "dump_methods.h"
4667 +#include <linux/proc_fs.h>
4668 +#include <linux/module.h>
4669 +#include <linux/utsname.h>
4670 +#include <linux/highmem.h>
4671 +#include <linux/major.h>
4672 +#include <linux/sysrq.h>
4673 +#include <linux/sysctl.h>
4674 +#include <linux/nmi.h>
4676 +#include <asm/hardirq.h>
4677 +#include <asm/uaccess.h>
4680 + * -----------------------------------------------------------------------
4681 + * V A R I A B L E S
4682 + * -----------------------------------------------------------------------
4685 +/* Dump tunables */
4686 +struct dump_config dump_config = {
4695 +/* Global variables used in dump.h */
4696 +/* degree of system freeze when dumping */
4697 +enum dump_silence_levels dump_silence_level = DUMP_HARD_SPIN_CPUS;
4699 +/* Other global fields */
4700 +extern struct __dump_header dump_header;
4701 +struct dump_dev *dump_dev = NULL; /* Active dump device */
4702 +static int dump_compress = 0;
4704 +static u16 dump_compress_none(const u8 *old, u16 oldsize, u8 *new, u16 newsize);
4705 +struct __dump_compress dump_none_compression = {
4706 + .compress_type = DUMP_COMPRESS_NONE,
4707 + .compress_func = dump_compress_none,
4708 + .compress_name = "none",
4711 +/* our device operations and functions */
4712 +static int dump_ioctl(struct inode *i, struct file *f,
4713 + unsigned int cmd, unsigned long arg);
4715 +static struct file_operations dump_fops = {
4716 + .ioctl = dump_ioctl,
4719 +/* static variables */
4720 +static int dump_okay = 0; /* can we dump out to disk? */
4721 +static spinlock_t dump_lock = SPIN_LOCK_UNLOCKED;
4723 +/* used for dump compressors */
4724 +static struct list_head dump_compress_list = LIST_HEAD_INIT(dump_compress_list);
4726 +/* list of registered dump targets */
4727 +static struct list_head dump_target_list = LIST_HEAD_INIT(dump_target_list);
4729 +/* lkcd info structure -- this is used by lcrash for basic system data */
4730 +struct __lkcdinfo lkcdinfo = {
4731 + .ptrsz = (sizeof(void *) * 8),
4732 +#if defined(__LITTLE_ENDIAN)
4733 + .byte_order = __LITTLE_ENDIAN,
4735 + .byte_order = __BIG_ENDIAN,
4737 + .page_shift = PAGE_SHIFT,
4738 + .page_size = PAGE_SIZE,
4739 + .page_mask = PAGE_MASK,
4740 + .page_offset = PAGE_OFFSET,
4744 + * -----------------------------------------------------------------------
4745 + * / P R O C T U N A B L E F U N C T I O N S
4746 + * -----------------------------------------------------------------------
4749 +static int proc_dump_device(ctl_table *ctl, int write, struct file *f,
4750 + void *buffer, size_t *lenp);
4752 +static int proc_doulonghex(ctl_table *ctl, int write, struct file *f,
4753 + void *buffer, size_t *lenp);
4755 + * sysctl-tuning infrastructure.
4757 +static ctl_table dump_table[] = {
4758 + { .ctl_name = CTL_DUMP_LEVEL,
4759 + .procname = DUMP_LEVEL_NAME,
4760 + .data = &dump_config.level,
4761 + .maxlen = sizeof(int),
4763 + .proc_handler = proc_doulonghex, },
4765 + { .ctl_name = CTL_DUMP_FLAGS,
4766 + .procname = DUMP_FLAGS_NAME,
4767 + .data = &dump_config.flags,
4768 + .maxlen = sizeof(int),
4770 + .proc_handler = proc_doulonghex, },
4772 + { .ctl_name = CTL_DUMP_COMPRESS,
4773 + .procname = DUMP_COMPRESS_NAME,
4774 + .data = &dump_compress, /* FIXME */
4775 + .maxlen = sizeof(int),
4777 + .proc_handler = proc_dointvec, },
4779 + { .ctl_name = CTL_DUMP_DEVICE,
4780 + .procname = DUMP_DEVICE_NAME,
4782 + .data = &dump_config.dump_device, /* FIXME */
4783 + .maxlen = sizeof(int),
4784 + .proc_handler = proc_dump_device },
4786 +#ifdef CONFIG_CRASH_DUMP_MEMDEV
4787 + { .ctl_name = CTL_DUMP_ADDR,
4788 + .procname = DUMP_ADDR_NAME,
4790 + .data = &dump_config.dump_addr,
4791 + .maxlen = sizeof(unsigned long),
4792 + .proc_handler = proc_doulonghex },
4798 +static ctl_table dump_root[] = {
4799 + { .ctl_name = KERN_DUMP,
4800 + .procname = "dump",
4802 + .child = dump_table },
4806 +static ctl_table kernel_root[] = {
4807 + { .ctl_name = CTL_KERN,
4808 + .procname = "kernel",
4810 + .child = dump_root, },
4814 +static struct ctl_table_header *sysctl_header;
4817 + * -----------------------------------------------------------------------
4818 + * C O M P R E S S I O N F U N C T I O N S
4819 + * -----------------------------------------------------------------------
4823 + * Name: dump_compress_none()
4824 + * Func: Don't do any compression, period.
4827 +dump_compress_none(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
4829 + /* just return the old size */
4835 + * Name: dump_execute()
4836 + * Func: Execute the dumping process. This makes sure all the appropriate
4837 + * fields are updated correctly, and calls dump_execute_memdump(),
4838 + * which does the real work.
4841 +dump_execute(const char *panic_str, const struct pt_regs *regs)
4844 + unsigned long flags;
4846 + /* make sure we can dump */
4848 + pr_info("LKCD not yet configured, can't take dump now\n");
4852 + /* Exclude multiple dumps at the same time,
4853 + * and disable interrupts, some drivers may re-enable
4854 + * interrupts in with silence()
4856 + * Try and acquire spin lock. If successful, leave preempt
4857 + * and interrupts disabled. See spin_lock_irqsave in spinlock.h
4859 + local_irq_save(flags);
4860 + if (!spin_trylock(&dump_lock)) {
4861 + local_irq_restore(flags);
4862 + pr_info("LKCD dump already in progress\n");
4866 + /* Bring system into the strictest level of quiescing for min drift
4867 + * dump drivers can soften this as required in dev->ops->silence()
4869 + dump_oncpu = smp_processor_id() + 1;
4870 + dump_silence_level = DUMP_HARD_SPIN_CPUS;
4872 + state = dump_generic_execute(panic_str, regs);
4875 + spin_unlock_irqrestore(&dump_lock, flags);
4878 + printk("Dump Incomplete or failed!\n");
4880 + printk("Dump Complete; %d dump pages saved.\n",
4881 + dump_header.dh_num_dump_pages);
4886 + * Name: dump_register_compression()
4887 + * Func: Register a dump compression mechanism.
4890 +dump_register_compression(struct __dump_compress *item)
4893 + list_add(&(item->list), &dump_compress_list);
4897 + * Name: dump_unregister_compression()
4898 + * Func: Remove a dump compression mechanism, and re-assign the dump
4899 + * compression pointer if necessary.
4902 +dump_unregister_compression(int compression_type)
4904 + struct list_head *tmp;
4905 + struct __dump_compress *dc;
4907 + /* let's make sure our list is valid */
4908 + if (compression_type != DUMP_COMPRESS_NONE) {
4909 + list_for_each(tmp, &dump_compress_list) {
4910 + dc = list_entry(tmp, struct __dump_compress, list);
4911 + if (dc->compress_type == compression_type) {
4912 + list_del(&(dc->list));
4920 + * Name: dump_compress_init()
4921 + * Func: Initialize (or re-initialize) compression scheme.
4924 +dump_compress_init(int compression_type)
4926 + struct list_head *tmp;
4927 + struct __dump_compress *dc;
4929 + /* try to remove the compression item */
4930 + list_for_each(tmp, &dump_compress_list) {
4931 + dc = list_entry(tmp, struct __dump_compress, list);
4932 + if (dc->compress_type == compression_type) {
4933 + dump_config.dumper->compress = dc;
4934 + dump_compress = compression_type;
4935 + pr_debug("Dump Compress %s\n", dc->compress_name);
4941 + * nothing on the list -- return ENODATA to indicate an error
4944 + * EAGAIN: reports "Resource temporarily unavailable" which
4945 + * isn't very enlightening.
4947 + printk("compression_type:%d not found\n", compression_type);
4953 +dumper_setup(unsigned long flags, unsigned long devid)
4957 + /* unconfigure old dumper if it exists */
4959 + if (dump_config.dumper) {
4960 + pr_debug("Unconfiguring current dumper\n");
4961 + dump_unconfigure();
4963 + /* set up new dumper */
4964 + if (dump_config.flags & DUMP_FLAGS_SOFTBOOT) {
4965 + printk("Configuring softboot based dump \n");
4966 +#ifdef CONFIG_CRASH_DUMP_MEMDEV
4967 + dump_config.dumper = &dumper_stage1;
4969 + printk("Requires CONFIG_CRASHDUMP_MEMDEV. Can't proceed.\n");
4973 + dump_config.dumper = &dumper_singlestage;
4975 + dump_config.dumper->dev = dump_dev;
4977 + ret = dump_configure(devid);
4980 + pr_debug("%s dumper set up for dev 0x%lx\n",
4981 + dump_config.dumper->name, devid);
4982 + dump_config.dump_device = devid;
4984 + printk("%s dumper set up failed for dev 0x%lx\n",
4985 + dump_config.dumper->name, devid);
4986 + dump_config.dumper = NULL;
4992 +dump_target_init(int target)
4995 + struct list_head *tmp;
4996 + struct dump_dev *dev;
4999 + case DUMP_FLAGS_DISKDUMP:
5000 + strcpy(type, "blockdev"); break;
5001 + case DUMP_FLAGS_NETDUMP:
5002 + strcpy(type, "networkdev"); break;
5008 + * This is a bit stupid, generating strings from flag
5009 + * and doing strcmp. This is done because 'struct dump_dev'
5010 + * has string 'type_name' and not interger 'type'.
5012 + list_for_each(tmp, &dump_target_list) {
5013 + dev = list_entry(tmp, struct dump_dev, list);
5014 + if (strcmp(type, dev->type_name) == 0) {
5023 + * Name: dump_ioctl()
5024 + * Func: Allow all dump tunables through a standard ioctl() mechanism.
5025 + * This is far better than before, where we'd go through /proc,
5026 + * because now this will work for multiple OS and architectures.
5029 +dump_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
5031 + /* check capabilities */
5032 + if (!capable(CAP_SYS_ADMIN))
5035 + if (!dump_config.dumper && cmd == DIOSDUMPCOMPRESS)
5036 + /* dump device must be configured first */
5040 + * This is the main mechanism for controlling get/set data
5041 + * for various dump device parameters. The real trick here
5042 + * is setting the dump device (DIOSDUMPDEV). That's what
5043 + * triggers everything else.
5046 + case DIOSDUMPDEV: /* set dump_device */
5047 + pr_debug("Configuring dump device\n");
5048 + if (!(f->f_flags & O_RDWR))
5052 + return dumper_setup(dump_config.flags, arg);
5055 + case DIOGDUMPDEV: /* get dump_device */
5056 + return put_user((long)dump_config.dump_device, (long *)arg);
5058 + case DIOSDUMPLEVEL: /* set dump_level */
5059 + if (!(f->f_flags & O_RDWR))
5062 + /* make sure we have a positive value */
5066 + /* Fixme: clean this up */
5067 + dump_config.level = 0;
5068 + switch ((int)arg) {
5069 + case DUMP_LEVEL_ALL:
5070 + case DUMP_LEVEL_ALL_RAM:
5071 + dump_config.level |= DUMP_MASK_UNUSED;
5072 + case DUMP_LEVEL_USED:
5073 + dump_config.level |= DUMP_MASK_USED;
5074 + case DUMP_LEVEL_KERN:
5075 + dump_config.level |= DUMP_MASK_KERN;
5076 + case DUMP_LEVEL_HEADER:
5077 + dump_config.level |= DUMP_MASK_HEADER;
5078 + case DUMP_LEVEL_NONE:
5083 + pr_debug("Dump Level 0x%lx\n", dump_config.level);
5086 + case DIOGDUMPLEVEL: /* get dump_level */
5087 + /* fixme: handle conversion */
5088 + return put_user((long)dump_config.level, (long *)arg);
5091 + case DIOSDUMPFLAGS: /* set dump_flags */
5093 + if (!(f->f_flags & O_RDWR))
5096 + /* make sure we have a positive value */
5100 + if (dump_target_init(arg & DUMP_FLAGS_TARGETMASK) < 0)
5101 + return -EINVAL; /* return proper error */
5103 + dump_config.flags = arg;
5105 + pr_debug("Dump Flags 0x%lx\n", dump_config.flags);
5108 + case DIOGDUMPFLAGS: /* get dump_flags */
5109 + return put_user((long)dump_config.flags, (long *)arg);
5111 + case DIOSDUMPCOMPRESS: /* set the dump_compress status */
5112 + if (!(f->f_flags & O_RDWR))
5115 + return dump_compress_init((int)arg);
5117 + case DIOGDUMPCOMPRESS: /* get the dump_compress status */
5118 + return put_user((long)(dump_config.dumper ?
5119 + dump_config.dumper->compress->compress_type : 0),
5124 + * these are network dump specific ioctls, let the
5125 + * module handle them.
5127 + return dump_dev_ioctl(cmd, arg);
5133 + * Handle special cases for dump_device
5134 + * changing dump device requires doing an opening the device
5137 +proc_dump_device(ctl_table *ctl, int write, struct file *f,
5138 + void *buffer, size_t *lenp)
5140 + int *valp = ctl->data;
5144 + /* same permission checks as ioctl */
5145 + if (capable(CAP_SYS_ADMIN)) {
5146 + ret = proc_doulonghex(ctl, write, f, buffer, lenp);
5147 + if (ret == 0 && write && *valp != oval) {
5148 + /* need to restore old value to close properly */
5149 + dump_config.dump_device = (dev_t) oval;
5151 + ret = dumper_setup(dump_config.flags, (dev_t) *valp);
5158 +/* All for the want of a proc_do_xxx routine which prints values in hex */
5160 +proc_doulonghex(ctl_table *ctl, int write, struct file *f,
5161 + void *buffer, size_t *lenp)
5163 +#define TMPBUFLEN 20
5166 + char buf[TMPBUFLEN];
5168 + if (!ctl->data || !ctl->maxlen || !*lenp || (f->f_pos)) {
5173 + i = (unsigned long *) ctl->data;
5176 + sprintf(buf, "0x%lx\n", (*i));
5177 + len = strlen(buf);
5180 + if(copy_to_user(buffer, buf, len))
5185 + f->f_pos += *lenp;
5190 + * -----------------------------------------------------------------------
5191 + * I N I T F U N C T I O N S
5192 + * -----------------------------------------------------------------------
5196 + * These register and unregister routines are exported for modules
5197 + * to register their dump drivers (like block, net etc)
5200 +dump_register_device(struct dump_dev *ddev)
5202 + struct list_head *tmp;
5203 + struct dump_dev *dev;
5205 + list_for_each(tmp, &dump_target_list) {
5206 + dev = list_entry(tmp, struct dump_dev, list);
5207 + if (strcmp(ddev->type_name, dev->type_name) == 0) {
5208 + printk("Target type %s already registered\n",
5210 + return -1; /* return proper error */
5213 + list_add(&(ddev->list), &dump_target_list);
5219 +dump_unregister_device(struct dump_dev *ddev)
5221 + list_del(&(ddev->list));
5222 + if (ddev != dump_dev)
5227 + if (dump_config.dumper)
5228 + dump_unconfigure();
5230 + dump_config.flags &= ~DUMP_FLAGS_TARGETMASK;
5233 + dump_config.dumper = NULL;
5236 +static int panic_event(struct notifier_block *this, unsigned long event,
5239 + struct pt_regs regs;
5241 + get_current_regs(®s);
5242 + dump_execute((const char *)ptr, ®s);
5246 +extern struct notifier_block *panic_notifier_list;
5247 +static int panic_event(struct notifier_block *, unsigned long, void *);
5248 +static struct notifier_block panic_block = {
5249 + .notifier_call = panic_event,
5252 +#ifdef CONFIG_MAGIC_SYSRQ
5253 +/* Sysrq handler */
5254 +static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
5255 + struct tty_struct *tty) {
5256 + dump_execute("sysrq", pt_regs);
5259 +static struct sysrq_key_op sysrq_crashdump_op = {
5260 + .handler = sysrq_handle_crashdump,
5261 + .help_msg = "Dump",
5262 + .action_msg = "Starting crash dump",
5267 +dump_sysrq_register(void)
5269 +#ifdef CONFIG_MAGIC_SYSRQ
5270 + __sysrq_lock_table();
5271 + __sysrq_put_key_op(DUMP_SYSRQ_KEY, &sysrq_crashdump_op);
5272 + __sysrq_unlock_table();
5277 +dump_sysrq_unregister(void)
5279 +#ifdef CONFIG_MAGIC_SYSRQ
5280 + __sysrq_lock_table();
5281 + if (__sysrq_get_key_op(DUMP_SYSRQ_KEY) == &sysrq_crashdump_op)
5282 + __sysrq_put_key_op(DUMP_SYSRQ_KEY, NULL);
5283 + __sysrq_unlock_table();
5288 + * Name: dump_init()
5289 + * Func: Initialize the dump process. This will set up any architecture
5290 + * dependent code. The big key is we need the memory offsets before
5291 + * the page table is initialized, because the base memory offset
5292 + * is changed after paging_init() is called.
5297 + struct sysinfo info;
5299 + /* try to create our dump device */
5300 + if (register_chrdev(CRASH_DUMP_MAJOR, "dump", &dump_fops)) {
5301 + printk("cannot register dump character device!\n");
5305 + __dump_init((u64)PAGE_OFFSET);
5307 + /* set the dump_compression_list structure up */
5308 + dump_register_compression(&dump_none_compression);
5310 + /* grab the total memory size now (not if/when we crash) */
5311 + si_meminfo(&info);
5313 + /* set the memory size */
5314 + dump_header.dh_memory_size = (u64)info.totalram;
5316 + sysctl_header = register_sysctl_table(kernel_root, 0);
5317 + dump_sysrq_register();
5319 + notifier_chain_register(&panic_notifier_list, &panic_block);
5320 + dump_function_ptr = dump_execute;
5322 + pr_info("Crash dump driver initialized.\n");
5331 + if (dump_config.dumper)
5332 + dump_unconfigure();
5334 + /* arch-specific cleanup routine */
5337 + /* ignore errors while unregistering -- since can't do anything */
5338 + unregister_sysctl_table(sysctl_header);
5339 + unregister_chrdev(CRASH_DUMP_MAJOR, "dump");
5340 + dump_sysrq_unregister();
5341 + notifier_chain_unregister(&panic_notifier_list, &panic_block);
5342 + dump_function_ptr = NULL;
5345 +EXPORT_SYMBOL(dump_register_compression);
5346 +EXPORT_SYMBOL(dump_unregister_compression);
5347 +EXPORT_SYMBOL(dump_register_device);
5348 +EXPORT_SYMBOL(dump_unregister_device);
5349 +EXPORT_SYMBOL(dump_config);
5350 +EXPORT_SYMBOL(dump_silence_level);
5352 +EXPORT_SYMBOL(__dump_irq_enable);
5353 +EXPORT_SYMBOL(__dump_irq_restore);
5355 +MODULE_AUTHOR("Matt D. Robinson <yakker@sourceforge.net>");
5356 +MODULE_DESCRIPTION("Linux Kernel Crash Dump (LKCD) driver");
5357 +MODULE_LICENSE("GPL");
5359 +module_init(dump_init);
5360 +module_exit(dump_cleanup);
5361 Index: linux-2.6.0-test5/include/linux/dumpdev.h
5362 ===================================================================
5363 --- linux-2.6.0-test5.orig/include/linux/dumpdev.h 2003-09-26 14:26:34.000000000 +0800
5364 +++ linux-2.6.0-test5/include/linux/dumpdev.h 2003-09-26 14:27:08.000000000 +0800
5367 + * Generic dump device interfaces for flexible system dump
5368 + * (Enables variation of dump target types e.g disk, network, memory)
5370 + * These interfaces have evolved based on discussions on lkcd-devel.
5371 + * Eventually the intent is to support primary and secondary or
5372 + * alternate targets registered at the same time, with scope for
5373 + * situation based failover or multiple dump devices used for parallel
5376 + * Started: Oct 2002 - Suparna Bhattacharya (suparna@in.ibm.com)
5378 + * Copyright (C) 2001 - 2002 Matt D. Robinson. All rights reserved.
5379 + * Copyright (C) 2002 International Business Machines Corp.
5381 + * This code is released under version 2 of the GNU GPL.
5384 +#ifndef _LINUX_DUMPDEV_H
5385 +#define _LINUX_DUMPDEV_H
5387 +#include <linux/kernel.h>
5388 +#include <linux/wait.h>
5389 +#include <linux/bio.h>
5391 +/* Determined by the dump target (device) type */
5395 +struct dump_dev_ops {
5396 + int (*open)(struct dump_dev *, unsigned long); /* configure */
5397 + int (*release)(struct dump_dev *); /* unconfigure */
5398 + int (*silence)(struct dump_dev *); /* when dump starts */
5399 + int (*resume)(struct dump_dev *); /* when dump is over */
5400 + int (*seek)(struct dump_dev *, loff_t);
5401 + /* trigger a write (async in nature typically) */
5402 + int (*write)(struct dump_dev *, void *, unsigned long);
5403 + /* not usually used during dump, but option available */
5404 + int (*read)(struct dump_dev *, void *, unsigned long);
5405 + /* use to poll for completion */
5406 + int (*ready)(struct dump_dev *, void *);
5407 + int (*ioctl)(struct dump_dev *, unsigned int, unsigned long);
5411 + char type_name[32]; /* block, net-poll etc */
5412 + unsigned long device_id; /* interpreted differently for various types */
5413 + struct dump_dev_ops *ops;
5414 + struct list_head list;
5415 + loff_t curr_offset;
5419 + * dump_dev type variations:
5423 +struct dump_blockdev {
5424 + struct dump_dev ddev;
5426 + struct block_device *bdev;
5428 + loff_t start_offset;
5433 +static inline struct dump_blockdev *DUMP_BDEV(struct dump_dev *dev)
5435 + return container_of(dev, struct dump_blockdev, ddev);
5439 +/* mem - for internal use by soft-boot based dumper */
5440 +struct dump_memdev {
5441 + struct dump_dev ddev;
5442 + unsigned long indirect_map_root;
5443 + unsigned long nr_free;
5444 + struct page *curr_page;
5445 + unsigned long *curr_map;
5446 + unsigned long curr_map_offset;
5447 + unsigned long last_offset;
5448 + unsigned long last_used_offset;
5449 + unsigned long last_bs_offset;
5452 +static inline struct dump_memdev *DUMP_MDEV(struct dump_dev *dev)
5454 + return container_of(dev, struct dump_memdev, ddev);
5457 +/* Todo/future - meant for raw dedicated interfaces e.g. mini-ide driver */
5459 + struct dump_dev ddev;
5461 + int (*reset)(struct dump_rdev *, unsigned int,
5463 + /* ... to do ... */
5466 +/* just to get the size right when saving config across a soft-reboot */
5467 +struct dump_anydev {
5469 + struct dump_blockdev bddev;
5470 + /* .. add other types here .. */
5476 +/* Dump device / target operation wrappers */
5477 +/* These assume that dump_dev is initiatized to dump_config.dumper->dev */
5479 +extern struct dump_dev *dump_dev;
5481 +static inline int dump_dev_open(unsigned long arg)
5483 + return dump_dev->ops->open(dump_dev, arg);
5486 +static inline int dump_dev_release(void)
5488 + return dump_dev->ops->release(dump_dev);
5491 +static inline int dump_dev_silence(void)
5493 + return dump_dev->ops->silence(dump_dev);
5496 +static inline int dump_dev_resume(void)
5498 + return dump_dev->ops->resume(dump_dev);
5501 +static inline int dump_dev_seek(loff_t offset)
5503 + return dump_dev->ops->seek(dump_dev, offset);
5506 +static inline int dump_dev_write(void *buf, unsigned long len)
5508 + return dump_dev->ops->write(dump_dev, buf, len);
5511 +static inline int dump_dev_ready(void *buf)
5513 + return dump_dev->ops->ready(dump_dev, buf);
5516 +static inline int dump_dev_ioctl(unsigned int cmd, unsigned long arg)
5518 + if (!dump_dev->ops->ioctl)
5520 + return dump_dev->ops->ioctl(dump_dev, cmd, arg);
5523 +extern int dump_register_device(struct dump_dev *);
5524 +extern void dump_unregister_device(struct dump_dev *);
5526 +#endif /* _LINUX_DUMPDEV_H */
5527 Index: linux-2.6.0-test5/include/linux/dump.h
5528 ===================================================================
5529 --- linux-2.6.0-test5.orig/include/linux/dump.h 2003-09-26 14:26:34.000000000 +0800
5530 +++ linux-2.6.0-test5/include/linux/dump.h 2003-09-26 14:26:34.000000000 +0800
5533 + * Kernel header file for Linux crash dumps.
5535 + * Created by: Matt Robinson (yakker@sgi.com)
5536 + * Copyright 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
5538 + * vmdump.h to dump.h by: Matt D. Robinson (yakker@sourceforge.net)
5539 + * Copyright 2001 - 2002 Matt D. Robinson. All rights reserved.
5540 + * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
5542 + * Most of this is the same old stuff from vmdump.h, except now we're
5543 + * actually a stand-alone driver plugged into the block layer interface,
5544 + * with the exception that we now allow for compression modes externally
5545 + * loaded (e.g., someone can come up with their own).
5547 + * This code is released under version 2 of the GNU GPL.
5550 +/* This header file includes all structure definitions for crash dumps. */
5554 +#if defined(CONFIG_CRASH_DUMP) || defined (CONFIG_CRASH_DUMP_MODULE)
5556 +#include <linux/list.h>
5557 +#include <linux/notifier.h>
5558 +#include <linux/dumpdev.h>
5561 + * Predefine default DUMP_PAGE constants, asm header may override.
5563 + * On ia64 discontinuous memory systems it's possible for the memory
5564 + * banks to stop at 2**12 page alignments, the smallest possible page
5565 + * size. But the system page size, PAGE_SIZE, is in fact larger.
5567 +#define DUMP_PAGE_SHIFT PAGE_SHIFT
5568 +#define DUMP_PAGE_MASK PAGE_MASK
5569 +#define DUMP_PAGE_ALIGN(addr) PAGE_ALIGN(addr)
5570 +#define DUMP_HEADER_OFFSET PAGE_SIZE
5572 +/* keep DUMP_PAGE_SIZE constant to 4K = 1<<12
5573 + * it may be different from PAGE_SIZE then.
5575 +#define DUMP_PAGE_SIZE 4096
5578 + * Predefined default memcpy() to use when copying memory to the dump buffer.
5580 + * On ia64 there is a heads up function that can be called to let the prom
5581 + * machine check monitor know that the current activity is risky and it should
5582 + * ignore the fault (nofault). In this case the ia64 header will redefine this
5583 + * macro to __dump_memcpy() and use it's arch specific version.
5585 +#define DUMP_memcpy memcpy
5587 +/* necessary header files */
5588 +#include <asm/dump.h> /* for architecture-specific header */
5591 + * Size of the buffer that's used to hold:
5593 + * 1. the dump header (padded to fill the complete buffer)
5594 + * 2. the possibly compressed page headers and data
5596 +#define DUMP_BUFFER_SIZE (64 * 1024) /* size of dump buffer */
5597 +#define DUMP_HEADER_SIZE DUMP_BUFFER_SIZE
5599 +/* standard header definitions */
5600 +#define DUMP_MAGIC_NUMBER 0xa8190173618f23edULL /* dump magic number */
5601 +#define DUMP_MAGIC_LIVE 0xa8190173618f23cdULL /* live magic number */
5602 +#define DUMP_VERSION_NUMBER 0x8 /* dump version number */
5603 +#define DUMP_PANIC_LEN 0x100 /* dump panic string length */
5605 +/* dump levels - type specific stuff added later -- add as necessary */
5606 +#define DUMP_LEVEL_NONE 0x0 /* no dumping at all -- just bail */
5607 +#define DUMP_LEVEL_HEADER 0x1 /* kernel dump header only */
5608 +#define DUMP_LEVEL_KERN 0x2 /* dump header and kernel pages */
5609 +#define DUMP_LEVEL_USED 0x4 /* dump header, kernel/user pages */
5610 +#define DUMP_LEVEL_ALL_RAM 0x8 /* dump header, all RAM pages */
5611 +#define DUMP_LEVEL_ALL 0x10 /* dump all memory RAM and firmware */
5614 +/* dump compression options -- add as necessary */
5615 +#define DUMP_COMPRESS_NONE 0x0 /* don't compress this dump */
5616 +#define DUMP_COMPRESS_RLE 0x1 /* use RLE compression */
5617 +#define DUMP_COMPRESS_GZIP 0x2 /* use GZIP compression */
5619 +/* dump flags - any dump-type specific flags -- add as necessary */
5620 +#define DUMP_FLAGS_NONE 0x0 /* no flags are set for this dump */
5621 +#define DUMP_FLAGS_SOFTBOOT 0x2 /* 2 stage soft-boot based dump */
5623 +#define DUMP_FLAGS_TARGETMASK 0xf0000000 /* handle special case targets */
5624 +#define DUMP_FLAGS_DISKDUMP 0x80000000 /* dump to local disk */
5625 +#define DUMP_FLAGS_NETDUMP 0x40000000 /* dump over the network */
5627 +/* dump header flags -- add as necessary */
5628 +#define DUMP_DH_FLAGS_NONE 0x0 /* no flags set (error condition!) */
5629 +#define DUMP_DH_RAW 0x1 /* raw page (no compression) */
5630 +#define DUMP_DH_COMPRESSED 0x2 /* page is compressed */
5631 +#define DUMP_DH_END 0x4 /* end marker on a full dump */
5632 +#define DUMP_DH_TRUNCATED 0x8 /* dump is incomplete */
5633 +#define DUMP_DH_TEST_PATTERN 0x10 /* dump page is a test pattern */
5634 +#define DUMP_DH_NOT_USED 0x20 /* 1st bit not used in flags */
5636 +/* names for various dump parameters in /proc/kernel */
5637 +#define DUMP_ROOT_NAME "sys/dump"
5638 +#define DUMP_DEVICE_NAME "device"
5639 +#define DUMP_COMPRESS_NAME "compress"
5640 +#define DUMP_LEVEL_NAME "level"
5641 +#define DUMP_FLAGS_NAME "flags"
5642 +#define DUMP_ADDR_NAME "addr"
5644 +#define DUMP_SYSRQ_KEY 'd' /* key to use for MAGIC_SYSRQ key */
5646 +/* CTL_DUMP names: */
5649 + CTL_DUMP_DEVICE=1,
5650 + CTL_DUMP_COMPRESS=3,
5658 +/* page size for gzip compression -- buffered slightly beyond hardware PAGE_SIZE used by DUMP */
5659 +#define DUMP_DPC_PAGE_SIZE (DUMP_PAGE_SIZE + 512)
5661 +/* dump ioctl() control options */
5662 +#define DIOSDUMPDEV 1 /* set the dump device */
5663 +#define DIOGDUMPDEV 2 /* get the dump device */
5664 +#define DIOSDUMPLEVEL 3 /* set the dump level */
5665 +#define DIOGDUMPLEVEL 4 /* get the dump level */
5666 +#define DIOSDUMPFLAGS 5 /* set the dump flag parameters */
5667 +#define DIOGDUMPFLAGS 6 /* get the dump flag parameters */
5668 +#define DIOSDUMPCOMPRESS 7 /* set the dump compress level */
5669 +#define DIOGDUMPCOMPRESS 8 /* get the dump compress level */
5671 +/* these ioctls are used only by netdump module */
5672 +#define DIOSTARGETIP 9 /* set the target m/c's ip */
5673 +#define DIOGTARGETIP 10 /* get the target m/c's ip */
5674 +#define DIOSTARGETPORT 11 /* set the target m/c's port */
5675 +#define DIOGTARGETPORT 12 /* get the target m/c's port */
5676 +#define DIOSSOURCEPORT 13 /* set the source m/c's port */
5677 +#define DIOGSOURCEPORT 14 /* get the source m/c's port */
5678 +#define DIOSETHADDR 15 /* set ethernet address */
5679 +#define DIOGETHADDR 16 /* get ethernet address */
5682 + * Structure: __dump_header
5683 + * Function: This is the header dumped at the top of every valid crash
5686 +struct __dump_header {
5687 + /* the dump magic number -- unique to verify dump is valid */
5688 + u64 dh_magic_number;
5690 + /* the version number of this dump */
5693 + /* the size of this header (in case we can't read it) */
5694 + u32 dh_header_size;
5696 + /* the level of this dump (just a header?) */
5697 + u32 dh_dump_level;
5700 + * We assume dump_page_size to be 4K in every case.
5701 + * Store here the configurable system page size (4K, 8K, 16K, etc.)
5705 + /* the size of all physical memory */
5706 + u64 dh_memory_size;
5708 + /* the start of physical memory */
5709 + u64 dh_memory_start;
5711 + /* the end of physical memory */
5712 + u64 dh_memory_end;
5714 + /* the number of hardware/physical pages in this dump specifically */
5715 + u32 dh_num_dump_pages;
5717 + /* the panic string, if available */
5718 + char dh_panic_string[DUMP_PANIC_LEN];
5720 + /* timeval depends on architecture, two long values */
5724 + } dh_time; /* the time of the system crash */
5726 + /* the NEW utsname (uname) information -- in character form */
5727 + /* we do this so we don't have to include utsname.h */
5728 + /* plus it helps us be more architecture independent */
5729 + /* now maybe one day soon they'll make the [65] a #define! */
5730 + char dh_utsname_sysname[65];
5731 + char dh_utsname_nodename[65];
5732 + char dh_utsname_release[65];
5733 + char dh_utsname_version[65];
5734 + char dh_utsname_machine[65];
5735 + char dh_utsname_domainname[65];
5737 + /* the address of current task (OLD = void *, NEW = u64) */
5738 + u64 dh_current_task;
5740 + /* what type of compression we're using in this dump (if any) */
5741 + u32 dh_dump_compress;
5743 + /* any additional flags */
5744 + u32 dh_dump_flags;
5746 + /* any additional flags */
5747 + u32 dh_dump_device;
5748 +} __attribute__((packed));
5751 + * Structure: __dump_page
5752 + * Function: To act as the header associated to each physical page of
5753 + * memory saved in the system crash dump. This allows for
5754 + * easy reassembly of each crash dump page. The address bits
5755 + * are split to make things easier for 64-bit/32-bit system
5758 + * dp_byte_offset and dp_page_index are landmarks that are helpful when
5759 + * looking at a hex dump of /dev/vmdump,
5761 +struct __dump_page {
5762 + /* the address of this dump page */
5765 + /* the size of this dump page */
5768 + /* flags (currently DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */
5770 +} __attribute__((packed));
5773 + * Structure: __lkcdinfo
5774 + * Function: This structure contains information needed for the lkcdutils
5775 + * package (particularly lcrash) to determine what information is
5776 + * associated to this kernel, specifically.
5778 +struct __lkcdinfo {
5782 + int linux_release;
5793 + * Structure: __dump_compress
5794 + * Function: This is what an individual compression mechanism can use
5795 + * to plug in their own compression techniques. It's always
5796 + * best to build these as individual modules so that people
5797 + * can put in whatever they want.
5799 +struct __dump_compress {
5800 + /* the list_head structure for list storage */
5801 + struct list_head list;
5803 + /* the type of compression to use (DUMP_COMPRESS_XXX) */
5804 + int compress_type;
5805 + const char *compress_name;
5807 + /* the compression function to call */
5808 + u16 (*compress_func)(const u8 *, u16, u8 *, u16);
5811 +/* functions for dump compression registration */
5812 +extern void dump_register_compression(struct __dump_compress *);
5813 +extern void dump_unregister_compression(int);
5816 + * Structure dump_mbank[]:
5818 + * For CONFIG_DISCONTIGMEM systems this array specifies the
5819 + * memory banks/chunks that need to be dumped after a panic.
5821 + * For classic systems it specifies a single set of pages from
5824 +struct __dump_mbank {
5832 +#define DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY 1
5833 +#define DUMP_MBANK_TYPE_OTHER 2
5835 +#define MAXCHUNKS 256
5836 +extern int dump_mbanks;
5837 +extern struct __dump_mbank dump_mbank[MAXCHUNKS];
5839 +/* notification event codes */
5840 +#define DUMP_BEGIN 0x0001 /* dump beginning */
5841 +#define DUMP_END 0x0002 /* dump ending */
5843 +/* Scheduler soft spin control.
5845 + * 0 - no dump in progress
5846 + * 1 - cpu0 is dumping, ...
5848 +extern unsigned long dump_oncpu;
5849 +extern void dump_execute(const char *, const struct pt_regs *);
5852 + * Notifier list for kernel code which wants to be called
5855 +extern struct notifier_block *dump_notifier_list;
5856 +static inline int register_dump_notifier(struct notifier_block *nb)
5858 + return notifier_chain_register(&dump_notifier_list, nb);
5860 +static inline int unregister_dump_notifier(struct notifier_block * nb)
5862 + return notifier_chain_unregister(&dump_notifier_list, nb);
5865 +extern void (*dump_function_ptr)(const char *, const struct pt_regs *);
5866 +static inline void dump(char * str, struct pt_regs * regs)
5868 + if (dump_function_ptr)
5869 + dump_function_ptr(str, regs);
5873 + * Common Arch Specific Functions should be declared here.
5874 + * This allows the C compiler to detect discrepancies.
5876 +extern void __dump_open(void);
5877 +extern void __dump_cleanup(void);
5878 +extern void __dump_init(u64);
5879 +extern void __dump_save_regs(struct pt_regs *, const struct pt_regs *);
5880 +extern int __dump_configure_header(const struct pt_regs *);
5881 +extern void __dump_irq_enable(void);
5882 +extern void __dump_irq_restore(void);
5883 +extern int __dump_page_valid(unsigned long index);
5885 +extern void __dump_save_other_cpus(void);
5887 +#define __dump_save_other_cpus()
5890 +/* to track all used (compound + zero order) pages */
5891 +#define PageInuse(p) (PageCompound(p) || page_count(p))
5893 +#endif /* __KERNEL__ */
5895 +#else /* !CONFIG_CRASH_DUMP */
5897 +/* If not configured then make code disappear! */
5898 +#define register_dump_watchdog(x) do { } while(0)
5899 +#define unregister_dump_watchdog(x) do { } while(0)
5900 +#define register_dump_notifier(x) do { } while(0)
5901 +#define unregister_dump_notifier(x) do { } while(0)
5902 +#define dump_in_progress() 0
5903 +#define dump(x, y) do { } while(0)
5905 +#endif /* !CONFIG_CRASH_DUMP */
5907 +#endif /* _DUMP_H */
5908 Index: linux-2.6.0-test5/include/linux/dump_netdev.h
5909 ===================================================================
5910 --- linux-2.6.0-test5.orig/include/linux/dump_netdev.h 2003-09-26 14:26:34.000000000 +0800
5911 +++ linux-2.6.0-test5/include/linux/dump_netdev.h 2003-09-26 14:26:34.000000000 +0800
5914 + * linux/drivers/net/netconsole.h
5916 + * Copyright (C) 2001 Ingo Molnar <mingo@redhat.com>
5918 + * This file contains the implementation of an IRQ-safe, crash-safe
5919 + * kernel console implementation that outputs kernel messages to the
5922 + * Modification history:
5924 + * 2001-09-17 started by Ingo Molnar.
5927 +/****************************************************************
5928 + * This program is free software; you can redistribute it and/or modify
5929 + * it under the terms of the GNU General Public License as published by
5930 + * the Free Software Foundation; either version 2, or (at your option)
5931 + * any later version.
5933 + * This program is distributed in the hope that it will be useful,
5934 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5935 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5936 + * GNU General Public License for more details.
5938 + * You should have received a copy of the GNU General Public License
5939 + * along with this program; if not, write to the Free Software
5940 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
5942 + ****************************************************************/
5944 +#define NETCONSOLE_VERSION 0x03
5946 +enum netdump_commands {
5948 + COMM_SEND_MEM = 1,
5952 + COMM_GET_NR_PAGES = 5,
5953 + COMM_GET_PAGE_SIZE = 6,
5954 + COMM_START_NETDUMP_ACK = 7,
5955 + COMM_GET_REGS = 8,
5956 + COMM_GET_MAGIC = 9,
5957 + COMM_START_WRITE_NETDUMP_ACK = 10,
5961 +typedef struct netdump_req_s {
5969 +enum netdump_replies {
5974 + REPLY_RESERVED = 4,
5976 + REPLY_NR_PAGES = 6,
5977 + REPLY_PAGE_SIZE = 7,
5978 + REPLY_START_NETDUMP = 8,
5979 + REPLY_END_NETDUMP = 9,
5982 + REPLY_START_WRITE_NETDUMP = 12,
5986 +typedef struct netdump_reply_s {
5992 +#define HEADER_LEN (1 + sizeof(reply_t))
5995 Index: linux-2.6.0-test5/include/asm-i386/dump.h
5996 ===================================================================
5997 --- linux-2.6.0-test5.orig/include/asm-i386/dump.h 2003-09-26 14:26:34.000000000 +0800
5998 +++ linux-2.6.0-test5/include/asm-i386/dump.h 2003-09-26 14:26:34.000000000 +0800
6001 + * Kernel header file for Linux crash dumps.
6003 + * Created by: Matt Robinson (yakker@sgi.com)
6005 + * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
6007 + * This code is released under version 2 of the GNU GPL.
6010 +/* This header file holds the architecture specific crash dump header */
6011 +#ifndef _ASM_DUMP_H
6012 +#define _ASM_DUMP_H
6014 +/* necessary header files */
6015 +#include <asm/ptrace.h>
6016 +#include <asm/page.h>
6017 +#include <linux/threads.h>
6018 +#include <linux/mm.h>
6021 +#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */
6022 +#define DUMP_ASM_VERSION_NUMBER 0x3 /* version number */
6024 +/* max number of cpus */
6025 +#define DUMP_MAX_NUM_CPUS 32
6028 + * Structure: __dump_header_asm
6029 + * Function: This is the header for architecture-specific stuff. It
6030 + * follows right after the dump header.
6032 +struct __dump_header_asm {
6033 + /* the dump magic number -- unique to verify dump is valid */
6034 + u64 dha_magic_number;
6036 + /* the version number of this dump */
6039 + /* the size of this header (in case we can't read it) */
6040 + u32 dha_header_size;
6042 + /* the esp for i386 systems */
6045 + /* the eip for i386 systems */
6048 + /* the dump registers */
6049 + struct pt_regs dha_regs;
6051 + /* smp specific */
6052 + u32 dha_smp_num_cpus;
6053 + u32 dha_dumping_cpu;
6054 + struct pt_regs dha_smp_regs[DUMP_MAX_NUM_CPUS];
6055 + u32 dha_smp_current_task[DUMP_MAX_NUM_CPUS];
6056 + u32 dha_stack[DUMP_MAX_NUM_CPUS];
6057 + u32 dha_stack_ptr[DUMP_MAX_NUM_CPUS];
6058 +} __attribute__((packed));
6062 +extern struct __dump_header_asm dump_header_asm;
6065 +extern cpumask_t irq_affinity[];
6066 +extern int (*dump_ipi_function_ptr)(struct pt_regs *);
6067 +extern void dump_send_ipi(void);
6069 +#define dump_send_ipi() do { } while(0)
6072 +static inline void get_current_regs(struct pt_regs *regs)
6074 + __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx));
6075 + __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx));
6076 + __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx));
6077 + __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi));
6078 + __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi));
6079 + __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp));
6080 + __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax));
6081 + __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp));
6082 + __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss));
6083 + __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs));
6084 + __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds));
6085 + __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes));
6086 + __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags));
6087 + regs->eip = (unsigned long)current_text_addr();
6090 +#endif /* __KERNEL__ */
6092 +#endif /* _ASM_DUMP_H */
6093 Index: linux-2.6.0-test5/init/kerntypes.c
6094 ===================================================================
6095 --- linux-2.6.0-test5.orig/init/kerntypes.c 2003-09-26 14:26:34.000000000 +0800
6096 +++ linux-2.6.0-test5/init/kerntypes.c 2003-09-26 14:26:34.000000000 +0800
6101 + * Copyright (C) 2000 Tom Morano (tjm@sgi.com) and
6102 + * Matt D. Robinson (yakker@alacritech.com)
6104 + * Dummy module that includes headers for all kernel types of interest.
6105 + * The kernel type information is used by the lcrash utility when
6106 + * analyzing system crash dumps or the live system. Using the type
6107 + * information for the running system, rather than kernel header files,
6108 + * makes for a more flexible and robust analysis tool.
6110 + * This source code is released under version 2 of the GNU GPL.
6113 +#include <linux/compile.h>
6114 +#include <linux/module.h>
6115 +#include <linux/mm.h>
6116 +#include <linux/config.h>
6117 +#include <linux/utsname.h>
6118 +#include <linux/dump.h>
6120 +#ifdef LINUX_COMPILE_VERSION_ID_TYPE
6121 +/* Define version type for version validation of dump and kerntypes */
6122 +LINUX_COMPILE_VERSION_ID_TYPE;
6126 +kerntypes_dummy(void)
6129 Index: linux-2.6.0-test5/drivers/dump/dump_methods.h
6130 ===================================================================
6131 --- linux-2.6.0-test5.orig/drivers/dump/dump_methods.h 2003-09-26 14:26:34.000000000 +0800
6132 +++ linux-2.6.0-test5/drivers/dump/dump_methods.h 2003-09-26 14:26:34.000000000 +0800
6135 + * Generic interfaces for flexible system dump
6137 + * Started: Oct 2002 - Suparna Bhattacharya (suparna@in.ibm.com)
6139 + * Copyright (C) 2002 International Business Machines Corp.
6141 + * This code is released under version 2 of the GNU GPL.
6144 +#ifndef _LINUX_DUMP_METHODS_H
6145 +#define _LINUX_DUMP_METHODS_H
6148 + * Inspired by Matt Robinson's suggestion of introducing dump
6149 + * methods as a way to enable different crash dump facilities to
6150 + * coexist where each employs its own scheme or dumping policy.
6152 + * The code here creates a framework for flexible dump by defining
6153 + * a set of methods and providing associated helpers that differentiate
6154 + * between the underlying mechanism (how to dump), overall scheme
6155 + * (sequencing of stages and data dumped and associated quiescing),
6156 + * output format (what the dump output looks like), target type
6157 + * (where to save the dump; see dumpdev.h), and selection policy
6158 + * (state/data to dump).
6160 + * These sets of interfaces can be mixed and matched to build a
6161 + * dumper suitable for a given situation, allowing for
6162 + * flexibility as well appropriate degree of code reuse.
6163 + * For example all features and options of lkcd (including
6164 + * granular selective dumping in the near future) should be
6165 + * available even when say, the 2 stage soft-boot based mechanism
6166 + * is used for taking disruptive dumps.
6168 + * Todo: Additionally modules or drivers may supply their own
6169 + * custom dumpers which extend dump with module specific
6170 + * information or hardware state, and can even tweak the
6171 + * mechanism when it comes to saving state relevant to
6175 +#include <linux/sched.h>
6176 +#include <linux/slab.h>
6177 +#include <linux/highmem.h>
6178 +#include <linux/dumpdev.h>
6180 +#define MAX_PASSES 6
6184 +/* To customise selection of pages to be dumped in a given pass/group */
6185 +struct dump_data_filter{
6187 + int (*selector)(int, unsigned long, unsigned long);
6188 + ulong level_mask; /* dump level(s) for which this filter applies */
6189 + loff_t start, end; /* location range applicable */
6194 + * Determined by the kind of dump mechanism and appropriate
6197 +struct dump_scheme_ops {
6198 + /* sets aside memory, inits data structures etc */
6199 + int (*configure)(unsigned long devid);
6200 + /* releases resources */
6201 + int (*unconfigure)(void);
6203 + /* ordering of passes, invoking iterator */
6204 + int (*sequencer)(void);
6205 + /* iterates over system data, selects and acts on data to dump */
6206 + int (*iterator)(int, int (*)(unsigned long, unsigned long),
6207 + struct dump_data_filter *);
6208 + /* action when data is selected for dump */
6209 + int (*save_data)(unsigned long, unsigned long);
6210 + /* action when data is to be excluded from dump */
6211 + int (*skip_data)(unsigned long, unsigned long);
6212 + /* policies for space, multiple dump devices etc */
6213 + int (*write_buffer)(void *, unsigned long);
6216 +struct dump_scheme {
6217 + /* the name serves as an anchor to locate the scheme after reboot */
6219 + struct dump_scheme_ops *ops;
6220 + struct list_head list;
6223 +/* Quiescing/Silence levels (controls IPI callback behaviour) */
6224 +extern enum dump_silence_levels {
6225 + DUMP_SOFT_SPIN_CPUS = 1,
6226 + DUMP_HARD_SPIN_CPUS = 2,
6227 + DUMP_HALT_CPUS = 3,
6228 +} dump_silence_level;
6230 +/* determined by the dump (file) format */
6231 +struct dump_fmt_ops {
6232 + /* build header */
6233 + int (*configure_header)(const char *, const struct pt_regs *);
6234 + int (*update_header)(void); /* update header and write it out */
6235 + /* save curr context */
6236 + void (*save_context)(int, const struct pt_regs *,
6237 + struct task_struct *);
6238 + /* typically called by the save_data action */
6239 + /* add formatted data to the dump buffer */
6240 + int (*add_data)(unsigned long, unsigned long);
6241 + int (*update_end_marker)(void);
6245 + unsigned long magic;
6246 + char name[32]; /* lcrash, crash, elf-core etc */
6247 + struct dump_fmt_ops *ops;
6248 + struct list_head list;
6252 + * Modules will be able add their own data capture schemes by
6253 + * registering their own dumpers. Typically they would use the
6254 + * primary dumper as a template and tune it with their routines.
6258 +/* The combined dumper profile (mechanism, scheme, dev, fmt) */
6260 + char name[32]; /* singlestage, overlay (stg1), passthru(stg2), pull */
6261 + struct dump_scheme *scheme;
6262 + struct dump_fmt *fmt;
6263 + struct __dump_compress *compress;
6264 + struct dump_data_filter *filter;
6265 + struct dump_dev *dev;
6266 + /* state valid only for active dumper(s) - per instance */
6267 + /* run time state/context */
6269 + unsigned long count;
6270 + loff_t curr_offset; /* current logical offset into dump device */
6271 + loff_t curr_loc; /* current memory location */
6272 + void *curr_buf; /* current position in the dump buffer */
6273 + void *dump_buf; /* starting addr of dump buffer */
6274 + int header_dirty; /* whether the header needs to be written out */
6276 + struct list_head dumper_list; /* links to other dumpers */
6279 +/* Starting point to get to the current configured state */
6280 +struct dump_config {
6283 + struct dumper *dumper;
6284 + unsigned long dump_device;
6285 + unsigned long dump_addr; /* relevant only for in-memory dumps */
6286 + struct list_head dump_dev_list;
6289 +extern struct dump_config dump_config;
6291 +/* Used to save the dump config across a reboot for 2-stage dumps:
6293 + * Note: The scheme, format, compression and device type should be
6294 + * registered at bootup, for this config to be sharable across soft-boot.
6295 + * The function addresses could have changed and become invalid, and
6296 + * need to be set up again.
6298 +struct dump_config_block {
6299 + u64 magic; /* for a quick sanity check after reboot */
6300 + struct dump_memdev memdev; /* handle to dump stored in memory */
6301 + struct dump_config config;
6302 + struct dumper dumper;
6303 + struct dump_scheme scheme;
6304 + struct dump_fmt fmt;
6305 + struct __dump_compress compress;
6306 + struct dump_data_filter filter_table[MAX_PASSES];
6307 + struct dump_anydev dev[MAX_DEVS]; /* target dump device */
6311 +/* Wrappers that invoke the methods for the current (active) dumper */
6313 +/* Scheme operations */
6315 +static inline int dump_sequencer(void)
6317 + return dump_config.dumper->scheme->ops->sequencer();
6320 +static inline int dump_iterator(int pass, int (*action)(unsigned long,
6321 + unsigned long), struct dump_data_filter *filter)
6323 + return dump_config.dumper->scheme->ops->iterator(pass, action, filter);
6326 +#define dump_save_data dump_config.dumper->scheme->ops->save_data
6327 +#define dump_skip_data dump_config.dumper->scheme->ops->skip_data
6329 +static inline int dump_write_buffer(void *buf, unsigned long len)
6331 + return dump_config.dumper->scheme->ops->write_buffer(buf, len);
6334 +static inline int dump_configure(unsigned long devid)
6336 + return dump_config.dumper->scheme->ops->configure(devid);
6339 +static inline int dump_unconfigure(void)
6341 + return dump_config.dumper->scheme->ops->unconfigure();
6344 +/* Format operations */
6346 +static inline int dump_configure_header(const char *panic_str,
6347 + const struct pt_regs *regs)
6349 + return dump_config.dumper->fmt->ops->configure_header(panic_str, regs);
6352 +static inline void dump_save_context(int cpu, const struct pt_regs *regs,
6353 + struct task_struct *tsk)
6355 + dump_config.dumper->fmt->ops->save_context(cpu, regs, tsk);
6358 +static inline int dump_save_this_cpu(const struct pt_regs *regs)
6360 + int cpu = smp_processor_id();
6362 + dump_save_context(cpu, regs, current);
6366 +static inline int dump_update_header(void)
6368 + return dump_config.dumper->fmt->ops->update_header();
6371 +static inline int dump_update_end_marker(void)
6373 + return dump_config.dumper->fmt->ops->update_end_marker();
6376 +static inline int dump_add_data(unsigned long loc, unsigned long sz)
6378 + return dump_config.dumper->fmt->ops->add_data(loc, sz);
6381 +/* Compression operation */
6382 +static inline int dump_compress_data(char *src, int slen, char *dst)
6384 + return dump_config.dumper->compress->compress_func(src, slen,
6385 + dst, DUMP_DPC_PAGE_SIZE);
6389 +/* Prototypes of some default implementations of dump methods */
6391 +extern struct __dump_compress dump_none_compression;
6393 +/* Default scheme methods (dump_scheme.c) */
6395 +extern int dump_generic_sequencer(void);
6396 +extern int dump_page_iterator(int pass, int (*action)(unsigned long, unsigned
6397 + long), struct dump_data_filter *filter);
6398 +extern int dump_generic_save_data(unsigned long loc, unsigned long sz);
6399 +extern int dump_generic_skip_data(unsigned long loc, unsigned long sz);
6400 +extern int dump_generic_write_buffer(void *buf, unsigned long len);
6401 +extern int dump_generic_configure(unsigned long);
6402 +extern int dump_generic_unconfigure(void);
6404 +/* Default scheme template */
6405 +extern struct dump_scheme dump_scheme_singlestage;
6407 +/* Default dump format methods */
6409 +extern int dump_lcrash_configure_header(const char *panic_str,
6410 + const struct pt_regs *regs);
6411 +extern void dump_lcrash_save_context(int cpu, const struct pt_regs *regs,
6412 + struct task_struct *tsk);
6413 +extern int dump_generic_update_header(void);
6414 +extern int dump_lcrash_add_data(unsigned long loc, unsigned long sz);
6415 +extern int dump_lcrash_update_end_marker(void);
6417 +/* Default format (lcrash) template */
6418 +extern struct dump_fmt dump_fmt_lcrash;
6420 +/* Default dump selection filter table */
6423 + * Entries listed in order of importance and correspond to passes
6424 + * The last entry (with a level_mask of zero) typically reflects data that
6425 + * won't be dumped -- this may for example be used to identify data
6426 + * that will be skipped for certain so the corresponding memory areas can be
6427 + * utilized as scratch space.
6429 +extern struct dump_data_filter dump_filter_table[];
6431 +/* Some pre-defined dumpers */
6432 +extern struct dumper dumper_singlestage;
6433 +extern struct dumper dumper_stage1;
6434 +extern struct dumper dumper_stage2;
6436 +/* These are temporary */
6437 +#define DUMP_MASK_HEADER DUMP_LEVEL_HEADER
6438 +#define DUMP_MASK_KERN DUMP_LEVEL_KERN
6439 +#define DUMP_MASK_USED DUMP_LEVEL_USED
6440 +#define DUMP_MASK_UNUSED DUMP_LEVEL_ALL_RAM
6441 +#define DUMP_MASK_REST 0 /* dummy for now */
6443 +/* Helpers - move these to dump.h later ? */
6445 +int dump_generic_execute(const char *panic_str, const struct pt_regs *regs);
6446 +extern int dump_ll_write(void *buf, unsigned long len);
6447 +int dump_check_and_free_page(struct dump_memdev *dev, struct page *page);
6449 +static inline void dumper_reset(void)
6451 + dump_config.dumper->curr_buf = dump_config.dumper->dump_buf;
6452 + dump_config.dumper->curr_loc = 0;
6453 + dump_config.dumper->curr_offset = 0;
6454 + dump_config.dumper->count = 0;
6455 + dump_config.dumper->curr_pass = 0;
6459 + * May later be moulded to perform boot-time allocations so we can dump
6460 + * earlier during bootup
6462 +static inline void *dump_alloc_mem(unsigned long size)
6464 + return kmalloc(size, GFP_KERNEL);
6467 +static inline void dump_free_mem(void *buf)
6469 + struct page *page;
6471 + /* ignore reserved pages (e.g. post soft boot stage) */
6472 + if (buf && (page = virt_to_page(buf))) {
6473 + if (PageReserved(page))
6481 +#endif /* _LINUX_DUMP_METHODS_H */
6482 Index: linux-2.6.0-test5/Makefile
6483 ===================================================================
6484 --- linux-2.6.0-test5.orig/Makefile 2003-09-26 14:26:29.000000000 +0800
6485 +++ linux-2.6.0-test5/Makefile 2003-09-26 14:26:34.000000000 +0800
6486 @@ -289,6 +289,10 @@
6488 export MODVERDIR := .tmp_versions
6490 +ifeq ($(CONFIG_CRASH_DUMP),)
6494 # The temporary file to save gcc -MD generated dependencies must not