Whamcloud - gitweb
smash the HEAD with the contents of b_cmd. HEAD_PRE_CMD_SMASH and
[fs/lustre-release.git] / lustre / kernel_patches / patches / lkcd-cvs-2.6.0-test6.patch
1  0 files changed
2
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
7 @@ -0,0 +1,14 @@
8 +#
9 +# Makefile for the dump device drivers.
10 +#
11 +
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)
16 +
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
26 @@ -0,0 +1,461 @@
27 +/*
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
30 + * routines.
31 + *
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
35 + *
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
38 + *
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)  
42 + *
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. 
46 + *
47 + * This code is released under version 2 of the GNU GPL.
48 + */
49 +
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"
59 +
60 +extern void *dump_page_buf;
61 +
62 +/* The end_io callback for dump i/o completion */
63 +static int
64 +dump_bio_end_io(struct bio *bio, unsigned int bytes_done, int error)
65 +{
66 +       struct dump_blockdev *dump_bdev;
67 +
68 +       if (bio->bi_size) {
69 +               /* some bytes still left to transfer */
70 +               return 1; /* not complete */
71 +       }
72 +
73 +       dump_bdev = (struct dump_blockdev *)bio->bi_private;
74 +       if (error) {
75 +               printk("IO error while writing the dump, aborting\n");
76 +       }
77 +
78 +       dump_bdev->err = error;
79 +
80 +       /* no wakeup needed, since caller polls for completion */
81 +       return 0;
82 +}
83 +
84 +/* Check if the dump bio is already mapped to the specified buffer */
85 +static int
86 +dump_block_map_valid(struct dump_blockdev *dev, struct page *page, 
87 +       int len) 
88 +{
89 +       struct bio *bio = dev->bio;
90 +       unsigned long bsize = 0;
91 +
92 +       if (!bio->bi_vcnt)
93 +               return 0; /* first time, not mapped */
94 +
95 +
96 +       if ((bio_page(bio) != page) || (len > bio->bi_vcnt << PAGE_SHIFT))
97 +               return 0; /* buffer not mapped */
98 +
99 +       bsize = bdev_hardsect_size(bio->bi_bdev);
100 +       if ((len & (PAGE_SIZE - 1)) || (len & bsize))
101 +               return 0; /* alignment checks needed */
102 +
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 */
106 +
107 +       return 1; /* already mapped */
108 +}
109 +
110 +/* 
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
113 + */
114 +static int
115 +dump_block_map(struct dump_blockdev *dev, void *buf, int len)
116 +{
117 +       struct page *page = virt_to_page(buf);
118 +       struct bio *bio = dev->bio;
119 +       unsigned long bsize = 0;
120 +
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 */
124 +
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 */
128 +       } else {
129 +               /* need to map the bio */
130 +               bio->bi_size = 0;
131 +               bio->bi_vcnt = 0;
132 +               bsize = bdev_hardsect_size(bio->bi_bdev);
133 +
134 +               /* first a few sanity checks */
135 +               if (len < bsize) {
136 +                       printk("map: len less than hardsect size \n");
137 +                       return -EINVAL;
138 +               }
139 +
140 +               if ((unsigned long)buf & bsize) {
141 +                       printk("map: not aligned \n");
142 +                       return -EINVAL;
143 +               }
144 +
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");
148 +                       return -EINVAL; 
149 +               }
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) {
153 +                               break;
154 +                       }
155 +
156 +               bio->bi_end_io = dump_bio_end_io;
157 +               bio->bi_private = dev;
158 +       }
159 +
160 +       if (bio->bi_size != len) {
161 +               printk("map: bio size = %d not enough for len = %d!\n",
162 +                       bio->bi_size, len);
163 +               return -E2BIG;
164 +       }
165 +       return 0;
166 +}
167 +
168 +static void
169 +dump_free_bio(struct bio *bio)
170 +{
171 +       if (bio)
172 +               kfree(bio->bi_io_vec);
173 +       kfree(bio);
174 +}
175 +
176 +/*
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.
180 + *
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.
184 + */
185 +static int
186 +dump_block_open(struct dump_dev *dev, unsigned long arg)
187 +{
188 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
189 +       struct block_device *bdev;
190 +       int retval = 0;
191 +       struct bio_vec *bvec;
192 +
193 +       /* make sure this is a valid block device */
194 +       if (!arg) {
195 +               retval = -EINVAL;
196 +               goto err;
197 +       }
198 +
199 +       /* get a corresponding block_dev struct for this */
200 +       bdev = bdget((dev_t)arg);
201 +       if (!bdev) {
202 +               retval = -ENODEV;
203 +               goto err;
204 +       }
205 +
206 +       /* get the block device opened */
207 +       if ((retval = blkdev_get(bdev, O_RDWR | O_LARGEFILE, 0, BDEV_RAW))) {
208 +               goto err1;
209 +       }
210 +
211 +       if ((dump_bdev->bio = kmalloc(sizeof(struct bio), GFP_KERNEL)) 
212 +               == NULL) {
213 +               printk("Cannot allocate bio\n");
214 +               retval = -ENOMEM;
215 +               goto err2;
216 +       }
217 +
218 +       bio_init(dump_bdev->bio);
219 +
220 +       if ((bvec = kmalloc(sizeof(struct bio_vec) * 
221 +               (DUMP_BUFFER_SIZE >> PAGE_SHIFT), GFP_KERNEL)) == NULL) {
222 +               retval = -ENOMEM;
223 +               goto err3;
224 +       }
225 +
226 +       /* assign the new dump dev structure */
227 +       dump_bdev->kdev_id = new_decode_dev((dev_t)arg);
228 +       dump_bdev->bdev = bdev;
229 +
230 +       /* make a note of the limit */
231 +       dump_bdev->limit = bdev->bd_inode->i_size;
232 +       
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;
236 +
237 +       retval = dump_block_map(dump_bdev, dump_config.dumper->dump_buf, 
238 +               DUMP_BUFFER_SIZE);
239 +               
240 +       if (retval) {
241 +               printk("open: dump_block_map failed, ret %d\n", retval);
242 +               goto err3;
243 +       }
244 +
245 +       printk("Block device (%d,%d) successfully configured for dumping\n",
246 +              MAJOR(dump_bdev->kdev_id),
247 +              MINOR(dump_bdev->kdev_id));
248 +
249 +
250 +       /* after opening the block device, return */
251 +       return retval;
252 +
253 +err3:  dump_free_bio(dump_bdev->bio);
254 +       dump_bdev->bio = NULL;
255 +err2:  if (bdev) blkdev_put(bdev, BDEV_RAW);
256 +               goto err;
257 +err1:  if (bdev) bdput(bdev);
258 +       dump_bdev->bdev = NULL;
259 +err:   return retval;
260 +}
261 +
262 +/*
263 + * Close the dump device and release associated resources
264 + * Invoked when unconfiguring the dump device.
265 + */
266 +static int
267 +dump_block_release(struct dump_dev *dev)
268 +{
269 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
270 +
271 +       /* release earlier bdev if present */
272 +       if (dump_bdev->bdev) {
273 +               blkdev_put(dump_bdev->bdev, BDEV_RAW);
274 +               dump_bdev->bdev = NULL;
275 +       }
276 +
277 +       dump_free_bio(dump_bdev->bio);
278 +       dump_bdev->bio = NULL;
279 +
280 +       return 0;
281 +}
282 +
283 +
284 +/*
285 + * Prepare the dump device for use (silence any ongoing activity
286 + * and quiesce state) when the system crashes.
287 + */
288 +static int
289 +dump_block_silence(struct dump_dev *dev)
290 +{
291 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
292 +       struct request_queue *q = bdev_get_queue(dump_bdev->bdev);
293 +       int ret;
294 +
295 +       /* If we can't get request queue lock, refuse to take the dump */
296 +       if (!spin_trylock(q->queue_lock))
297 +               return -EBUSY;
298 +
299 +       ret = elv_queue_empty(q);
300 +       spin_unlock(q->queue_lock);
301 +
302 +       /* For now we assume we have the device to ourselves */
303 +       /* Just a quick sanity check */
304 +       if (!ret) {
305 +               /* i/o in flight - safer to quit */
306 +               return -EBUSY;
307 +       }
308 +
309 +       /* 
310 +        * Move to a softer level of silencing where no spin_lock_irqs 
311 +        * are held on other cpus
312 +        */
313 +       dump_silence_level = DUMP_SOFT_SPIN_CPUS;       
314 +
315 +       __dump_irq_enable();
316 +
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());
320 +       
321 +       return 0;
322 +}
323 +
324 +/*
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.
328 + */
329 +static int
330 +dump_block_resume(struct dump_dev *dev)
331 +{
332 +       __dump_irq_restore();
333 +       return 0;
334 +}
335 +
336 +
337 +/*
338 + * Seek to the specified offset in the dump device.
339 + * Makes sure this is a valid offset, otherwise returns an error.
340 + */
341 +static int
342 +dump_block_seek(struct dump_dev *dev, loff_t off)
343 +{
344 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
345 +       loff_t offset = off + dump_bdev->start_offset;
346 +       
347 +       if (offset & ( PAGE_SIZE - 1)) {
348 +               printk("seek: non-page aligned\n");
349 +               return -EINVAL;
350 +       }
351 +
352 +       if (offset & (bdev_hardsect_size(dump_bdev->bdev) - 1)) {
353 +               printk("seek: not sector aligned \n");
354 +               return -EINVAL;
355 +       }
356 +
357 +       if (offset > dump_bdev->limit) {
358 +               printk("seek: not enough space left on device!\n");
359 +               return -ENOSPC; 
360 +       }
361 +       dev->curr_offset = off;
362 +       return 0;
363 +}
364 +
365 +/*
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).
369 + *
370 + * Returns: number of bytes written or -ERRNO. 
371 + */
372 +static int
373 +dump_block_write(struct dump_dev *dev, void *buf, 
374 +       unsigned long len)
375 +{
376 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
377 +       loff_t offset = dev->curr_offset + dump_bdev->start_offset;
378 +       int retval = -ENOSPC;
379 +
380 +       if (offset >= dump_bdev->limit) {
381 +               printk("write: not enough space left on device!\n");
382 +               goto out;
383 +       }
384 +
385 +       /* don't write more blocks than our max limit */
386 +       if (offset + len > dump_bdev->limit) 
387 +               len = dump_bdev->limit - offset;
388 +
389 +
390 +       retval = dump_block_map(dump_bdev, buf, len);
391 +       if (retval){
392 +               printk("write: dump_block_map failed! err %d\n", retval);
393 +               goto out;
394 +       }
395 +
396 +       /*
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.
402 +        */
403 +       dump_bdev->err = -EAGAIN;
404 +       submit_bio(WRITE, dump_bdev->bio);
405 +
406 +       dump_bdev->ddev.curr_offset += len;
407 +       retval = len;
408 + out:
409 +       return retval;
410 +}
411 +
412 +/*
413 + * Name: dump_block_ready()
414 + * Func: check if the last dump i/o is over and ready for next request
415 + */
416 +static int
417 +dump_block_ready(struct dump_dev *dev, void *buf)
418 +{
419 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
420 +       request_queue_t *q = bdev_get_queue(dump_bdev->bio->bi_bdev);
421 +
422 +       /* check for io completion */
423 +       if (dump_bdev->err == -EAGAIN) {
424 +               q->unplug_fn(q);
425 +               return -EAGAIN;
426 +       }
427 +
428 +       if (dump_bdev->err) {
429 +               printk("dump i/o err\n");
430 +               return dump_bdev->err;
431 +       }
432 +
433 +       return 0;
434 +}
435 +
436 +
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
446 +};
447 +
448 +static struct dump_blockdev default_dump_blockdev = {
449 +       .ddev = {.type_name = "blockdev", .ops = &dump_blockdev_ops, 
450 +                       .curr_offset = 0},
451 +       /* 
452 +        * leave enough room for the longest swap header possibly written 
453 +        * written by mkswap (likely the largest page size supported by
454 +        * the arch
455 +        */
456 +       .start_offset   = DUMP_HEADER_OFFSET,
457 +       .err            = 0
458 +       /* assume the rest of the fields are zeroed by default */
459 +};     
460 +       
461 +struct dump_blockdev *dump_blockdev = &default_dump_blockdev;
462 +
463 +static int __init
464 +dump_blockdev_init(void)
465 +{
466 +       if (dump_register_device(&dump_blockdev->ddev) < 0) {
467 +               printk("block device driver registration failed\n");
468 +               return -1;
469 +       }
470 +               
471 +       printk("block device driver for LKCD registered\n");
472 +       return 0;
473 +}
474 +
475 +static void __exit
476 +dump_blockdev_cleanup(void)
477 +{
478 +       dump_unregister_device(&dump_blockdev->ddev);
479 +       printk("block device driver for LKCD unregistered\n");
480 +}
481 +
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");
485 +
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
492 @@ -0,0 +1,126 @@
493 +/*
494 + * The file has the common/generic dump execution code 
495 + *
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.
499 + *
500 + * Derived from original code in dump_base.c created by 
501 + *     Matt Robinson <yakker@sourceforge.net>)
502 + *     
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. 
506 + *
507 + * Assumes dumper and dump config settings are in place
508 + * (invokes corresponding dumper specific routines as applicable)
509 + *
510 + * This code is released under version 2 of the GNU GPL.
511 + */
512 +#include <linux/kernel.h>
513 +#include <linux/notifier.h>
514 +#include <linux/dump.h>
515 +#include "dump_methods.h"
516 +
517 +struct notifier_block *dump_notifier_list; /* dump started/ended callback */
518 +
519 +/* Dump progress indicator */
520 +void 
521 +dump_speedo(int i)
522 +{
523 +       static const char twiddle[4] =  { '|', '\\', '-', '/' };
524 +       printk("%c\b", twiddle[i&3]);
525 +}
526 +
527 +/* Make the device ready and write out the header */
528 +int dump_begin(void)
529 +{
530 +       int err = 0;
531 +
532 +       /* dump_dev = dump_config.dumper->dev; */
533 +       dumper_reset();
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);
538 +               return err;
539 +       }
540 +
541 +       pr_debug("Writing dump header\n");
542 +       if ((err = dump_update_header())) {
543 +               printk("dump update header failed ! error %d\n", err);
544 +               dump_dev_resume();
545 +               return err;
546 +       }
547 +
548 +       dump_config.dumper->curr_offset = DUMP_BUFFER_SIZE;
549 +
550 +       return 0;
551 +}
552 +
553 +/* 
554 + * Write the dump terminator, a final header update and let go of 
555 + * exclusive use of the device for dump.
556 + */
557 +int dump_complete(void)
558 +{
559 +       int ret = 0;
560 +
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);
564 +               }
565 +               if ((ret = dump_update_header())) {
566 +                       printk("dump update header error %d\n", ret);
567 +               }
568 +       }
569 +       ret = dump_dev_resume();
570 +
571 +       return ret;
572 +}
573 +
574 +/* Saves all dump data */
575 +int dump_execute_savedump(void)
576 +{
577 +       int ret = 0, err = 0;
578 +
579 +       if ((ret = dump_begin()))  {
580 +               return ret;
581 +       }
582 +
583 +       if (dump_config.level != DUMP_LEVEL_HEADER) { 
584 +               ret = dump_sequencer();
585 +       }
586 +       if ((err = dump_complete())) {
587 +               printk("Dump complete failed. Error %d\n", err);
588 +       }
589 +
590 +       return ret;
591 +}
592 +
593 +/* Does all the real work:  Capture and save state */
594 +int dump_generic_execute(const char *panic_str, const struct pt_regs *regs)
595 +{
596 +       int ret = 0;
597 +
598 +       if ((ret = dump_configure_header(panic_str, regs))) {
599 +               printk("dump config header failed ! error %d\n", ret);
600 +               return ret;     
601 +       }
602 +
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);
606 +
607 +       if (dump_config.level != DUMP_LEVEL_NONE)
608 +               ret = dump_execute_savedump();
609 +
610 +       pr_debug("dumped %ld blocks of %d bytes each\n", 
611 +               dump_config.dumper->count, DUMP_BUFFER_SIZE);
612 +       
613 +       /* tell interested parties that a dump has completed */
614 +       notifier_call_chain(&dump_notifier_list, DUMP_END, 
615 +               &dump_config.dump_device);
616 +
617 +       return ret;
618 +}
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
623 @@ -0,0 +1,143 @@
624 +/*
625 + * Default filters to select data to dump for various passes.
626 + *
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>)
632 + *
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. 
636 + *
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)
640 + *
641 + * Future: Custom selective dump may involve a different set of filters.
642 + *
643 + * This code is released under version 2 of the GNU GPL.
644 + */
645 +
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"
652 +
653 +
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)
657 +{
658 +       unsigned long mapsize;
659 +       unsigned long pages = num_physpages;
660 +
661 +       mapsize = (pages+7)/8;
662 +       mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK;
663 +       mapsize >>= PAGE_SHIFT;
664 +
665 +       return mapsize;
666 +}
667 +
668 +
669 +#define DUMP_PFN_SAFETY_MARGIN 1024  /* 4 MB */
670 +/* temporary */
671 +extern unsigned long min_low_pfn;
672 +
673 +
674 +int dump_low_page(struct page *p)
675 +{
676 +       return page_to_pfn(p) < min_low_pfn + dump_calc_bootmap_pages() 
677 +                       + 1 + DUMP_PFN_SAFETY_MARGIN;
678 +}
679 +
680 +static inline int kernel_page(struct page *p)
681 +{
682 +       /* FIXME: Need to exclude hugetlb pages. Clue: reserved but inuse */
683 +       return PageReserved(p) || (!PageLRU(p) && PageInuse(p));
684 +}
685 +
686 +static inline int user_page(struct page *p)
687 +{
688 +       return PageInuse(p) && (!PageReserved(p) && PageLRU(p));
689 +}
690 +
691 +static inline int unreferenced_page(struct page *p)
692 +{
693 +       return !PageInuse(p) && !PageReserved(p);
694 +}
695 +
696 +
697 +/* loc marks the beginning of a range of pages */
698 +int dump_filter_kernpages(int pass, unsigned long loc, unsigned long sz)
699 +{
700 +       struct page *page = (struct page *)loc;
701 +       /* if any of the pages is a kernel page, select this set */     
702 +       while (sz) {
703 +               if (dump_low_page(page) || kernel_page(page))
704 +                       return 1;
705 +               sz -= PAGE_SIZE;
706 +               page++;
707 +       }       
708 +       return 0;
709 +}
710 +
711 +
712 +/* loc marks the beginning of a range of pages */
713 +int dump_filter_userpages(int pass, unsigned long loc, unsigned long sz)
714 +{
715 +       struct page *page = (struct page *)loc;
716 +       int ret = 0;
717 +       /* select if the set has any user page, and no kernel pages  */ 
718 +       while (sz) {
719 +               if (user_page(page) && !dump_low_page(page)) {
720 +                       ret = 1;
721 +               } else if (kernel_page(page) || dump_low_page(page)) {
722 +                       return 0;
723 +               }
724 +               page++;
725 +               sz -= PAGE_SIZE;
726 +       }       
727 +       return ret;
728 +}
729 +
730 +
731 +
732 +/* loc marks the beginning of a range of pages */
733 +int dump_filter_unusedpages(int pass, unsigned long loc, unsigned long sz)
734 +{
735 +       struct page *page = (struct page *)loc;
736 +
737 +       /* select if the set does not have any used pages  */   
738 +       while (sz) {
739 +               if (!unreferenced_page(page) || dump_low_page(page)) {
740 +                       return 0;
741 +               }
742 +               page++;
743 +               sz -= PAGE_SIZE;
744 +       }       
745 +       return 1;
746 +}
747 +
748 +/* dummy: last (non-existent) pass */
749 +int dump_filter_none(int pass, unsigned long loc, unsigned long sz)
750 +{
751 +       return 0;
752 +}
753 +
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}
765 +};
766 +
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
771 @@ -0,0 +1,399 @@
772 +/*
773 + * Implements the routines which handle the format specific
774 + * aspects of dump for the default dump format.
775 + *
776 + * Used in single stage dumping and stage 1 of soft-boot based dumping 
777 + * Saves data in LKCD (lcrash) format 
778 + *
779 + * Previously a part of dump_base.c
780 + *
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.
784 + *
785 + * Derived from original code created by 
786 + *     Matt Robinson <yakker@sourceforge.net>)
787 + *
788 + * Contributions from SGI, IBM, HP, MCL, and others.
789 + *
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. 
794 + *
795 + * This code is released under version 2 of the GNU GPL.
796 + */
797 +
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"
807 +
808 +/*
809 + * SYSTEM DUMP LAYOUT
810 + * 
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:
814 + *
815 + *             +-----------------------------+
816 + *             |     generic dump header     |
817 + *             +-----------------------------+
818 + *             |   architecture dump header  |
819 + *             +-----------------------------+
820 + *             |         page header         |
821 + *             +-----------------------------+
822 + *             |          page data          |
823 + *             +-----------------------------+
824 + *             |         page header         |
825 + *             +-----------------------------+
826 + *             |          page data          |
827 + *             +-----------------------------+
828 + *             |              |              |
829 + *             |              |              |
830 + *             |              |              |
831 + *             |              |              |
832 + *             |              V              |
833 + *             +-----------------------------+
834 + *             |        PAGE_END header      |
835 + *             +-----------------------------+
836 + *
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.
841 + *
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
849 + * of space.
850 + *
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.
854 + */
855 +
856 +struct __dump_header dump_header;  /* the primary dump header              */
857 +struct __dump_header_asm dump_header_asm; /* the arch-specific dump header */
858 +
859 +/*
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.
863 + */
864 +static int lcrash_init_dump_header(const char *panic_str)
865 +{
866 +       struct timeval dh_time;
867 +       struct sysinfo info;
868 +
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");
874 +                       return -E2BIG;
875 +       }
876 +
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));
880 +
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);
887 +       si_meminfo(&info);
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->
893 +               compress_type;
894 +       dump_header.dh_dump_flags = dump_config.flags;
895 +       dump_header.dh_dump_device = dump_config.dumper->dev->device_id; 
896 +       
897 +#if DUMP_DEBUG >= 6
898 +       dump_header.dh_num_bytes = 0;
899 +#endif
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;
904 +
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);
917 +
918 +       if (panic_str) {
919 +               memcpy((void *)&(dump_header.dh_panic_string),
920 +                       (const void *)panic_str, DUMP_PANIC_LEN);
921 +       }
922 +
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);
926 +
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);
930 +
931 +       dump_header_asm.dha_dumping_cpu = smp_processor_id();
932 +       
933 +       return sizeof(dump_header) + sizeof(dump_header_asm);
934 +}
935 +
936 +
937 +int dump_lcrash_configure_header(const char *panic_str, 
938 +       const struct pt_regs *regs)
939 +{
940 +       int retval = 0;
941 +
942 +       dump_config.dumper->header_len = lcrash_init_dump_header(panic_str);
943 +
944 +       /* capture register states for all processors */
945 +       dump_save_this_cpu(regs);
946 +       __dump_save_other_cpus(); /* side effect:silence cpus */
947 +
948 +       /* configure architecture-specific dump header values */
949 +       if ((retval = __dump_configure_header(regs))) 
950 +               return retval;
951 +
952 +       dump_config.dumper->header_dirty++;
953 +       return 0;
954 +}
955 +
956 +/* save register and task context */
957 +void dump_lcrash_save_context(int cpu, const struct pt_regs *regs, 
958 +       struct task_struct *tsk)
959 +{
960 +       dump_header_asm.dha_smp_current_task[cpu] = (uint32_t) tsk;
961 +
962 +       __dump_save_regs(&dump_header_asm.dha_smp_regs[cpu], regs);
963 +
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);
969 +       }
970 +       dump_header_asm.dha_stack_ptr[cpu] = (uint32_t)(tsk->thread_info);
971 +}
972 +
973 +/* write out the header */
974 +int dump_write_header(void)
975 +{
976 +       int retval = 0, size;
977 +       void *buf = dump_config.dumper->dump_buf;
978 +
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", 
982 +                       retval);
983 +               return retval;
984 +       }
985 +
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);
992 +
993 +       if (retval < size) 
994 +               return (retval >= 0) ? ENOSPC : retval;
995 +
996 +       return 0;
997 +}
998 +
999 +int dump_generic_update_header(void)
1000 +{
1001 +       int err = 0;
1002 +
1003 +       if (dump_config.dumper->header_dirty) {
1004 +               if ((err = dump_write_header())) {
1005 +                       printk("dump write header failed !err %d\n", err);
1006 +               } else {
1007 +                       dump_config.dumper->header_dirty = 0;
1008 +               }
1009 +       }
1010 +
1011 +       return err;
1012 +}
1013 +
1014 +static inline int is_curr_stack_page(struct page *page, unsigned long size)
1015 +{
1016 +       unsigned long thread_addr = (unsigned long)current_thread_info();
1017 +       unsigned long addr = (unsigned long)page_address(page);
1018 +
1019 +       return !PageHighMem(page) && (addr < thread_addr + THREAD_SIZE)
1020 +               && (addr + size > thread_addr);
1021 +}
1022 +
1023 +static inline int is_dump_page(struct page *page, unsigned long size)
1024 +{
1025 +       unsigned long addr = (unsigned long)page_address(page);
1026 +       unsigned long dump_buf = (unsigned long)dump_config.dumper->dump_buf;
1027 +
1028 +       return !PageHighMem(page) && (addr < dump_buf + DUMP_BUFFER_SIZE)
1029 +               && (addr + size > dump_buf);
1030 +}
1031 +
1032 +int dump_allow_compress(struct page *page, unsigned long size)
1033 +{
1034 +       /*
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)
1038 +        */
1039 +       return !is_curr_stack_page(page, size) && !is_dump_page(page, size);
1040 +}
1041 +
1042 +void lcrash_init_pageheader(struct __dump_page *dp, struct page *page, 
1043 +       unsigned long sz)
1044 +{
1045 +       memset(dp, sizeof(struct __dump_page), 0);
1046 +       dp->dp_flags = 0; 
1047 +       dp->dp_size = 0;
1048 +       if (sz > 0)
1049 +               dp->dp_address = page_to_pfn(page) << PAGE_SHIFT;
1050 +
1051 +#if DUMP_DEBUG > 6
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 */
1056 +}
1057 +
1058 +int dump_lcrash_add_data(unsigned long loc, unsigned long len)
1059 +{
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; 
1063 +       int bytes, size;
1064 +
1065 +       if (buf > dump_config.dumper->dump_buf + DUMP_BUFFER_SIZE)
1066 +               return -ENOMEM;
1067 +
1068 +       lcrash_init_pageheader(dp, page, len);
1069 +       buf += sizeof(struct __dump_page);
1070 +
1071 +       while (len) {
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);
1077 +               }
1078 +               /* set the compressed flag if the page did compress */
1079 +               if (size && (size < bytes)) {
1080 +                       dp->dp_flags |= DUMP_DH_COMPRESSED;
1081 +               } else {
1082 +                       /* compression failed -- default to raw mode */
1083 +                       dp->dp_flags |= DUMP_DH_RAW;
1084 +                       memcpy(buf, addr, bytes);
1085 +                       size = bytes;
1086 +               }
1087 +               /* memset(buf, 'A', size); temporary: testing only !! */
1088 +               kunmap_atomic(addr, KM_DUMP);
1089 +               dp->dp_size += size;
1090 +               buf += size;
1091 +               len -= bytes;
1092 +               page++;
1093 +       }
1094 +
1095 +       /* now update the header */
1096 +#if DUMP_DEBUG > 6
1097 +       dump_header.dh_num_bytes += dp->dp_size + sizeof(*dp);
1098 +#endif
1099 +       dump_header.dh_num_dump_pages++;
1100 +       dump_config.dumper->header_dirty++;
1101 +
1102 +       dump_config.dumper->curr_buf = buf;     
1103 +
1104 +       return len;
1105 +}
1106 +
1107 +int dump_lcrash_update_end_marker(void)
1108 +{
1109 +       struct __dump_page *dp = 
1110 +               (struct __dump_page *)dump_config.dumper->curr_buf;
1111 +       unsigned long left;
1112 +       int ret = 0;
1113 +               
1114 +       lcrash_init_pageheader(dp, NULL, 0);
1115 +       dp->dp_flags |= DUMP_DH_END; /* tbd: truncation test ? */
1116 +       
1117 +       /* now update the header */
1118 +#if DUMP_DEBUG > 6
1119 +       dump_header.dh_num_bytes += sizeof(*dp);
1120 +#endif
1121 +       dump_config.dumper->curr_buf += sizeof(*dp);
1122 +       left = dump_config.dumper->curr_buf - dump_config.dumper->dump_buf;
1123 +
1124 +       printk("\n");
1125 +
1126 +       while (left) {
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);
1130 +                       return ret;
1131 +               }
1132 +
1133 +               if (DUMP_BUFFER_SIZE > left) 
1134 +                       memset(dump_config.dumper->curr_buf, 'm', 
1135 +                               DUMP_BUFFER_SIZE - left);
1136 +
1137 +               if ((ret = dump_ll_write(dump_config.dumper->dump_buf, 
1138 +                       DUMP_BUFFER_SIZE)) < DUMP_BUFFER_SIZE) {
1139 +                       return (ret < 0) ? ret : -ENOSPC;
1140 +               }
1141 +
1142 +               dump_config.dumper->curr_offset += DUMP_BUFFER_SIZE;
1143 +       
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;
1149 +               } else {
1150 +                       left = 0;
1151 +               }
1152 +       }
1153 +       return 0;
1154 +}
1155 +
1156 +
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
1164 +};
1165 +
1166 +struct dump_fmt dump_fmt_lcrash = {
1167 +       .name   = "lcrash",
1168 +       .ops    = &dump_fmt_lcrash_ops
1169 +};
1170 +
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
1175 @@ -0,0 +1,118 @@
1176 +/*
1177 + * GZIP Compression functions for kernel crash dumps.
1178 + *
1179 + * Created by: Matt Robinson (yakker@sourceforge.net)
1180 + * Copyright 2001 Matt D. Robinson.  All rights reserved.
1181 + *
1182 + * This code is released under version 2 of the GNU GPL.
1183 + */
1184 +
1185 +/* header files */
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>
1196 +
1197 +static void *deflate_workspace;
1198 +
1199 +/*
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).
1203 + */
1204 +static u16
1205 +dump_compress_gzip(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
1206 +{
1207 +       /* error code and dump stream */
1208 +       int err;
1209 +       z_stream dump_stream;
1210 +       
1211 +       dump_stream.workspace = deflate_workspace;
1212 +       
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);
1217 +               return 0;
1218 +       }
1219 +
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;
1223 +
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;
1227 +
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",
1234 +                       err);
1235 +               return 0;
1236 +       }
1237 +
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);
1242 +       }
1243 +
1244 +       /* return the compressed byte total (if it's smaller) */
1245 +       if (dump_stream.total_out >= oldsize) {
1246 +               return oldsize;
1247 +       }
1248 +       return dump_stream.total_out;
1249 +}
1250 +
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",
1256 +};
1257 +
1258 +/*
1259 + * Name: dump_compress_gzip_init()
1260 + * Func: Initialize gzip as a compression mechanism.
1261 + */
1262 +static int __init
1263 +dump_compress_gzip_init(void)
1264 +{
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());
1270 +               return -ENOMEM;
1271 +       }
1272 +       dump_register_compression(&dump_gzip_compression);
1273 +       return 0;
1274 +}
1275 +
1276 +/*
1277 + * Name: dump_compress_gzip_cleanup()
1278 + * Func: Remove gzip as a compression mechanism.
1279 + */
1280 +static void __exit
1281 +dump_compress_gzip_cleanup(void)
1282 +{
1283 +       vfree(deflate_workspace);
1284 +       dump_unregister_compression(DUMP_COMPRESS_GZIP);
1285 +}
1286 +
1287 +/* module initialization */
1288 +module_init(dump_compress_gzip_init);
1289 +module_exit(dump_compress_gzip_cleanup);
1290 +
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
1298 @@ -0,0 +1,329 @@
1299 +/*
1300 + * Architecture specific (i386) functions for Linux crash dumps.
1301 + *
1302 + * Created by: Matt Robinson (yakker@sgi.com)
1303 + *
1304 + * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
1305 + *
1306 + * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com)
1307 + * Copyright 2000 TurboLinux, Inc.  All rights reserved.
1308 + * 
1309 + * This code is released under version 2 of the GNU GPL.
1310 + */
1311 +
1312 +/*
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.
1316 + */
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>
1327 +
1328 +#include <asm/processor.h>
1329 +#include <asm/e820.h>
1330 +#include <asm/hardirq.h>
1331 +#include <asm/nmi.h>
1332 +
1333 +static __s32        saved_irq_count;   /* saved preempt_count() flags */
1334 +
1335 +static int
1336 +alloc_dha_stack(void)
1337 +{
1338 +       int i;
1339 +       void *ptr;
1340 +       
1341 +       if (dump_header_asm.dha_stack[0])
1342 +               return 0;
1343 +
1344 +       ptr = vmalloc(THREAD_SIZE * num_online_cpus());
1345 +       if (!ptr) {
1346 +               printk("vmalloc for dha_stacks failed\n");
1347 +               return -ENOMEM;
1348 +       }
1349 +
1350 +       for (i = 0; i < num_online_cpus(); i++) {
1351 +               dump_header_asm.dha_stack[i] = (u32)((unsigned long)ptr +
1352 +                               (i * THREAD_SIZE));
1353 +       }
1354 +       return 0;
1355 +}
1356 +
1357 +static int
1358 +free_dha_stack(void) 
1359 +{
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;
1363 +       }
1364 +       return 0;
1365 +}
1366 +
1367 +
1368 +void 
1369 +__dump_save_regs(struct pt_regs *dest_regs, const struct pt_regs *regs)
1370 +{
1371 +       *dest_regs = *regs;
1372 +
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.
1380 +        */
1381 +       if (!user_mode(regs)) {
1382 +               if ((0xffff & regs->xss) == __KERNEL_DS) 
1383 +                       /* already fixed up */
1384 +                       return;
1385 +               dest_regs->esp = (unsigned long)&(regs->esp);
1386 +               __asm__ __volatile__ ("movw %%ss, %%ax;"
1387 +                       :"=a"(dest_regs->xss));
1388 +       }
1389 +}
1390 +
1391 +
1392 +#ifdef CONFIG_SMP
1393 +extern cpumask_t irq_affinity[];
1394 +extern irq_desc_t irq_desc[];
1395 +extern void dump_send_ipi(void);
1396 +
1397 +static int dump_expect_ipi[NR_CPUS];
1398 +static atomic_t waiting_for_dump_ipi;
1399 +static cpumask_t saved_affinity[NR_IRQS];
1400 +
1401 +extern void stop_this_cpu(void *); /* exported by i386 kernel */
1402 +
1403 +static int
1404 +dump_nmi_callback(struct pt_regs *regs, int cpu) 
1405 +{
1406 +       if (!dump_expect_ipi[cpu])
1407 +               return 0;
1408 +
1409 +       dump_expect_ipi[cpu] = 0;
1410 +       
1411 +       dump_save_this_cpu(regs);
1412 +       atomic_dec(&waiting_for_dump_ipi);
1413 +
1414 + level_changed:
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;
1421 +
1422 +                       cpu_relax();    /* kill time nicely */
1423 +               }
1424 +               break;
1425 +
1426 +       case DUMP_HALT_CPUS:            /* Execute halt */
1427 +               stop_this_cpu(NULL);
1428 +               break;
1429 +               
1430 +       case DUMP_SOFT_SPIN_CPUS:
1431 +               /* Mark the task so it spins in schedule */
1432 +               set_tsk_thread_flag(current, TIF_NEED_RESCHED);
1433 +               break;
1434 +       }
1435 +
1436 +       return 1;
1437 +}
1438 +
1439 +/* save registers on other processors */
1440 +void 
1441 +__dump_save_other_cpus(void)
1442 +{
1443 +       int i, cpu = smp_processor_id();
1444 +       int other_cpus = num_online_cpus()-1;
1445 +       
1446 +       if (other_cpus > 0) {
1447 +               atomic_set(&waiting_for_dump_ipi, other_cpus);
1448 +
1449 +               for (i = 0; i < NR_CPUS; i++) {
1450 +                       dump_expect_ipi[i] = (i != cpu && cpu_online(i));
1451 +               }
1452 +
1453 +               /* short circuit normal NMI handling temporarily */
1454 +               set_nmi_callback(dump_nmi_callback);
1455 +               wmb();
1456 +
1457 +               dump_send_ipi();
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 
1462 +                  other cpus. */
1463 +               while(atomic_read(&waiting_for_dump_ipi) > 0) {
1464 +                       cpu_relax();
1465 +               }
1466 +
1467 +               unset_nmi_callback();
1468 +       }
1469 +}
1470 +
1471 +/*
1472 + * Routine to save the old irq affinities and change affinities of all irqs to
1473 + * the dumping cpu.
1474 + */
1475 +static void 
1476 +set_irq_affinity(void)
1477 +{
1478 +       int i;
1479 +       int cpu = smp_processor_id();
1480 +
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)
1484 +                       continue;
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]);
1488 +       }
1489 +}
1490 +
1491 +/*
1492 + * Restore old irq affinities.
1493 + */
1494 +static void 
1495 +reset_irq_affinity(void)
1496 +{
1497 +       int i;
1498 +
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)
1502 +                       continue;
1503 +               if (irq_desc[i].handler->set_affinity != NULL)
1504 +                       irq_desc[i].handler->set_affinity(i, saved_affinity[i]);
1505 +       }
1506 +}
1507 +
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 */
1513 +
1514 +/* 
1515 + * Kludge - dump from interrupt context is unreliable (Fixme)
1516 + *
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.
1520 + *
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 
1525 + * code. 
1526 + */
1527 +static inline void
1528 +irq_bh_save(void)
1529 +{
1530 +       saved_irq_count = irq_count();
1531 +       preempt_count() &= ~(HARDIRQ_MASK|SOFTIRQ_MASK);
1532 +}
1533 +
1534 +static inline void
1535 +irq_bh_restore(void)
1536 +{
1537 +       preempt_count() |= saved_irq_count;
1538 +}
1539 +
1540 +/*
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.
1546 + *
1547 + *     Change irq affinities
1548 + *     Re-enable interrupts
1549 + */
1550 +void 
1551 +__dump_irq_enable(void)
1552 +{
1553 +       set_irq_affinity();
1554 +       irq_bh_save();
1555 +       local_irq_enable();
1556 +}
1557 +
1558 +/*
1559 + * Name: __dump_irq_restore
1560 + * Func: Resume the system state in an architecture-specific way.
1561 +
1562 + */
1563 +void 
1564 +__dump_irq_restore(void)
1565 +{
1566 +       local_irq_disable();
1567 +       reset_irq_affinity();
1568 +       irq_bh_restore();
1569 +}
1570 +
1571 +/*
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.
1575 + */
1576 +int
1577 +__dump_configure_header(const struct pt_regs *regs)
1578 +{
1579 +       return (0);
1580 +}
1581 +
1582 +/*
1583 + * Name: __dump_init()
1584 + * Func: Initialize the dumping routine process.
1585 + */
1586 +void
1587 +__dump_init(uint64_t local_memory_start)
1588 +{
1589 +       return;
1590 +}
1591 +
1592 +/*
1593 + * Name: __dump_open()
1594 + * Func: Open the dump device (architecture specific).
1595 + */
1596 +void
1597 +__dump_open(void)
1598 +{
1599 +       alloc_dha_stack();
1600 +}
1601 +
1602 +/*
1603 + * Name: __dump_cleanup()
1604 + * Func: Free any architecture specific data structures. This is called
1605 + *       when the dump module is being removed.
1606 + */
1607 +void
1608 +__dump_cleanup(void)
1609 +{
1610 +       free_dha_stack();
1611 +}
1612 +
1613 +extern int pfn_is_ram(unsigned long);
1614 +
1615 +/*
1616 + * Name: __dump_page_valid()
1617 + * Func: Check if page is valid to dump.
1618 + */ 
1619 +int 
1620 +__dump_page_valid(unsigned long index)
1621 +{
1622 +       if (!pfn_valid(index))
1623 +               return 0;
1624 +
1625 +       return pfn_is_ram(index);
1626 +}
1627 +
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
1632 @@ -0,0 +1,640 @@
1633 +/*
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.
1637 + *
1638 + * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
1639 + *
1640 + * Copyright (C) 2002 International Business Machines Corp. 
1641 + *
1642 + * This code is released under version 2 of the GNU GPL.
1643 + *
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. 
1647 + *
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>
1654 + *
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)
1666 + *
1667 + */
1668 +
1669 +/*
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.
1676 + *
1677 + * root
1678 + *  |    ---------    --------        --------
1679 + *  -->  | .  . +|--->|  .  +|------->| . .  |       indirect 
1680 + *       --|--|---    ---|----        --|-|---      maps
1681 + *         |  |          |                     | |     
1682 + *    ------  ------   -------     ------ -------
1683 + *    | .  |  | .  |   | .  . |    | .  | |  . . |   maps 
1684 + *    --|---  --|---   --|--|--    --|--- ---|-|--
1685 + *     page    page    page page   page   page page  data
1686 + *                                                   pages
1687 + *
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)
1696 + */
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"
1702 +
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 */
1706 +
1707 +extern int dump_low_page(struct page *);
1708 +
1709 +/* check if the next entry crosses a page boundary */
1710 +static inline int is_last_map_entry(unsigned long *map)
1711 +{
1712 +       unsigned long addr = (unsigned long)(map + 1);
1713 +
1714 +       return (!(addr & (PAGE_SIZE - 1)));
1715 +}
1716 +
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)
1721 +{
1722 +       return (unsigned long *)map[DUMP_IND_MAP_SZ];
1723 +}
1724 +
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)
1728 +{
1729 +       unsigned long *map1, *map2;
1730 +       loff_t off = 0, last = dev->last_used_offset >> PAGE_SHIFT;
1731 +       int i, j;
1732 +       
1733 +       printk("Reserve bootmap space holding previous dump of %lld pages\n",
1734 +                       last);
1735 +       map1= (unsigned long *)dev->indirect_map_root;
1736 +
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)
1743 +                               continue;
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, 
1749 +                                       map2[j]);
1750 +                               if (map2[j] < max_low_pfn) {
1751 +                                       reserve_bootmem(map2[j] << PAGE_SHIFT,
1752 +                                               PAGE_SIZE);
1753 +                               }
1754 +                       }
1755 +               }
1756 +               map1 = next_indirect_map(map1);
1757 +       }
1758 +       dev->nr_free = 0; /* these pages don't belong to this boot */
1759 +}
1760 +#endif
1761 +
1762 +/* mark dump pages so that they aren't used by this kernel */
1763 +void dump_mark_map(struct dump_memdev *dev)
1764 +{
1765 +       unsigned long *map1, *map2;
1766 +       loff_t off = 0, last = dev->last_used_offset >> PAGE_SHIFT;
1767 +       struct page *page;
1768 +       int i, j;
1769 +       
1770 +       printk("Dump: marking pages in use by previous dump\n");
1771 +       map1= (unsigned long *)dev->indirect_map_root;
1772 +
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, 
1785 +                                       map2[j]);
1786 +                               page = pfn_to_page(map2[j]);
1787 +                               set_page_count(page, 1);
1788 +                       }
1789 +               }
1790 +               map1 = next_indirect_map(map1);
1791 +       }
1792 +}
1793 +       
1794 +
1795 +/* 
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)
1800 + */
1801 +struct page *dump_mem_lookup(struct dump_memdev *dump_mdev, unsigned long loc)
1802 +{
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;
1807 +
1808 +       map = (unsigned long *)dump_mdev->indirect_map_root;
1809 +       if (!map)
1810 +               return NULL;
1811 +
1812 +       if (loc > dump_mdev->last_offset >> PAGE_SHIFT)
1813 +               return NULL;
1814 +
1815 +       /* 
1816 +        * first locate the right indirect map 
1817 +        * in the chain of indirect maps 
1818 +        */
1819 +       for (i = 0; i + DUMP_IND_MAP_SZ < index ; i += DUMP_IND_MAP_SZ) {
1820 +               if (!(map = next_indirect_map(map)))
1821 +                       return NULL;
1822 +       }
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];
1830 +       }
1831 +
1832 +       if (page)
1833 +               map = kmap_atomic(page, KM_DUMP);
1834 +       else 
1835 +               return NULL;
1836 +
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;
1845 +       } else {
1846 +               page = NULL;
1847 +       }
1848 +       kunmap_atomic(map, KM_DUMP);
1849 +
1850 +       return page;
1851 +}
1852 +                       
1853 +/* 
1854 + * Retrieves a pointer to the next page in the dump device 
1855 + * Used during the lookup pass post-soft-reboot 
1856 + */
1857 +struct page *dump_mem_next_page(struct dump_memdev *dev)
1858 +{
1859 +       unsigned long i; 
1860 +       unsigned long *map;     
1861 +       struct page *page = NULL;
1862 +
1863 +       if (dev->ddev.curr_offset + PAGE_SIZE >= dev->last_offset) {
1864 +               return NULL;
1865 +       }
1866 +
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)
1874 +                               return NULL;
1875 +               }
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);
1879 +
1880 +       };
1881 +       
1882 +       if (*dev->curr_map) {
1883 +               map = kmap_atomic(pfn_to_page(*dev->curr_map), KM_DUMP);
1884 +               if (map[i])
1885 +                       page = pfn_to_page(map[i]);
1886 +               kunmap_atomic(map, KM_DUMP);
1887 +               dev->ddev.curr_offset += PAGE_SIZE;
1888 +       };
1889 +
1890 +       return page;
1891 +}
1892 +
1893 +/* Copied from dump_filters.c */
1894 +static inline int kernel_page(struct page *p)
1895 +{
1896 +       /* FIXME: Need to exclude hugetlb pages. Clue: reserved but inuse */
1897 +       return PageReserved(p) || (!PageLRU(p) && PageInuse(p));
1898 +}
1899 +
1900 +static inline int user_page(struct page *p)
1901 +{
1902 +       return PageInuse(p) && (!PageReserved(p) && PageLRU(p));
1903 +}
1904 +
1905 +int dump_reused_by_boot(struct page *page)
1906 +{
1907 +       /* Todo
1908 +        * Checks:
1909 +        * if PageReserved 
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.
1915 +        */
1916 +
1917 +       /* Temporary proof of concept hack, avoid overwriting kern pages */
1918 +
1919 +       return (kernel_page(page) || dump_low_page(page) || user_page(page));
1920 +}
1921 +
1922 +
1923 +/* Uses the free page passed in to expand available space */
1924 +int dump_mem_add_space(struct dump_memdev *dev, struct page *page)
1925 +{
1926 +       struct page *map_page;
1927 +       unsigned long *map;     
1928 +       unsigned long i; 
1929 +
1930 +       if (!dev->curr_map)
1931 +               return -ENOMEM; /* must've exhausted indirect map */
1932 +
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;
1937 +               return 0;
1938 +       }
1939 +
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;
1955 +               }
1956 +       }               
1957 +       return 0;
1958 +}
1959 +
1960 +
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)
1963 +{
1964 +       int err = 0;
1965 +
1966 +       /* 
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.
1970 +        */
1971 +       if (dump_reused_by_boot(page))
1972 +               return 0;
1973 +
1974 +       if ((err = dump_mem_add_space(dev, page))) {
1975 +               printk("Warning: Unable to extend memdev space. Err %d\n",
1976 +               err);
1977 +               return 0;
1978 +       }
1979 +
1980 +       dev->nr_free++;
1981 +       return 1;
1982 +}
1983 +
1984 +
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)
1988 +{
1989 +       struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
1990 +       unsigned long nr_maps, *map, *prev_map = &dump_mdev->indirect_map_root;
1991 +       void *addr;
1992 +       struct page *page;
1993 +       unsigned long i = 0;
1994 +       int err = 0;
1995 +
1996 +       /* Todo: sanity check for unwritten previous dump */
1997 +
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);
2004 +                       return -ENOMEM;
2005 +               }
2006 +               clear_page(map);
2007 +               *prev_map = (unsigned long)map;
2008 +               prev_map = &map[DUMP_IND_MAP_SZ];
2009 +       };
2010 +               
2011 +       dump_mdev->curr_map = (unsigned long *)dump_mdev->indirect_map_root;
2012 +       dump_mdev->curr_map_offset = 0; 
2013 +
2014 +       /* 
2015 +        * allocate a few bootstrap pages: at least 1 map and 1 data page
2016 +        * plus enough to save the dump header
2017 +        */
2018 +       i = 0;
2019 +       do {
2020 +               if (!(addr = dump_alloc_mem(PAGE_SIZE))) {
2021 +                       printk("Unable to alloc bootstrap page %ld\n", i);
2022 +                       return -ENOMEM;
2023 +               }
2024 +
2025 +               page = virt_to_page(addr);
2026 +               if (dump_low_page(page)) {
2027 +                       dump_free_mem(addr);
2028 +                       continue;
2029 +               }
2030 +
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);
2035 +                       continue;
2036 +               }
2037 +               i++;
2038 +       } while (i < DUMP_NR_BOOTSTRAP);
2039 +
2040 +       printk("dump memdev init: %ld maps, %ld bootstrap pgs, %ld free pgs\n",
2041 +               nr_maps, i, dump_mdev->last_offset >> PAGE_SHIFT);
2042 +       
2043 +       dump_mdev->last_bs_offset = dump_mdev->last_offset;
2044 +
2045 +       return 0;
2046 +}
2047 +
2048 +/* Releases all pre-alloc'd pages */
2049 +int dump_mem_release(struct dump_dev *dev)
2050 +{
2051 +       struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
2052 +       struct page *page, *map_page;
2053 +       unsigned long *map, *prev_map;
2054 +       void *addr;
2055 +       int i;
2056 +
2057 +       if (!dump_mdev->nr_free)
2058 +               return 0;
2059 +
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))
2064 +                       break;
2065 +               addr = page_address(page);
2066 +               if (!addr) {
2067 +                       printk("page_address(%p) = NULL\n", page);
2068 +                       break;
2069 +               }
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))
2075 +                               break;
2076 +                       page = dump_mem_next_page(dump_mdev);
2077 +                       addr = page_address(map_page);
2078 +                       if (!addr) {
2079 +                               printk("page_address(%p) = NULL\n", 
2080 +                                       map_page);
2081 +                               break;
2082 +                       }
2083 +                       pr_debug("Freeing map page at 0x%lx\n", addr);
2084 +                       dump_free_mem(addr);
2085 +                       i++;
2086 +               } else {
2087 +                       page = dump_mem_next_page(dump_mdev);
2088 +               }
2089 +       }
2090 +
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);
2096 +                       if (!addr) {
2097 +                               printk("page_address(%p) = NULL\n", map_page);
2098 +                       } else {
2099 +                               pr_debug("Freeing map page at 0x%lx\n", addr);
2100 +                               dump_free_mem(addr);
2101 +                               i++;
2102 +                       }
2103 +               }
2104 +       }
2105 +
2106 +       printk("Freed %d bootstrap pages\n", i);
2107 +
2108 +       /* free the indirect maps */
2109 +       map = (unsigned long *)dump_mdev->indirect_map_root;
2110 +
2111 +       i = 0;
2112 +       while (map) {
2113 +               prev_map = map;
2114 +               map = next_indirect_map(map);
2115 +               dump_free_mem(prev_map);
2116 +               i++;
2117 +       }
2118 +
2119 +       printk("Freed %d indirect map(s)\n", i);
2120 +
2121 +       /* Reset the indirect map */
2122 +       dump_mdev->indirect_map_root = 0;
2123 +       dump_mdev->curr_map = 0;
2124 +
2125 +       /* Reset the free list */
2126 +       dump_mdev->nr_free = 0;
2127 +
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;
2132 +       return 0;
2133 +}
2134 +
2135 +/*
2136 + * Long term:
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.
2142 + *
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.
2147 + */
2148 +/* 
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
2154 + */
2155 +int dump_mem_silence(struct dump_dev *dev)
2156 +{
2157 +       struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
2158 +
2159 +       if (dump_mdev->last_offset > dump_mdev->last_bs_offset) {
2160 +               /* prefer to run lkcd config & start with a clean slate */
2161 +               return -EEXIST;
2162 +       }
2163 +       return 0;
2164 +}
2165 +
2166 +extern int dump_overlay_resume(void);
2167 +
2168 +/* Trigger the next stage of dumping */
2169 +int dump_mem_resume(struct dump_dev *dev)
2170 +{
2171 +       dump_overlay_resume(); 
2172 +       return 0;
2173 +}
2174 +
2175 +/* 
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
2181 + */
2182 +int dump_mem_write(struct dump_dev *dev, void *buf, unsigned long len)
2183 +{
2184 +       struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
2185 +       struct page *page;
2186 +       unsigned long n = 0;
2187 +       void *addr;
2188 +       unsigned long *saved_curr_map, saved_map_offset;
2189 +       int ret = 0;
2190 +
2191 +       pr_debug("dump_mem_write: offset 0x%llx, size %ld\n", 
2192 +               dev->curr_offset, len);
2193 +
2194 +       if (dev->curr_offset + len > dump_mdev->last_offset)  {
2195 +               printk("Out of space to write\n");
2196 +               return -ENOSPC;
2197 +       }
2198 +       
2199 +       if ((len & (PAGE_SIZE - 1)) || (dev->curr_offset & (PAGE_SIZE - 1)))
2200 +               return -EINVAL; /* not aligned in units of page size */
2201 +
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);
2205 +
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);
2213 +       }
2214 +
2215 +       dump_mdev->curr_map = saved_curr_map;
2216 +       dump_mdev->curr_map_offset = saved_map_offset;
2217 +
2218 +       if (dump_mdev->last_used_offset < dev->curr_offset)
2219 +               dump_mdev->last_used_offset = dev->curr_offset;
2220 +
2221 +       return (len - n) ? (len - n) : ret ;
2222 +}
2223 +
2224 +/* dummy - always ready */
2225 +int dump_mem_ready(struct dump_dev *dev, void *buf)
2226 +{
2227 +       return 0;
2228 +}
2229 +
2230 +/* 
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 
2234 + */
2235 +int dump_mem_seek(struct dump_dev *dev, loff_t offset)
2236 +{
2237 +       struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
2238 +
2239 +       if (offset & (PAGE_SIZE - 1))
2240 +               return -EINVAL; /* allow page size units only for now */
2241 +       
2242 +       /* Are we exceeding available space ? */
2243 +       if (offset > dump_mdev->last_offset) {
2244 +               printk("dump_mem_seek failed for offset 0x%llx\n",
2245 +                       offset);
2246 +               return -ENOSPC; 
2247 +       }
2248 +
2249 +       dump_mdev->ddev.curr_offset = offset;
2250 +       return 0;
2251 +}
2252 +
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
2262 +};
2263 +
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 */
2268 +};     
2269 +       
2270 +/* may be overwritten if a previous dump exists */
2271 +struct dump_memdev *dump_memdev = &default_dump_memdev;
2272 +
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
2277 @@ -0,0 +1,880 @@
2278 +/*
2279 + * Implements the dump driver interface for saving a dump via network
2280 + * interface. 
2281 + *
2282 + * Some of this code has been taken/adapted from Ingo Molnar's netconsole
2283 + * code. LKCD team expresses its thanks to Ingo.
2284 + *
2285 + * Started: June 2002 - Mohamed Abbas <mohamed.abbas@intel.com>
2286 + *     Adapted netconsole code to implement LKCD dump over the network.
2287 + *
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.
2291 + *
2292 + * Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
2293 + * Copyright (C) 2002 International Business Machines Corp. 
2294 + *
2295 + *  This code is released under version 2 of the GNU GPL.
2296 + */
2297 +
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>
2306 +
2307 +#include <asm/unaligned.h>
2308 +
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];
2322 +
2323 +/*
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.
2328 + */
2329 +static u64 dump_magic;
2330 +
2331 +#define MAX_UDP_CHUNK 1460
2332 +#define MAX_PRINT_CHUNK (MAX_UDP_CHUNK-HEADER_LEN)
2333 +
2334 +/*
2335 + * We maintain a small pool of fully-sized skbs,
2336 + * to make sure the message gets out even in
2337 + * extreme OOM situations.
2338 + */
2339 +#define DUMP_MAX_SKBS 32
2340 +
2341 +#define MAX_SKB_SIZE \
2342 +               (MAX_UDP_CHUNK + sizeof(struct udphdr) + \
2343 +                               sizeof(struct iphdr) + sizeof(struct ethhdr))
2344 +
2345 +static void
2346 +dump_refill_skbs(void)
2347 +{
2348 +       struct sk_buff *skb;
2349 +       unsigned long flags;
2350 +
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);
2354 +               if (!skb)
2355 +                       break;
2356 +               if (dump_skb)
2357 +                       skb->next = dump_skb;
2358 +               else
2359 +                       skb->next = NULL;
2360 +               dump_skb = skb;
2361 +               dump_nr_skbs++;
2362 +       }
2363 +       spin_unlock_irqrestore(&dump_skb_lock, flags);
2364 +}
2365 +
2366 +static struct
2367 +sk_buff * dump_get_skb(void)
2368 +{
2369 +       struct sk_buff *skb;
2370 +       unsigned long flags;
2371 +
2372 +       spin_lock_irqsave(&dump_skb_lock, flags);
2373 +       skb = dump_skb;
2374 +       if (skb) {
2375 +               dump_skb = skb->next;
2376 +               skb->next = NULL;
2377 +               dump_nr_skbs--;
2378 +       }
2379 +       spin_unlock_irqrestore(&dump_skb_lock, flags);
2380 +        
2381 +       return skb;
2382 +}
2383 +
2384 +/*
2385 + * Zap completed output skbs.
2386 + */
2387 +static void
2388 +zap_completion_queue(void)
2389 +{
2390 +       int count;
2391 +       unsigned long flags;
2392 +       int cpu = smp_processor_id();
2393 +       struct softnet_data *softnet_data;
2394 +               
2395 +
2396 +       softnet_data = &__get_cpu_var(softnet_data);
2397 +       count=0;
2398 +       if (softnet_data[cpu].completion_queue) {
2399 +               struct sk_buff *clist;
2400 +       
2401 +               local_irq_save(flags);
2402 +               clist = softnet_data[cpu].completion_queue;
2403 +               softnet_data[cpu].completion_queue = NULL;
2404 +               local_irq_restore(flags);
2405 +
2406 +               while (clist != NULL) {
2407 +                       struct sk_buff *skb = clist;
2408 +                       clist = clist->next;
2409 +                       __kfree_skb(skb);
2410 +                       count++;
2411 +                       if (count > 10000)
2412 +                               printk("Error in sk list\n");
2413 +               }
2414 +       }
2415 +}
2416 +
2417 +static void
2418 +dump_send_skb(struct net_device *dev, const char *msg, unsigned int msg_len,
2419 +               reply_t *reply)
2420 +{
2421 +       int once = 1;
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; 
2427 +
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;
2431 +
2432 +repeat_loop:
2433 +       zap_completion_queue();
2434 +       if (dump_nr_skbs < DUMP_MAX_SKBS)
2435 +               dump_refill_skbs();
2436 +
2437 +       skb = alloc_skb(total_len, GFP_ATOMIC);
2438 +       if (!skb) {
2439 +               skb = dump_get_skb();
2440 +               if (!skb) {
2441 +                       count++;
2442 +                       if (once && (count == 1000000)) {
2443 +                               printk("possibly FATAL: out of netconsole "
2444 +                                       "skbs!!! will keep retrying.\n");
2445 +                               once = 0;
2446 +                       }
2447 +                       dev->poll_controller(dev);
2448 +                       goto repeat_loop;
2449 +               }
2450 +       }
2451 +
2452 +       atomic_set(&skb->users, 1);
2453 +       skb_reserve(skb, total_len - msg_len - HEADER_LEN);
2454 +       skb->data[0] = NETCONSOLE_VERSION;
2455 +
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));
2459 +
2460 +       memcpy(skb->data + HEADER_LEN, msg, msg_len);
2461 +       skb->len += msg_len + HEADER_LEN;
2462 +
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);
2467 +       udph->check = 0;
2468 +
2469 +       iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
2470 +
2471 +       iph->version  = 4;
2472 +       iph->ihl      = 5;
2473 +       iph->tos      = 0;
2474 +       iph->tot_len  = htons(ip_len);
2475 +       iph->id       = 0;
2476 +       iph->frag_off = 0;
2477 +       iph->ttl      = 64;
2478 +       iph->protocol = IPPROTO_UDP;
2479 +       iph->check    = 0;
2480 +       iph->saddr    = source_ip;
2481 +       iph->daddr    = target_ip;
2482 +       iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
2483 +
2484 +       eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
2485 +
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);
2489 +
2490 +       count=0;
2491 +repeat_poll:
2492 +       spin_lock(&dev->xmit_lock);
2493 +       dev->xmit_lock_owner = smp_processor_id();
2494 +
2495 +       count++;
2496 +
2497 +
2498 +       if (netif_queue_stopped(dev)) {
2499 +               dev->xmit_lock_owner = -1;
2500 +               spin_unlock(&dev->xmit_lock);
2501 +
2502 +               dev->poll_controller(dev);
2503 +               zap_completion_queue();
2504 +
2505 +
2506 +               goto repeat_poll;
2507 +       }
2508 +
2509 +       dev->hard_start_xmit(skb, dev);
2510 +
2511 +       dev->xmit_lock_owner = -1;
2512 +       spin_unlock(&dev->xmit_lock);
2513 +}
2514 +
2515 +static unsigned short
2516 +udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr,
2517 +               unsigned long base)
2518 +{
2519 +       return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base);
2520 +}
2521 +
2522 +static int
2523 +udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
2524 +                            unsigned short ulen, u32 saddr, u32 daddr)
2525 +{
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))
2531 +                       return 0;
2532 +               skb->ip_summed = CHECKSUM_NONE;
2533 +       }
2534 +       if (skb->ip_summed != CHECKSUM_UNNECESSARY)
2535 +               skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen,
2536 +                               IPPROTO_UDP, 0);
2537 +       /* Probably, we should checksum udp header (it should be in cache
2538 +        * in any case) and data in tiny packets (< rx copybreak).
2539 +        */
2540 +       return 0;
2541 +}
2542 +
2543 +static __inline__ int
2544 +__udp_checksum_complete(struct sk_buff *skb)
2545 +{
2546 +       return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len,
2547 +                               skb->csum));
2548 +}
2549 +
2550 +static __inline__
2551 +int udp_checksum_complete(struct sk_buff *skb)
2552 +{
2553 +       return skb->ip_summed != CHECKSUM_UNNECESSARY &&
2554 +               __udp_checksum_complete(skb);
2555 +}
2556 +
2557 +int new_req = 0;
2558 +static req_t req;
2559 +
2560 +static int
2561 +dump_rx_hook(struct sk_buff *skb)
2562 +{
2563 +       int proto;
2564 +       struct iphdr *iph;
2565 +       struct udphdr *uh;
2566 +       __u32 len, saddr, daddr, ulen;
2567 +       req_t *__req;
2568 +
2569 +       /* 
2570 +        * First check if were are dumping or doing startup handshake, if
2571 +        * not quickly return.
2572 +        */
2573 +       if (!netdump_in_progress)
2574 +               return NET_RX_SUCCESS;
2575 +
2576 +       if (skb->dev->type != ARPHRD_ETHER)
2577 +               goto out;
2578 +
2579 +       proto = ntohs(skb->mac.ethernet->h_proto);
2580 +       if (proto != ETH_P_IP)
2581 +               goto out;
2582 +
2583 +       if (skb->pkt_type == PACKET_OTHERHOST)
2584 +               goto out;
2585 +
2586 +       if (skb_shared(skb))
2587 +               goto out;
2588 +
2589 +        /* IP header correctness testing: */
2590 +       iph = (struct iphdr *)skb->data;
2591 +       if (!pskb_may_pull(skb, sizeof(struct iphdr)))
2592 +               goto out;
2593 +
2594 +       if (iph->ihl < 5 || iph->version != 4)
2595 +               goto out;
2596 +
2597 +       if (!pskb_may_pull(skb, iph->ihl*4))
2598 +               goto out;
2599 +
2600 +       if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
2601 +               goto out;
2602 +
2603 +       len = ntohs(iph->tot_len);
2604 +       if (skb->len < len || len < iph->ihl*4)
2605 +               goto out;
2606 +
2607 +       saddr = iph->saddr;
2608 +       daddr = iph->daddr;
2609 +       if (iph->protocol != IPPROTO_UDP)
2610 +               goto out;
2611 +
2612 +       if (source_ip != daddr)
2613 +               goto out;
2614 +
2615 +       if (target_ip != saddr)
2616 +               goto out;
2617 +
2618 +       len -= iph->ihl*4;
2619 +       uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
2620 +       ulen = ntohs(uh->len);
2621 +
2622 +       if (ulen != len || ulen < (sizeof(*uh) + sizeof(*__req)))
2623 +               goto out;
2624 +
2625 +       if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0)
2626 +               goto out;
2627 +
2628 +       if (udp_checksum_complete(skb))
2629 +               goto out;
2630 +
2631 +       if (source_port != uh->dest)
2632 +               goto out;
2633 +
2634 +       if (target_port != uh->source)
2635 +               goto out;
2636 +
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))
2643 +               goto out;
2644 +
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);
2650 +       new_req = 1;
2651 +out:
2652 +       return NET_RX_DROP;
2653 +}
2654 +
2655 +static void
2656 +dump_send_mem(struct net_device *dev, req_t *req, const char* buff, size_t len)
2657 +{
2658 +       int i;
2659 +
2660 +       int nr_chunks = len/1024;
2661 +       reply_t reply;
2662 +       
2663 +       reply.nr = req->nr;
2664 +       reply.info = 0;
2665 +
2666 +        if ( nr_chunks <= 0)
2667 +                nr_chunks = 1;
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);
2673 +       }
2674 +}
2675 +static void dump_do_sysrq(int key)
2676 +{
2677 +        struct pt_regs regs;
2678 +        
2679 +       get_current_regs(&regs);
2680 +       handle_sysrq(key, &regs, NULL, NULL);
2681 +}
2682 +
2683 +/*
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.
2688 + *
2689 + * (The client can test the success of the handshake via the HELLO
2690 + * command, and send ACKs until we enter netdump mode.)
2691 + */
2692 +static int
2693 +dump_handshake(struct dump_dev *net_dev)
2694 +{
2695 +       char tmp[200];
2696 +       reply_t reply;
2697 +       int i, j;
2698 +
2699 +       if (startup_handshake) {
2700 +               sprintf(tmp, "NETDUMP start, waiting for start-ACK.\n");
2701 +               reply.code = REPLY_START_NETDUMP;
2702 +               reply.nr = 0;
2703 +               reply.info = 0;
2704 +       } else {
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;
2709 +       }
2710 +       
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);
2714 +
2715 +               /* wait 1 sec */
2716 +               for (j = 0; j < 10000; j++) {
2717 +                       udelay(100);
2718 +                       dump_ndev->poll_controller(dump_ndev);
2719 +                       zap_completion_queue();
2720 +                       if (new_req)
2721 +                               break;
2722 +               }
2723 +
2724 +               /* 
2725 +                * if there is no new request, try sending the handshaking
2726 +                * packet again
2727 +                */
2728 +               if (!new_req)
2729 +                       continue;
2730 +
2731 +               /* 
2732 +                * check if the new request is of the expected type,
2733 +                * if so, return, else try sending the handshaking
2734 +                * packet again
2735 +                */
2736 +               if (startup_handshake) {
2737 +                       if (req.command == COMM_HELLO || req.command ==
2738 +                               COMM_START_NETDUMP_ACK) {
2739 +                               return 0;
2740 +                       } else {
2741 +                               new_req = 0;
2742 +                               continue;
2743 +                       }
2744 +               } else {
2745 +                       if (req.command == COMM_SEND_MEM) {
2746 +                               return 0;
2747 +                       } else {
2748 +                               new_req = 0;
2749 +                               continue;
2750 +                       }
2751 +               }
2752 +       }
2753 +       return -1;
2754 +}
2755 +
2756 +static ssize_t
2757 +do_netdump(struct dump_dev *net_dev, const char* buff, size_t len)
2758 +{
2759 +       reply_t reply;
2760 +       char tmp[200];
2761 +       ssize_t  ret = 0;
2762 +       int repeatCounter, counter, total_loop;
2763 +       
2764 +       netdump_in_progress = 1;
2765 +
2766 +       if (dump_handshake(net_dev) < 0) {
2767 +               printk("network dump failed due to handshake failure\n");
2768 +               goto out;
2769 +       }
2770 +
2771 +       /*
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.
2776 +        */
2777 +       if (startup_handshake)
2778 +               startup_handshake = 0;
2779 +
2780 +        counter = 0;
2781 +       repeatCounter = 0;
2782 +       total_loop = 0;
2783 +       while (1) {
2784 +                if (!new_req) {
2785 +                       dump_ndev->poll_controller(dump_ndev);
2786 +                       zap_completion_queue();
2787 +               }
2788 +               if (!new_req) {
2789 +                       repeatCounter++;
2790 +
2791 +                       if (repeatCounter > 5) {
2792 +                               counter++;
2793 +                               if (counter > 10000) {
2794 +                                       if (total_loop >= 100000) {
2795 +                                               printk("Time OUT LEAVE NOW\n");
2796 +                                               goto out;
2797 +                                       } else {
2798 +                                               total_loop++;
2799 +                                               printk("Try number %d out of "
2800 +                                                       "10 before Time Out\n",
2801 +                                                       total_loop);
2802 +                                       }
2803 +                               }
2804 +                               mdelay(1);
2805 +                               repeatCounter = 0;
2806 +                       }       
2807 +                       continue;
2808 +               }
2809 +               repeatCounter = 0;
2810 +               counter = 0;
2811 +               total_loop = 0;
2812 +               new_req = 0;
2813 +               switch (req.command) {
2814 +               case COMM_NONE:
2815 +                       break;
2816 +
2817 +               case COMM_SEND_MEM:
2818 +                       dump_send_mem(dump_ndev, &req, buff, len);
2819 +                       break;
2820 +
2821 +               case COMM_EXIT:
2822 +                case COMM_START_WRITE_NETDUMP_ACK:
2823 +                       ret = len;
2824 +                       goto out;
2825 +
2826 +               case COMM_HELLO:
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);
2833 +                       break;
2834 +
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);
2841 +                       break;
2842 +
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);
2850 +                       break;
2851 +
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);
2858 +                       break;
2859 +                case COMM_SYSRQ:
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);
2866 +                       break;
2867 +               default:
2868 +                       reply.code = REPLY_ERROR;
2869 +                       reply.nr = req.nr;
2870 +                       reply.info = req.command;
2871 +                       sprintf(tmp, "Got unknown command code %d!\n",
2872 +                                       req.command);
2873 +                       dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
2874 +                       break;
2875 +               }
2876 +       }
2877 +out:
2878 +       netdump_in_progress = 0;
2879 +       return ret;
2880 +}
2881 +
2882 +static int
2883 +dump_validate_config(void)
2884 +{
2885 +       source_ip = dump_in_dev->ifa_list->ifa_local;
2886 +       if (!source_ip) {
2887 +               printk("network device %s has no local address, "
2888 +                               "aborting.\n", device_name);
2889 +               return -1;
2890 +       }
2891 +
2892 +#define IP(x) ((unsigned char *)&source_ip)[x]
2893 +       printk("Source %d.%d.%d.%d", IP(0), IP(1), IP(2), IP(3));
2894 +#undef IP
2895 +
2896 +       if (!source_port) {
2897 +               printk("source_port parameter not specified, aborting.\n");
2898 +               return -1;
2899 +       }
2900 +       printk(":%i\n", source_port);
2901 +       source_port = htons(source_port);
2902 +
2903 +       if (!target_ip) {
2904 +               printk("target_ip parameter not specified, aborting.\n");
2905 +               return -1;
2906 +       }
2907 +
2908 +#define IP(x) ((unsigned char *)&target_ip)[x]
2909 +       printk("Target %d.%d.%d.%d", IP(0), IP(1), IP(2), IP(3));
2910 +#undef IP
2911 +
2912 +       if (!target_port) {
2913 +               printk("target_port parameter not specified, aborting.\n");
2914 +               return -1;
2915 +       }
2916 +       printk(":%i\n", target_port);
2917 +       target_port = htons(target_port);
2918 +
2919 +       printk("Target Ethernet Address %02x:%02x:%02x:%02x:%02x:%02x",
2920 +               daddr[0], daddr[1], daddr[2], daddr[3], daddr[4], daddr[5]);
2921 +
2922 +       if ((daddr[0] & daddr[1] & daddr[2] & daddr[3] & daddr[4] & 
2923 +                               daddr[5]) == 255)
2924 +               printk("(Broadcast)");
2925 +       printk("\n");
2926 +       return 0;
2927 +}
2928 +
2929 +/*
2930 + * Prepares the dump device so we can take a dump later. 
2931 + * Validates the netdump configuration parameters.
2932 + *
2933 + * TODO: Network connectivity check should be done here.
2934 + */
2935 +static int
2936 +dump_net_open(struct dump_dev *net_dev, unsigned long arg)
2937 +{
2938 +       int retval = 0;
2939 +
2940 +       /* get the interface name */
2941 +       if (copy_from_user(device_name, (void *)arg, IFNAMSIZ))
2942 +               return -EFAULT;
2943 +
2944 +       if (!(dump_ndev = dev_get_by_name(device_name))) {
2945 +               printk("network device %s does not exist, aborting.\n",
2946 +                               device_name);
2947 +               return -ENODEV;
2948 +       }
2949 +
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 */
2954 +               goto err1;
2955 +       }
2956 +
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);
2960 +               retval = -EINVAL;
2961 +               goto err1;
2962 +       }
2963 +
2964 +       if ((retval = dump_validate_config()) < 0)
2965 +               goto err2;
2966 +
2967 +       net_dev->curr_offset = 0;
2968 +       printk("Network device %s successfully configured for dumping\n",
2969 +                       device_name);
2970 +       return retval;
2971 +err2:
2972 +       in_dev_put(dump_in_dev);
2973 +err1:
2974 +       dev_put(dump_ndev);     
2975 +       return retval;
2976 +}
2977 +
2978 +/*
2979 + * Close the dump device and release associated resources
2980 + * Invoked when unconfiguring the dump device.
2981 + */
2982 +static int
2983 +dump_net_release(struct dump_dev *net_dev)
2984 +{
2985 +       if (dump_in_dev)
2986 +               in_dev_put(dump_in_dev);
2987 +       if (dump_ndev)
2988 +               dev_put(dump_ndev);
2989 +       return 0;
2990 +}
2991 +
2992 +/*
2993 + * Prepare the dump device for use (silence any ongoing activity
2994 + * and quiesce state) when the system crashes.
2995 + */
2996 +static int
2997 +dump_net_silence(struct dump_dev *net_dev)
2998 +{
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());
3005 +       return 0;
3006 +}
3007 +
3008 +/*
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.
3012 + */
3013 +static int
3014 +dump_net_resume(struct dump_dev *net_dev)
3015 +{
3016 +       int indx;
3017 +       reply_t reply;
3018 +       char tmp[200];
3019 +
3020 +        if (!dump_ndev)
3021 +               return (0);
3022 +
3023 +       sprintf(tmp, "NETDUMP end.\n");
3024 +       for( indx = 0; indx < 6; indx++) {
3025 +               reply.code = REPLY_END_NETDUMP;
3026 +               reply.nr = 0;
3027 +               reply.info = 0;
3028 +               dump_send_skb(dump_ndev, tmp, strlen(tmp), &reply);
3029 +       }
3030 +       printk("NETDUMP END!\n");
3031 +       local_irq_restore(flags_global);
3032 +       dump_ndev->rx_hook = NULL;
3033 +       startup_handshake = 0;
3034 +       return 0;
3035 +}
3036 +
3037 +/*
3038 + * Seek to the specified offset in the dump device.
3039 + * Makes sure this is a valid offset, otherwise returns an error.
3040 + */
3041 +static  int
3042 +dump_net_seek(struct dump_dev *net_dev, loff_t off)
3043 +{
3044 +       /*
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.
3048 +        */
3049 +       net_dev->curr_offset = off + DUMP_HEADER_OFFSET;
3050 +       return 0;
3051 +}
3052 +
3053 +/*
3054 + *
3055 + */
3056 +static int
3057 +dump_net_write(struct dump_dev *net_dev, void *buf, unsigned long len)
3058 +{
3059 +       int cnt, i, off;
3060 +       ssize_t ret;
3061 +
3062 +       cnt = len/ PAGE_SIZE;
3063 +
3064 +       for (i = 0; i < cnt; i++) {
3065 +               off = i* PAGE_SIZE;
3066 +               ret = do_netdump(net_dev, buf+off, PAGE_SIZE);
3067 +               if (ret <= 0)
3068 +                       return -1;
3069 +               net_dev->curr_offset = net_dev->curr_offset + PAGE_SIZE;
3070 +       }
3071 +       return len;
3072 +}
3073 +
3074 +/*
3075 + * check if the last dump i/o is over and ready for next request
3076 + */
3077 +static int
3078 +dump_net_ready(struct dump_dev *net_dev, void *buf)
3079 +{
3080 +       return 0;
3081 +}
3082 +
3083 +/*
3084 + * ioctl function used for configuring network dump
3085 + */
3086 +static int
3087 +dump_net_ioctl(struct dump_dev *net_dev, unsigned int cmd, unsigned long arg)
3088 +{
3089 +       switch (cmd) {
3090 +       case DIOSTARGETIP:
3091 +               target_ip = arg;
3092 +               break;
3093 +       case DIOSTARGETPORT:
3094 +               target_port = (u16)arg;
3095 +               break;
3096 +       case DIOSSOURCEPORT:
3097 +               source_port = (u16)arg;
3098 +               break;
3099 +       case DIOSETHADDR:
3100 +               return copy_from_user(daddr, (void *)arg, 6);
3101 +               break;
3102 +       case DIOGTARGETIP:
3103 +       case DIOGTARGETPORT:
3104 +       case DIOGSOURCEPORT:
3105 +       case DIOGETHADDR:
3106 +               break;
3107 +       default:
3108 +               return -EINVAL;
3109 +       }
3110 +       return 0;
3111 +}
3112 +
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
3123 +};
3124 +
3125 +static struct dump_dev default_dump_netdev = {
3126 +       .type_name = "networkdev", 
3127 +       .ops = &dump_netdev_ops, 
3128 +       .curr_offset = 0
3129 +};
3130 +
3131 +static int __init
3132 +dump_netdev_init(void)
3133 +{
3134 +        default_dump_netdev.curr_offset = 0;
3135 +
3136 +       if (dump_register_device(&default_dump_netdev) < 0) {
3137 +               printk("network dump device driver registration failed\n");
3138 +               return -1;
3139 +       }
3140 +       printk("network device driver for LKCD registered\n");
3141
3142 +       get_random_bytes(&dump_magic, sizeof(dump_magic));
3143 +       return 0;
3144 +}
3145 +
3146 +static void __exit
3147 +dump_netdev_cleanup(void)
3148 +{
3149 +       dump_unregister_device(&default_dump_netdev);
3150 +}
3151 +
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");
3155 +
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
3162 @@ -0,0 +1,848 @@
3163 +/*
3164 + * Two-stage soft-boot based dump scheme methods (memory overlay
3165 + * with post soft-boot writeout)
3166 + *
3167 + * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
3168 + *
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)
3176 + *     and also to
3177 + *     Jeff Moyer <moyer@mclx.com>
3178 + *     Josh Huber <huber@mclx.com>
3179 + * 
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 
3187 + * from userspace.
3188 + *
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. 
3194 + *
3195 + * Copyright (C) 2002 International Business Machines Corp. 
3196 + *
3197 + * This code is released under version 2 of the GNU GPL.
3198 + */
3199 +
3200 +/*
3201 + * Disruptive dumping using the second kernel soft-boot option
3202 + * for issuing dump i/o operates in 2 stages:
3203 + * 
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. 
3210 + *
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.
3219 + *
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 
3224 + *     clean reboot.
3225 + *     
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
3230 + *     passes.
3231 + */
3232 +
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"
3239 +
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;
3247 +
3248 +/* For testing 
3249 +extern void dump_display_map(struct dump_memdev *);
3250 +*/
3251 +
3252 +struct dumper *dumper_by_name(char *name)
3253 +{
3254 +#ifdef LATER
3255 +       struct dumper *dumper;
3256 +       list_for_each_entry(dumper, &dumper_list_head, dumper_list)
3257 +               if (!strncmp(dumper->name, name, 32))
3258 +                       return dumper;
3259 +
3260 +       /* not found */
3261 +       return NULL; 
3262 +#endif
3263 +       /* Temporary proof of concept */
3264 +       if (!strncmp(dumper_stage2.name, name, 32))
3265 +               return &dumper_stage2;
3266 +       else
3267 +               return NULL;
3268 +}
3269 +
3270 +#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
3271 +extern void dump_early_reserve_map(struct dump_memdev *);
3272 +
3273 +void crashdump_reserve(void)
3274 +{
3275 +       extern unsigned long crashdump_addr;
3276 +
3277 +       if (crashdump_addr == 0xdeadbeef) 
3278 +               return;
3279 +
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;
3286 +               return;
3287 +       }
3288 +                       
3289 +       printk("Dump may be available from previous boot\n");
3290 +
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);
3294 +
3295 +}
3296 +#endif
3297 +
3298 +/* 
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.
3302 + */
3303 +int dump_load_config(struct dump_config_block *config)
3304 +{
3305 +       struct dumper *dumper;
3306 +       struct dump_data_filter *filter_table, *filter;
3307 +       struct dump_dev *dev;
3308 +       int i;
3309 +
3310 +       if (config->magic != DUMP_MAGIC_LIVE)
3311 +               return -ENOENT; /* not a valid config */
3312 +
3313 +       /* initialize generic config data */
3314 +       memcpy(&dump_config, &config->config, sizeof(dump_config));
3315 +
3316 +       /* initialize dumper state */
3317 +       if (!(dumper = dumper_by_name(config->dumper.name)))  {
3318 +               printk("dumper name mismatch\n");
3319 +               return -ENOENT; /* dumper mismatch */
3320 +       }
3321 +       
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 */
3326 +       }
3327 +       config->scheme.ops = dumper->scheme->ops;
3328 +       config->dumper.scheme = &config->scheme;
3329 +       
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); 
3334 +               i++, filter++) {
3335 +               if (strncmp(filter_table[i].name, filter->name, 32)) {
3336 +                       printk("dump filter mismatch\n");
3337 +                       return -ENOENT; /* filter name mismatch */
3338 +               }
3339 +               filter->selector = filter_table[i].selector;
3340 +       }
3341 +       config->dumper.filter = config->filter_table;
3342 +
3343 +       /* fixup format */
3344 +       if (strncmp(dumper->fmt->name, config->fmt.name, 32)) {
3345 +               printk("dump format mismatch\n");
3346 +               return -ENOENT; /* mismatch */
3347 +       }
3348 +       config->fmt.ops = dumper->fmt->ops;
3349 +       config->dumper.fmt = &config->fmt;
3350 +
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)
3356 +                       return -ENODEV;
3357 +               dumper->dev = dump_dev;
3358 +       }
3359 +
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 */
3364 +       }
3365 +       dev->ops = dumper->dev->ops; 
3366 +       config->dumper.dev = dev;
3367 +       
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;
3374 +
3375 +       /* Make this the current primary dumper */
3376 +       dump_config.dumper = &config->dumper;
3377 +
3378 +       return 0;
3379 +}
3380 +
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)
3383 +{
3384 +       printk("saving dump config settings\n");
3385 +
3386 +       /* dump config settings */
3387 +       memcpy(&config->config, &dump_config, sizeof(dump_config));
3388 +
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);
3398 +
3399 +       /* handle to saved mem pages */
3400 +       memcpy(&config->memdev, dump_memdev, sizeof(struct dump_memdev));
3401 +
3402 +       config->magic = DUMP_MAGIC_LIVE;
3403 +       
3404 +       return 0;
3405 +}
3406 +
3407 +int dump_init_stage2(struct dump_config_block *saved_config)
3408 +{
3409 +       int err = 0;
3410 +
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)))
3417 +                       return err;
3418 +
3419 +               if (!dump_oncpu) {
3420 +                       if ((err = dump_configure(dump_config.dump_device))) {
3421 +                               printk("Stage 2 dump configure failed\n");
3422 +                               return err;
3423 +                       }
3424 +               }
3425 +
3426 +               dumper_reset();
3427 +               dump_dev = dump_config.dumper->dev;
3428 +               /* write out the dump */
3429 +               err = dump_generic_execute(NULL, NULL);
3430 +               
3431 +               dump_saved_config = NULL;
3432 +
3433 +               if (!dump_oncpu) {
3434 +                       dump_unconfigure(); 
3435 +               }
3436 +               
3437 +               return err;
3438 +
3439 +       } else {
3440 +               /* no dump to write out */
3441 +               printk("no dumper from previous boot \n");
3442 +               return 0;
3443 +       }
3444 +}
3445 +
3446 +extern void dump_mem_markpages(struct dump_memdev *);
3447 +
3448 +int dump_switchover_stage(void)
3449 +{
3450 +       int ret = 0;
3451 +
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;
3459 +       return ret;
3460 +}
3461 +
3462 +int dump_activate_softboot(void) 
3463 +{
3464 +       int err = 0;
3465 +
3466 +       /* temporary - switchover to writeout previously saved dump */
3467 +       err = dump_switchover_stage(); /* non-disruptive case */
3468 +       if (dump_oncpu) 
3469 +               dump_config.dumper = &dumper_stage1; /* set things back */
3470 +
3471 +       return err;
3472 +
3473 +       dump_silence_level = DUMP_HALT_CPUS;
3474 +       /* wait till we become the only cpu */
3475 +       /* maybe by checking for online cpus ? */
3476 +
3477 +       /* now call into kexec */
3478 +
3479 +       /* TBD/Fixme: 
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 ? 
3484 +        */
3485 +       return 0;
3486 +}
3487 +
3488 +/* --- DUMP SCHEME ROUTINES  --- */
3489 +
3490 +static inline int dump_buf_pending(struct dumper *dumper)
3491 +{
3492 +       return (dumper->curr_buf - dumper->dump_buf);
3493 +}
3494 +
3495 +/* Invoked during stage 1 of soft-reboot based dumping */
3496 +int dump_overlay_sequencer(void)
3497 +{
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);
3502 +
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");
3506 +               return -EINVAL;
3507 +       }
3508 +
3509 +       /* start filling in dump data right after the header */
3510 +       dump_config.dumper->curr_offset = 
3511 +               PAGE_ALIGN(dump_config.dumper->header_len);
3512 +
3513 +       /* Locate the last pass */
3514 +       for (;filter->selector; filter++, pass++);
3515 +       
3516 +       /* 
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
3520 +        * with them. 
3521 +        */
3522 +       for (--pass, --filter; pass >= 0; pass--, filter--)
3523 +       {
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;
3528 +               else
3529 +                       action = dump_skip_data;
3530 +
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);
3538 +               }
3539 +               
3540 +               filter2[pass].start = dump_config.dumper->curr_offset
3541 +                       + dump_buf_pending(dump_config.dumper);
3542 +
3543 +               err = dump_iterator(pass, action, filter);
3544 +
3545 +               filter2[pass].end = dump_config.dumper->curr_offset
3546 +                       + dump_buf_pending(dump_config.dumper);
3547 +
3548 +               if (err < 0) {
3549 +                       printk("dump_overlay_seq: failure %d in pass %d\n", 
3550 +                               err, pass);
3551 +                       break;
3552 +               }       
3553 +               printk("\n %d overlay pages %s of %d each in pass %d\n", 
3554 +               err, save ? "saved" : "skipped", DUMP_PAGE_SIZE, pass);
3555 +       }
3556 +
3557 +       return err;
3558 +}
3559 +
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);
3563 +
3564 +static inline struct page *dump_get_saved_page(loff_t loc)
3565 +{
3566 +       return (dump_mem_lookup(dump_memdev, loc >> PAGE_SHIFT));
3567 +}
3568 +
3569 +static inline struct page *dump_next_saved_page(void)
3570 +{
3571 +       return (dump_mem_next_page(dump_memdev));
3572 +}
3573 +
3574 +/* 
3575 + * Iterates over list of saved dump pages. Invoked during second stage of 
3576 + * soft boot dumping
3577 + *
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
3583 + * faster.
3584 + */
3585 +int dump_saved_data_iterator(int pass, int (*action)(unsigned long, 
3586 +       unsigned long), struct dump_data_filter *filter)
3587 +{
3588 +       loff_t loc = filter->start;
3589 +       struct page *page;
3590 +       unsigned long count = 0;
3591 +       int err = 0;
3592 +       unsigned long sz;
3593 +
3594 +       printk("pass %d, start off 0x%llx end offset 0x%llx\n", pass,
3595 +                       filter->start, filter->end);
3596 +
3597 +       /* loc will get treated as logical offset into stage 1 */
3598 +       page = dump_get_saved_page(loc);
3599 +                       
3600 +       for (; loc < filter->end; loc += PAGE_SIZE) {
3601 +               dump_config.dumper->curr_loc = loc;
3602 +               if (!page) {
3603 +                       printk("no more saved data for pass %d\n", pass);
3604 +                       break;
3605 +               }
3606 +               sz = (loc + PAGE_SIZE > filter->end) ? filter->end - loc :
3607 +                       PAGE_SIZE;
3608 +
3609 +               if (page && filter->selector(pass, (unsigned long)page, 
3610 +                       PAGE_SIZE))  {
3611 +                       pr_debug("mem offset 0x%llx\n", loc);
3612 +                       if ((err = action((unsigned long)page, sz))) 
3613 +                               break;
3614 +                       else
3615 +                               count++;
3616 +                       /* clear the contents of page */
3617 +                       /* fixme: consider using KM_DUMP instead */
3618 +                       clear_highpage(page);
3619 +                       
3620 +               }
3621 +               page = dump_next_saved_page();
3622 +       }
3623 +
3624 +       return err ? err : count;
3625 +}
3626 +
3627 +static inline int dump_overlay_pages_done(struct page *page, int nr)
3628 +{
3629 +       int ret=0;
3630 +
3631 +       for (; nr ; page++, nr--) {
3632 +               if (dump_check_and_free_page(dump_memdev, page))
3633 +                       ret++;
3634 +       }
3635 +       return ret;
3636 +}
3637 +
3638 +int dump_overlay_save_data(unsigned long loc, unsigned long len)
3639 +{
3640 +       int err = 0;
3641 +       struct page *page = (struct page *)loc;
3642 +       static unsigned long cnt = 0;
3643 +
3644 +       if ((err = dump_generic_save_data(loc, len)))
3645 +               return err;
3646 +
3647 +       if (dump_overlay_pages_done(page, len >> PAGE_SHIFT)) {
3648 +               cnt++;
3649 +               if (!(cnt & 0x7f))
3650 +                       pr_debug("released page 0x%lx\n", page_to_pfn(page));
3651 +       }
3652 +       
3653 +       return err;
3654 +}
3655 +
3656 +
3657 +int dump_overlay_skip_data(unsigned long loc, unsigned long len)
3658 +{
3659 +       struct page *page = (struct page *)loc;
3660 +
3661 +       dump_overlay_pages_done(page, len >> PAGE_SHIFT);
3662 +       return 0;
3663 +}
3664 +
3665 +int dump_overlay_resume(void)
3666 +{
3667 +       int err = 0;
3668 +
3669 +       /* 
3670 +        * switch to stage 2 dumper, save dump_config_block
3671 +        * and then trigger a soft-boot
3672 +        */
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)))
3676 +               return err;
3677 +
3678 +       dump_dev = dump_config.dumper->dev;
3679 +
3680 +       return err;
3681 +       err = dump_switchover_stage();  /* plugs into soft boot mechanism */
3682 +       dump_config.dumper = &dumper_stage1; /* set things back */
3683 +       return err;
3684 +}
3685 +
3686 +int dump_overlay_configure(unsigned long devid)
3687 +{
3688 +       struct dump_dev *dev;
3689 +       struct dump_config_block *saved_config = dump_saved_config;
3690 +       int err = 0;
3691 +
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();
3696 +               if (err) {
3697 +                       printk("failed to writeout saved dump\n");
3698 +                       return err;
3699 +               }
3700 +               dump_free_mem(saved_config); /* testing only: not after boot */
3701 +       }
3702 +
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);
3708 +               return err;
3709 +       }
3710 +       /* temporary */
3711 +       dumper_stage2.dump_buf = dump_config.dumper->dump_buf;
3712 +
3713 +       /* Sanity check on the actual target dump device */
3714 +       if (!dev || (err = dev->ops->open(dev, devid))) {
3715 +               return err;
3716 +       }
3717 +       /* TBD: should we release the target if this is soft-boot only ? */
3718 +
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();
3725 +               return -ENOMEM;
3726 +       }
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);
3730 +       return 0;
3731 +}
3732 +
3733 +int dump_overlay_unconfigure(void)
3734 +{
3735 +       struct dump_dev *dev = dumper_stage2.dev;
3736 +       int err = 0;
3737 +
3738 +       pr_debug("dump_overlay_unconfigure\n");
3739 +       /* Close the secondary device */
3740 +       dev->ops->release(dev); 
3741 +       pr_debug("released secondary device\n");
3742 +
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;
3749 +
3750 +       printk("Unconfigured overlay dumper\n");
3751 +       return err;
3752 +}
3753 +
3754 +int dump_staged_unconfigure(void)
3755 +{
3756 +       int err = 0;
3757 +       struct dump_config_block *saved_config = dump_saved_config;
3758 +       struct dump_dev *dev;
3759 +
3760 +       pr_debug("dump_staged_unconfigure\n");
3761 +       err = dump_generic_unconfigure();
3762 +
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");
3770 +               } else {
3771 +                       dump_free_mem(saved_config);
3772 +                       pr_debug("Freed saved config block\n");
3773 +               }
3774 +               dump_saved_config = NULL;
3775 +       } else {
3776 +               dev = &dump_memdev->ddev;
3777 +               dev->ops->release(dev);
3778 +       }
3779 +       printk("Unconfigured second stage dumper\n");
3780 +
3781 +       return 0;
3782 +}
3783 +
3784 +/* ----- PASSTHRU FILTER ROUTINE --------- */
3785 +
3786 +/* transparent - passes everything through */
3787 +int dump_passthru_filter(int pass, unsigned long loc, unsigned long sz)
3788 +{
3789 +       return 1;
3790 +}
3791 +
3792 +/* ----- PASSTRU FORMAT ROUTINES ---- */
3793 +
3794 +
3795 +int dump_passthru_configure_header(const char *panic_str, const struct pt_regs *regs)
3796 +{
3797 +       dump_config.dumper->header_dirty++;
3798 +       return 0;
3799 +}
3800 +
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)
3803 +{
3804 +       unsigned long len = 0, bytes;
3805 +       void *addr;
3806 +
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);
3812 +               buf += bytes;
3813 +               len += bytes;
3814 +               page++;
3815 +       }
3816 +       /* memset(dump_config.dumper->curr_buf, 0x57, len); temporary */
3817 +
3818 +       return sz - len;
3819 +}
3820 +
3821 +int dump_passthru_update_header(void)
3822 +{
3823 +       long len = dump_config.dumper->header_len;
3824 +       struct page *page;
3825 +       void *buf = dump_config.dumper->dump_buf;
3826 +       int err = 0;
3827 +
3828 +       if (!dump_config.dumper->header_dirty)
3829 +               return 0;
3830 +
3831 +       pr_debug("Copying header of size %ld bytes from memory\n", len);
3832 +       if (len > DUMP_BUFFER_SIZE) 
3833 +               return -E2BIG;
3834 +
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)))
3838 +                       return err;
3839 +               page = dump_mem_next_page(dump_memdev);
3840 +       }
3841 +       if (len > 0) {
3842 +               printk("Incomplete header saved in mem\n");
3843 +               return -ENOENT;
3844 +       }
3845 +
3846 +       if ((err = dump_dev_seek(0))) {
3847 +               printk("Unable to seek to dump header offset\n");
3848 +               return err;
3849 +       }
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;
3854 +
3855 +       dump_config.dumper->header_dirty = 0;
3856 +       return 0;
3857 +}
3858 +
3859 +static loff_t next_dph_offset = 0;
3860 +
3861 +static int dph_valid(struct __dump_page *dph)
3862 +{
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);
3868 +               return 0;
3869 +       }
3870 +       return 1;
3871 +}
3872 +
3873 +int dump_verify_lcrash_data(void *buf, unsigned long sz)
3874 +{
3875 +       struct __dump_page *dph;
3876 +
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",
3882 +                               next_dph_offset);
3883 +                       return -EINVAL;
3884 +               }
3885 +               next_dph_offset += dph->dp_size + sizeof(*dph);
3886 +       }
3887 +
3888 +       next_dph_offset -= sz;  
3889 +       return 0;
3890 +}
3891 +
3892 +/* 
3893 + * TBD/Later: Consider avoiding the copy by using a scatter/gather 
3894 + * vector representation for the dump buffer
3895 + */
3896 +int dump_passthru_add_data(unsigned long loc, unsigned long sz)
3897 +{
3898 +       struct page *page = (struct page *)loc;
3899 +       void *buf = dump_config.dumper->curr_buf;
3900 +       int err = 0;
3901 +
3902 +       if ((err = dump_copy_pages(buf, page, sz))) {
3903 +               printk("dump_copy_pages failed");
3904 +               return err;
3905 +       }
3906 +
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));
3912 +               return err;
3913 +       }
3914 +
3915 +       dump_config.dumper->curr_buf = buf + sz;
3916 +
3917 +       return 0;
3918 +}
3919 +
3920 +
3921 +/* Stage 1 dumper: Saves compressed dump in memory and soft-boots system */
3922 +
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
3932 +};
3933 +
3934 +struct dump_scheme dump_scheme_overlay = {
3935 +       .name           = "overlay",
3936 +       .ops            = &dump_scheme_overlay_ops
3937 +};
3938 +
3939 +
3940 +/* Stage 1 must use a good compression scheme - default to gzip */
3941 +extern struct __dump_compress dump_gzip_compression;
3942 +
3943 +struct dumper dumper_stage1 = {
3944 +       .name           = "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,
3949 +       .dev            = NULL,
3950 +};             
3951 +
3952 +/* Stage 2 dumper: Activated after softboot to write out saved dump to device */
3953 +
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
3961 +};
3962 +
3963 +struct dump_fmt dump_fmt_passthru = {
3964 +       .name   = "passthru",
3965 +       .ops    = &dump_fmt_passthru_ops
3966 +};
3967 +
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 */
3970 +
3971 +extern int dump_filter_none(int pass, unsigned long loc, unsigned long sz);
3972 +
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 }
3982 +};
3983 +
3984 +
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
3994 +};
3995 +
3996 +struct dump_scheme dump_scheme_staged = {
3997 +       .name           = "staged",
3998 +       .ops            = &dump_scheme_staged_ops
3999 +};
4000 +
4001 +/* The stage 2 dumper comprising all these */
4002 +struct dumper dumper_stage2 = {
4003 +       .name           = "stage2",
4004 +       .scheme         = &dump_scheme_staged,
4005 +       .fmt            = &dump_fmt_passthru,
4006 +       .compress       = &dump_none_compression,
4007 +       .filter         = dump_passthru_filtertable,
4008 +       .dev            = NULL,
4009 +};             
4010 +
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
4015 @@ -0,0 +1,175 @@
4016 +/*
4017 + * RLE Compression functions for kernel crash dumps.
4018 + *
4019 + * Created by: Matt Robinson (yakker@sourceforge.net)
4020 + * Copyright 2001 Matt D. Robinson.  All rights reserved.
4021 + *
4022 + * This code is released under version 2 of the GNU GPL.
4023 + */
4024 +
4025 +/* header files */
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>
4033 +
4034 +/*
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.
4038 + */
4039 +static u16
4040 +dump_compress_rle(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
4041 +{
4042 +       u16 ri, wi, count = 0;
4043 +       u_char value = 0, cur_byte;
4044 +
4045 +       /*
4046 +        * If the block should happen to "compress" to larger than the
4047 +        * buffer size, allocate a larger one and change cur_buf_size.
4048 +        */
4049 +
4050 +       wi = ri = 0;
4051 +
4052 +       while (ri < oldsize) {
4053 +               if (!ri) {
4054 +                       cur_byte = value = old[ri];
4055 +                       count = 0;
4056 +               } else {
4057 +                       if (count == 255) {
4058 +                               if (wi + 3 > oldsize) {
4059 +                                       return oldsize;
4060 +                               }
4061 +                               new[wi++] = 0;
4062 +                               new[wi++] = count;
4063 +                               new[wi++] = value;
4064 +                               value = cur_byte = old[ri];
4065 +                               count = 0;
4066 +                       } else { 
4067 +                               if ((cur_byte = old[ri]) == value) {
4068 +                                       count++;
4069 +                               } else {
4070 +                                       if (count > 1) {
4071 +                                               if (wi + 3 > oldsize) {
4072 +                                                       return oldsize;
4073 +                                               }
4074 +                                               new[wi++] = 0;
4075 +                                               new[wi++] = count;
4076 +                                               new[wi++] = value;
4077 +                                       } else if (count == 1) {
4078 +                                               if (value == 0) {
4079 +                                                       if (wi + 3 > oldsize) {
4080 +                                                               return oldsize;
4081 +                                                       }
4082 +                                                       new[wi++] = 0;
4083 +                                                       new[wi++] = 1;
4084 +                                                       new[wi++] = 0;
4085 +                                               } else {
4086 +                                                       if (wi + 2 > oldsize) {
4087 +                                                               return oldsize;
4088 +                                                       }
4089 +                                                       new[wi++] = value;
4090 +                                                       new[wi++] = value;
4091 +                                               }
4092 +                                       } else { /* count == 0 */
4093 +                                               if (value == 0) {
4094 +                                                       if (wi + 2 > oldsize) {
4095 +                                                               return oldsize;
4096 +                                                       }
4097 +                                                       new[wi++] = value;
4098 +                                                       new[wi++] = value;
4099 +                                               } else {
4100 +                                                       if (wi + 1 > oldsize) {
4101 +                                                               return oldsize;
4102 +                                                       }
4103 +                                                       new[wi++] = value;
4104 +                                               }
4105 +                                       } /* if count > 1 */
4106 +
4107 +                                       value = cur_byte;
4108 +                                       count = 0;
4109 +
4110 +                               } /* if byte == value */
4111 +
4112 +                       } /* if count == 255 */
4113 +
4114 +               } /* if ri == 0 */
4115 +               ri++;
4116 +
4117 +       }
4118 +       if (count > 1) {
4119 +               if (wi + 3 > oldsize) {
4120 +                       return oldsize;
4121 +               }
4122 +               new[wi++] = 0;
4123 +               new[wi++] = count;
4124 +               new[wi++] = value;
4125 +       } else if (count == 1) {
4126 +               if (value == 0) {
4127 +                       if (wi + 3 > oldsize)
4128 +                               return oldsize;
4129 +                       new[wi++] = 0;
4130 +                       new[wi++] = 1;
4131 +                       new[wi++] = 0;
4132 +               } else {
4133 +                       if (wi + 2 > oldsize)
4134 +                               return oldsize;
4135 +                       new[wi++] = value;
4136 +                       new[wi++] = value;
4137 +               }
4138 +       } else { /* count == 0 */
4139 +               if (value == 0) {
4140 +                       if (wi + 2 > oldsize)
4141 +                               return oldsize;
4142 +                       new[wi++] = value;
4143 +                       new[wi++] = value;
4144 +               } else {
4145 +                       if (wi + 1 > oldsize)
4146 +                               return oldsize;
4147 +                       new[wi++] = value;
4148 +               }
4149 +       } /* if count > 1 */
4150 +
4151 +       value = cur_byte;
4152 +       count = 0;
4153 +       return wi;
4154 +}
4155 +
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",
4161 +};
4162 +
4163 +/*
4164 + * Name: dump_compress_rle_init()
4165 + * Func: Initialize rle compression for dumping.
4166 + */
4167 +static int __init
4168 +dump_compress_rle_init(void)
4169 +{
4170 +       dump_register_compression(&dump_rle_compression);
4171 +       return 0;
4172 +}
4173 +
4174 +/*
4175 + * Name: dump_compress_rle_cleanup()
4176 + * Func: Remove rle compression for dumping.
4177 + */
4178 +static void __exit
4179 +dump_compress_rle_cleanup(void)
4180 +{
4181 +       dump_unregister_compression(DUMP_COMPRESS_RLE);
4182 +}
4183 +
4184 +/* module initialization */
4185 +module_init(dump_compress_rle_init);
4186 +module_exit(dump_compress_rle_cleanup);
4187 +
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
4195 @@ -0,0 +1,357 @@
4196 +/* 
4197 + * Default single stage dump scheme methods
4198 + *
4199 + * Previously a part of dump_base.c
4200 + *
4201 + * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
4202 + *     Split and rewrote LKCD dump scheme to generic dump method 
4203 + *     interfaces 
4204 + * Derived from original code created by
4205 + *     Matt Robinson <yakker@sourceforge.net>)
4206 + *
4207 + * Contributions from SGI, IBM, HP, MCL, and others.
4208 + *
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. 
4212 + *
4213 + * This code is released under version 2 of the GNU GPL.
4214 + */
4215 +
4216 +/*
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.
4221 + *
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) 
4225 + */ 
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"
4235 +
4236 +extern int panic_timeout;  /* time before reboot */
4237 +
4238 +extern void dump_speedo(int);
4239 +
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)
4243 +{
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);
4247 +
4248 +       /* 
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 
4253 +        */
4254 +       for (;filter->selector; filter++, pass++)
4255 +       {
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;
4260 +               else
4261 +                       action = dump_skip_data;
4262 +
4263 +               if ((err = dump_iterator(pass, action, filter)) < 0)
4264 +                       break;
4265 +
4266 +               printk("\n %d dump pages %s of %d each in pass %d\n", 
4267 +               err, save ? "saved" : "skipped", DUMP_PAGE_SIZE, pass);
4268 +
4269 +       }
4270 +
4271 +       return (err < 0) ? err : 0;
4272 +}
4273 +
4274 +static inline struct page *dump_get_page(loff_t loc)
4275 +{
4276 +       unsigned long page_index = loc >> PAGE_SHIFT;
4277 +
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);
4283 +       else
4284 +               return NULL;
4285 +
4286 +}
4287 +
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)
4292 +{
4293 +       /* Todo : fix unit, type */
4294 +       loff_t loc;
4295 +       int count = 0, err = 0;
4296 +       struct page *page;
4297 +
4298 +       /* Todo: Add membanks code */
4299 +       /* TBD: Check if we need to address DUMP_PAGE_SIZE < PAGE_SIZE */       
4300 +       
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)))
4307 +                       {
4308 +                               printk("dump_page_iterator: err %d for loc "
4309 +                               "0x%llx, in pass %d\n", err, loc, pass);
4310 +                               break;
4311 +                       } else
4312 +                               count++;
4313 +               }
4314 +       }
4315 +
4316 +       return err ? err : count;
4317 +}
4318 +
4319 +/* 
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 
4322 + */
4323 +int dump_generic_save_data(unsigned long loc, unsigned long sz)
4324 +{
4325 +       void *buf;
4326 +       void *dump_buf = dump_config.dumper->dump_buf;
4327 +       int left, bytes, ret;
4328 +
4329 +       if ((ret = dump_add_data(loc, sz))) {
4330 +               return ret;
4331 +       }
4332 +       buf = dump_config.dumper->curr_buf;
4333 +
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;
4340 +               }
4341 +
4342 +               left -= bytes;
4343 +               
4344 +               /* -- A few chores to do from time to time -- */
4345 +               dump_config.dumper->count++;
4346 +
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 */
4352 +                               return ret;
4353 +                       }
4354 +                       printk(".");
4355 +
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); 
4360 +               }
4361 +               /* Todo: Touch/Refresh watchdog */
4362 +
4363 +               /* --- Done with periodic chores -- */
4364 +
4365 +               /* 
4366 +                * extra bit of copying to simplify verification  
4367 +                * in the second kernel boot based scheme
4368 +                */
4369 +               memcpy(dump_buf - DUMP_PAGE_SIZE, dump_buf + 
4370 +                       DUMP_BUFFER_SIZE - DUMP_PAGE_SIZE, DUMP_PAGE_SIZE);
4371 +
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);
4375 +               if (left) {
4376 +                       memcpy(dump_buf, dump_buf + DUMP_BUFFER_SIZE, left);
4377 +               }
4378 +               buf -= DUMP_BUFFER_SIZE;
4379 +               dump_config.dumper->curr_buf = buf;
4380 +       }
4381 +                               
4382 +       return 0;
4383 +}
4384 +
4385 +int dump_generic_skip_data(unsigned long loc, unsigned long sz)
4386 +{
4387 +       /* dummy by default */
4388 +       return 0;
4389 +}
4390 +
4391 +/* 
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
4396 + */
4397 +int dump_ll_write(void *buf, unsigned long len)
4398 +{
4399 +       long transferred = 0, last_transfer = 0;
4400 +       int ret = 0;
4401 +
4402 +       /* make sure device is ready */
4403 +       while ((ret = dump_dev_ready(NULL)) == -EAGAIN);
4404 +       if  (ret < 0) {
4405 +               printk("dump_dev_ready failed !err %d\n", ret);
4406 +               return ret;
4407 +       }
4408 +
4409 +       while (len) {
4410 +               if ((last_transfer = dump_dev_write(buf, len)) <= 0)  {
4411 +                       ret = last_transfer;
4412 +                       printk("dump_dev_write failed !err %d\n", 
4413 +                       ret);
4414 +                       break;
4415 +               }
4416 +               /* wait till complete */
4417 +               while ((ret = dump_dev_ready(buf)) == -EAGAIN)
4418 +                       cpu_relax();
4419 +
4420 +               if  (ret < 0) {
4421 +                       printk("i/o failed !err %d\n", ret);
4422 +                       break;
4423 +               }
4424 +
4425 +               len -= last_transfer;
4426 +               buf += last_transfer;
4427 +               transferred += last_transfer;
4428 +       }
4429 +       return (ret < 0) ? ret : transferred;
4430 +}
4431 +
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)
4435 +{
4436 +       long written = 0;
4437 +       int err = 0;
4438 +
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);
4444 +               return err;
4445 +       }
4446 +       /* alignment check would happen as a side effect of this */
4447 +       if ((err = dump_dev_seek(dump_config.dumper->curr_offset)) < 0)
4448 +               return err; 
4449 +
4450 +       written = dump_ll_write(buf, len);
4451 +
4452 +       /* all or none */
4453 +
4454 +       if (written < len)
4455 +               written = written ? -ENOSPC : written;
4456 +       else
4457 +               dump_config.dumper->curr_offset += len;
4458 +
4459 +       return written;
4460 +}
4461 +
4462 +int dump_generic_configure(unsigned long devid)
4463 +{
4464 +       struct dump_dev *dev = dump_config.dumper->dev;
4465 +       struct dump_data_filter *filter;
4466 +       void *buf;
4467 +       int ret = 0;
4468 +
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)))
4472 +               return -ENOMEM;
4473 +
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 */
4478 +       }
4479 +
4480 +       /* Initialize the rest of the fields */
4481 +       dump_config.dumper->dump_buf = buf + DUMP_PAGE_SIZE;
4482 +       dumper_reset();
4483 +
4484 +       /* Open the dump device */
4485 +       if (!dev)
4486 +               return -ENODEV;
4487 +
4488 +       if ((ret = dev->ops->open(dev, devid))) {
4489 +              return ret;
4490 +       }
4491 +
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;
4497 +               }
4498 +       }
4499 +
4500 +       return 0;
4501 +}
4502 +
4503 +int dump_generic_unconfigure(void)
4504 +{
4505 +       struct dump_dev *dev = dump_config.dumper->dev;
4506 +       void *buf = dump_config.dumper->dump_buf;
4507 +       int ret = 0;
4508 +
4509 +       pr_debug("Generic unconfigure\n");
4510 +       /* Close the dump device */
4511 +       if (dev && (ret = dev->ops->release(dev)))
4512 +               return ret;
4513 +
4514 +       printk("Closed dump device\n");
4515 +       
4516 +       if (buf)
4517 +               dump_free_mem((buf - DUMP_PAGE_SIZE));
4518 +
4519 +       dump_config.dumper->curr_buf = dump_config.dumper->dump_buf = NULL;
4520 +       pr_debug("Released dump buffer\n");
4521 +
4522 +       return 0;
4523 +}
4524 +
4525 +
4526 +/* Set up the default dump scheme */
4527 +
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,
4536 +};
4537 +
4538 +struct dump_scheme dump_scheme_singlestage = {
4539 +       .name           = "single-stage",
4540 +       .ops            = &dump_scheme_singlestage_ops
4541 +};
4542 +
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,
4550 +       .dev            = NULL,
4551 +};             
4552 +
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
4557 @@ -0,0 +1,803 @@
4558 +/*
4559 + * Standard kernel function entry points for Linux crash dumps.
4560 + *
4561 + * Created by: Matt Robinson (yakker@sourceforge.net)
4562 + * Contributions from SGI, IBM, HP, MCL, and others.
4563 + *
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.
4568 + *
4569 + * This code is released under version 2 of the GNU GPL.
4570 + */
4571 +
4572 +/*
4573 + * -----------------------------------------------------------------------
4574 + *
4575 + * DUMP HISTORY
4576 + *
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.
4587 + *
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.
4598 + *
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.
4603 + */
4604 +
4605 +/*
4606 + * DUMP TUNABLES
4607 + *
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:
4611 + *
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.
4618 + *
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:
4623 + *
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.
4627 + *
4628 + * dump_level:
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:
4632 + *
4633 + *     0:   Do nothing, no dumping. (DUMP_LEVEL_NONE)
4634 + *
4635 + *     1:   Print out the dump information to the dump header, and
4636 + *          write it out to the dump_device. (DUMP_LEVEL_HEADER)
4637 + *
4638 + *     2:   Write out the dump header and all kernel memory pages.
4639 + *          (DUMP_LEVEL_KERN)
4640 + *
4641 + *     4:   Write out the dump header and all kernel and user
4642 + *          memory pages.  (DUMP_LEVEL_USED)
4643 + *
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)
4647 + *
4648 + *    16:   Write out everything, including non-conventional memory
4649 + *         like firmware, proms, I/O registers, uncached memory.
4650 + *         (DUMP_LEVEL_ALL)
4651 + *
4652 + *     The dump_level will default to 1.
4653 + *
4654 + * dump_flags:
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.
4657 + * 
4658 + * -----------------------------------------------------------------------
4659 + */
4660 +
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>
4675 +
4676 +#include <asm/hardirq.h>
4677 +#include <asm/uaccess.h>
4678 +
4679 +/*
4680 + * -----------------------------------------------------------------------
4681 + *                         V A R I A B L E S
4682 + * -----------------------------------------------------------------------
4683 + */
4684 +
4685 +/* Dump tunables */
4686 +struct dump_config dump_config = {
4687 +       .level          = 0,
4688 +       .flags          = 0,
4689 +       .dump_device    = 0,
4690 +       .dump_addr      = 0,
4691 +       .dumper         = NULL
4692 +};
4693 +
4694 +
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;      
4698 +
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;
4703 +
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",
4709 +};
4710 +
4711 +/* our device operations and functions */
4712 +static int dump_ioctl(struct inode *i, struct file *f,
4713 +       unsigned int cmd, unsigned long arg);
4714 +
4715 +static struct file_operations dump_fops = {
4716 +       .ioctl          =       dump_ioctl,
4717 +};
4718 +
4719 +/* static variables                                                    */
4720 +static int dump_okay = 0;              /* can we dump out to disk?     */
4721 +static spinlock_t dump_lock = SPIN_LOCK_UNLOCKED;
4722 +
4723 +/* used for dump compressors */
4724 +static struct list_head dump_compress_list = LIST_HEAD_INIT(dump_compress_list);
4725 +
4726 +/* list of registered dump targets */
4727 +static struct list_head dump_target_list = LIST_HEAD_INIT(dump_target_list);
4728 +
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,
4734 +#else
4735 +       .byte_order     = __BIG_ENDIAN,
4736 +#endif
4737 +       .page_shift     = PAGE_SHIFT,
4738 +       .page_size      = PAGE_SIZE,
4739 +       .page_mask      = PAGE_MASK,
4740 +       .page_offset    = PAGE_OFFSET,
4741 +};
4742 +
4743 +/*
4744 + * -----------------------------------------------------------------------
4745 + *            / P R O C   T U N A B L E   F U N C T I O N S
4746 + * -----------------------------------------------------------------------
4747 + */
4748 +
4749 +static int proc_dump_device(ctl_table *ctl, int write, struct file *f,
4750 +                           void *buffer, size_t *lenp);
4751 +
4752 +static int proc_doulonghex(ctl_table *ctl, int write, struct file *f,
4753 +                           void *buffer, size_t *lenp);
4754 +/*
4755 + * sysctl-tuning infrastructure.
4756 + */
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),
4762 +         .mode = 0644,
4763 +         .proc_handler = proc_doulonghex, },
4764 +
4765 +       { .ctl_name = CTL_DUMP_FLAGS,
4766 +         .procname = DUMP_FLAGS_NAME,
4767 +         .data = &dump_config.flags,   
4768 +         .maxlen = sizeof(int),
4769 +         .mode = 0644,
4770 +         .proc_handler = proc_doulonghex, },
4771 +
4772 +       { .ctl_name = CTL_DUMP_COMPRESS,
4773 +         .procname = DUMP_COMPRESS_NAME,
4774 +         .data = &dump_compress, /* FIXME */
4775 +         .maxlen = sizeof(int),
4776 +         .mode = 0644,
4777 +         .proc_handler = proc_dointvec, },
4778 +         
4779 +       { .ctl_name = CTL_DUMP_DEVICE,
4780 +         .procname = DUMP_DEVICE_NAME,
4781 +         .mode = 0644,
4782 +         .data = &dump_config.dump_device, /* FIXME */
4783 +         .maxlen = sizeof(int),
4784 +         .proc_handler = proc_dump_device },
4785 +
4786 +#ifdef CONFIG_CRASH_DUMP_MEMDEV
4787 +       { .ctl_name = CTL_DUMP_ADDR,
4788 +         .procname = DUMP_ADDR_NAME,
4789 +         .mode = 0444,
4790 +         .data = &dump_config.dump_addr,
4791 +         .maxlen = sizeof(unsigned long),
4792 +         .proc_handler = proc_doulonghex },
4793 +#endif
4794 +
4795 +       { 0, }
4796 +};
4797 +
4798 +static ctl_table dump_root[] = {
4799 +       { .ctl_name = KERN_DUMP,
4800 +         .procname = "dump",
4801 +         .mode = 0555, 
4802 +         .child = dump_table },
4803 +       { 0, }
4804 +};
4805 +
4806 +static ctl_table kernel_root[] = {
4807 +       { .ctl_name = CTL_KERN,
4808 +         .procname = "kernel",
4809 +         .mode = 0555,
4810 +         .child = dump_root, },
4811 +       { 0, }
4812 +};
4813 +
4814 +static struct ctl_table_header *sysctl_header;
4815 +
4816 +/*
4817 + * -----------------------------------------------------------------------
4818 + *              C O M P R E S S I O N   F U N C T I O N S
4819 + * -----------------------------------------------------------------------
4820 + */
4821 +
4822 +/*
4823 + * Name: dump_compress_none()
4824 + * Func: Don't do any compression, period.
4825 + */
4826 +static u16
4827 +dump_compress_none(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
4828 +{
4829 +       /* just return the old size */
4830 +       return oldsize;
4831 +}
4832 +
4833 +
4834 +/*
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.
4839 + */
4840 +void
4841 +dump_execute(const char *panic_str, const struct pt_regs *regs)
4842 +{
4843 +       int state = -1;
4844 +       unsigned long flags;
4845 +
4846 +       /* make sure we can dump */
4847 +       if (!dump_okay) {
4848 +               pr_info("LKCD not yet configured, can't take dump now\n");
4849 +               return;
4850 +       }
4851 +
4852 +       /* Exclude multiple dumps at the same time,
4853 +        * and disable interrupts,  some drivers may re-enable
4854 +        * interrupts in with silence()
4855 +        *
4856 +        * Try and acquire spin lock. If successful, leave preempt
4857 +        * and interrupts disabled.  See spin_lock_irqsave in spinlock.h
4858 +        */
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");
4863 +               return;
4864 +       }
4865 +
4866 +       /* Bring system into the strictest level of quiescing for min drift 
4867 +        * dump drivers can soften this as required in dev->ops->silence() 
4868 +        */
4869 +       dump_oncpu = smp_processor_id() + 1;
4870 +       dump_silence_level = DUMP_HARD_SPIN_CPUS; 
4871 +
4872 +       state = dump_generic_execute(panic_str, regs);
4873 +       
4874 +       dump_oncpu = 0;
4875 +       spin_unlock_irqrestore(&dump_lock, flags);
4876 +
4877 +       if (state < 0) {
4878 +               printk("Dump Incomplete or failed!\n");
4879 +       } else {
4880 +               printk("Dump Complete; %d dump pages saved.\n", 
4881 +                      dump_header.dh_num_dump_pages);
4882 +       }
4883 +}
4884 +
4885 +/*
4886 + * Name: dump_register_compression()
4887 + * Func: Register a dump compression mechanism.
4888 + */
4889 +void
4890 +dump_register_compression(struct __dump_compress *item)
4891 +{
4892 +       if (item)
4893 +               list_add(&(item->list), &dump_compress_list);
4894 +}
4895 +
4896 +/*
4897 + * Name: dump_unregister_compression()
4898 + * Func: Remove a dump compression mechanism, and re-assign the dump
4899 + *       compression pointer if necessary.
4900 + */
4901 +void
4902 +dump_unregister_compression(int compression_type)
4903 +{
4904 +       struct list_head *tmp;
4905 +       struct __dump_compress *dc;
4906 +
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));
4913 +                               break;
4914 +                       }
4915 +               }
4916 +       }
4917 +}
4918 +
4919 +/*
4920 + * Name: dump_compress_init()
4921 + * Func: Initialize (or re-initialize) compression scheme.
4922 + */
4923 +static int
4924 +dump_compress_init(int compression_type)
4925 +{
4926 +       struct list_head *tmp;
4927 +       struct __dump_compress *dc;
4928 +
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);
4936 +                       return 0;
4937 +               }
4938 +       }
4939 +
4940 +       /* 
4941 +        * nothing on the list -- return ENODATA to indicate an error 
4942 +        *
4943 +        * NB: 
4944 +        *      EAGAIN: reports "Resource temporarily unavailable" which
4945 +        *              isn't very enlightening.
4946 +        */
4947 +       printk("compression_type:%d not found\n", compression_type);
4948 +
4949 +       return -ENODATA;
4950 +}
4951 +
4952 +static int
4953 +dumper_setup(unsigned long flags, unsigned long devid)
4954 +{
4955 +       int ret = 0;
4956 +
4957 +       /* unconfigure old dumper if it exists */
4958 +       dump_okay = 0;
4959 +       if (dump_config.dumper) {
4960 +               pr_debug("Unconfiguring current dumper\n");
4961 +               dump_unconfigure();
4962 +       }
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; 
4968 +#else
4969 +               printk("Requires CONFIG_CRASHDUMP_MEMDEV. Can't proceed.\n");
4970 +               return -1;
4971 +#endif
4972 +       } else {
4973 +               dump_config.dumper = &dumper_singlestage;
4974 +       }       
4975 +       dump_config.dumper->dev = dump_dev;
4976 +
4977 +       ret = dump_configure(devid);
4978 +       if (!ret) {
4979 +               dump_okay = 1;
4980 +               pr_debug("%s dumper set up for dev 0x%lx\n", 
4981 +                       dump_config.dumper->name, devid);
4982 +               dump_config.dump_device = devid;
4983 +       } else {
4984 +               printk("%s dumper set up failed for dev 0x%lx\n", 
4985 +                      dump_config.dumper->name, devid);
4986 +               dump_config.dumper = NULL;
4987 +       }
4988 +       return ret;
4989 +}
4990 +
4991 +static int
4992 +dump_target_init(int target)
4993 +{
4994 +       char type[20];
4995 +       struct list_head *tmp;
4996 +       struct dump_dev *dev;
4997 +       
4998 +       switch (target) {
4999 +               case DUMP_FLAGS_DISKDUMP:
5000 +                       strcpy(type, "blockdev"); break;
5001 +               case DUMP_FLAGS_NETDUMP:
5002 +                       strcpy(type, "networkdev"); break;
5003 +               default:
5004 +                       return -1;
5005 +       }
5006 +
5007 +       /*
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'.
5011 +        */
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) {
5015 +                       dump_dev = dev;
5016 +                       return 0;
5017 +               }
5018 +       }
5019 +       return -1;
5020 +}
5021 +
5022 +/*
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.
5027 + */
5028 +static int
5029 +dump_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
5030 +{
5031 +       /* check capabilities */
5032 +       if (!capable(CAP_SYS_ADMIN))
5033 +               return -EPERM;
5034 +
5035 +       if (!dump_config.dumper && cmd == DIOSDUMPCOMPRESS)
5036 +               /* dump device must be configured first */
5037 +               return -ENODEV;
5038 +
5039 +       /*
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.
5044 +        */
5045 +       switch (cmd) {
5046 +       case DIOSDUMPDEV:       /* set dump_device */
5047 +               pr_debug("Configuring dump device\n"); 
5048 +               if (!(f->f_flags & O_RDWR))
5049 +                       return -EPERM;
5050 +
5051 +               __dump_open();
5052 +               return dumper_setup(dump_config.flags, arg);
5053 +
5054 +               
5055 +       case DIOGDUMPDEV:       /* get dump_device */
5056 +               return put_user((long)dump_config.dump_device, (long *)arg);
5057 +
5058 +       case DIOSDUMPLEVEL:     /* set dump_level */
5059 +               if (!(f->f_flags & O_RDWR))
5060 +                       return -EPERM;
5061 +
5062 +               /* make sure we have a positive value */
5063 +               if (arg < 0)
5064 +                       return -EINVAL;
5065 +
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:
5079 +                               break;
5080 +                       default:
5081 +                               return (-EINVAL);
5082 +                       }
5083 +               pr_debug("Dump Level 0x%lx\n", dump_config.level);
5084 +               break;
5085 +
5086 +       case DIOGDUMPLEVEL:     /* get dump_level */
5087 +               /* fixme: handle conversion */
5088 +               return put_user((long)dump_config.level, (long *)arg);
5089 +
5090 +               
5091 +       case DIOSDUMPFLAGS:     /* set dump_flags */
5092 +               /* check flags */
5093 +               if (!(f->f_flags & O_RDWR))
5094 +                       return -EPERM;
5095 +
5096 +               /* make sure we have a positive value */
5097 +               if (arg < 0)
5098 +                       return -EINVAL;
5099 +                       
5100 +               if (dump_target_init(arg & DUMP_FLAGS_TARGETMASK) < 0)
5101 +                       return -EINVAL; /* return proper error */
5102 +
5103 +               dump_config.flags = arg;
5104 +               
5105 +               pr_debug("Dump Flags 0x%lx\n", dump_config.flags);
5106 +               break;
5107 +               
5108 +       case DIOGDUMPFLAGS:     /* get dump_flags */
5109 +               return put_user((long)dump_config.flags, (long *)arg);
5110 +
5111 +       case DIOSDUMPCOMPRESS:  /* set the dump_compress status */
5112 +               if (!(f->f_flags & O_RDWR))
5113 +                       return -EPERM;
5114 +
5115 +               return dump_compress_init((int)arg);
5116 +
5117 +       case DIOGDUMPCOMPRESS:  /* get the dump_compress status */
5118 +               return put_user((long)(dump_config.dumper ? 
5119 +                       dump_config.dumper->compress->compress_type : 0), 
5120 +                       (long *)arg);
5121 +                       
5122 +       default:
5123 +               /* 
5124 +                * these are network dump specific ioctls, let the
5125 +                * module handle them.
5126 +                */
5127 +               return dump_dev_ioctl(cmd, arg);
5128 +       }
5129 +       return 0;
5130 +}
5131 +
5132 +/*
5133 + * Handle special cases for dump_device 
5134 + * changing dump device requires doing an opening the device
5135 + */
5136 +static int 
5137 +proc_dump_device(ctl_table *ctl, int write, struct file *f,
5138 +                void *buffer, size_t *lenp)
5139 +{
5140 +       int *valp = ctl->data;
5141 +       int oval = *valp;
5142 +       int ret = -EPERM;
5143 +
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;
5150 +                       __dump_open();
5151 +                       ret = dumper_setup(dump_config.flags, (dev_t) *valp);
5152 +               }
5153 +       }
5154 +
5155 +       return ret;
5156 +}
5157 +
5158 +/* All for the want of a proc_do_xxx routine which prints values in hex */
5159 +static int 
5160 +proc_doulonghex(ctl_table *ctl, int write, struct file *f,
5161 +                void *buffer, size_t *lenp)
5162 +{
5163 +#define TMPBUFLEN 20
5164 +       unsigned long *i;
5165 +       size_t len, left;
5166 +       char buf[TMPBUFLEN];
5167 +
5168 +       if (!ctl->data || !ctl->maxlen || !*lenp || (f->f_pos)) {
5169 +               *lenp = 0;
5170 +               return 0;
5171 +       }
5172 +       
5173 +       i = (unsigned long *) ctl->data;
5174 +       left = *lenp;
5175 +       
5176 +       sprintf(buf, "0x%lx\n", (*i));
5177 +       len = strlen(buf);
5178 +       if (len > left)
5179 +               len = left;
5180 +       if(copy_to_user(buffer, buf, len))
5181 +               return -EFAULT;
5182 +       
5183 +       left -= len;
5184 +       *lenp -= left;
5185 +       f->f_pos += *lenp;
5186 +       return 0;
5187 +}
5188 +
5189 +/*
5190 + * -----------------------------------------------------------------------
5191 + *                     I N I T   F U N C T I O N S
5192 + * -----------------------------------------------------------------------
5193 + */
5194 +
5195 +/*
5196 + * These register and unregister routines are exported for modules
5197 + * to register their dump drivers (like block, net etc)
5198 + */
5199 +int
5200 +dump_register_device(struct dump_dev *ddev)
5201 +{
5202 +       struct list_head *tmp;
5203 +       struct dump_dev *dev;
5204 +
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",
5209 +                                       dev->type_name);
5210 +                       return -1; /* return proper error */
5211 +               }
5212 +       }
5213 +       list_add(&(ddev->list), &dump_target_list);
5214 +       
5215 +       return 0;
5216 +}
5217 +
5218 +void
5219 +dump_unregister_device(struct dump_dev *ddev)
5220 +{
5221 +       list_del(&(ddev->list));
5222 +       if (ddev != dump_dev)
5223 +               return;
5224 +
5225 +       dump_okay = 0;
5226 +
5227 +       if (dump_config.dumper)
5228 +               dump_unconfigure();
5229 +
5230 +       dump_config.flags &= ~DUMP_FLAGS_TARGETMASK;
5231 +       dump_okay = 0;
5232 +       dump_dev = NULL;
5233 +       dump_config.dumper = NULL;
5234 +}
5235 +
5236 +static int panic_event(struct notifier_block *this, unsigned long event,
5237 +                      void *ptr)
5238 +{
5239 +       struct pt_regs regs;
5240 +
5241 +       get_current_regs(&regs);
5242 +       dump_execute((const char *)ptr, &regs);
5243 +       return 0;
5244 +}
5245 +
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,
5250 +};
5251 +
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);
5257 +}
5258 +
5259 +static struct sysrq_key_op sysrq_crashdump_op = {
5260 +       .handler        =       sysrq_handle_crashdump,
5261 +       .help_msg       =       "Dump",
5262 +       .action_msg     =       "Starting crash dump",
5263 +};
5264 +#endif
5265 +
5266 +static inline void
5267 +dump_sysrq_register(void) 
5268 +{
5269 +#ifdef CONFIG_MAGIC_SYSRQ
5270 +       __sysrq_lock_table();
5271 +       __sysrq_put_key_op(DUMP_SYSRQ_KEY, &sysrq_crashdump_op);
5272 +       __sysrq_unlock_table();
5273 +#endif
5274 +}
5275 +
5276 +static inline void
5277 +dump_sysrq_unregister(void)
5278 +{
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();
5284 +#endif
5285 +}
5286 +
5287 +/*
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.
5293 + */
5294 +static int __init
5295 +dump_init(void)
5296 +{
5297 +       struct sysinfo info;
5298 +
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");
5302 +               return -EBUSY;
5303 +       }
5304 +
5305 +       __dump_init((u64)PAGE_OFFSET);
5306 +
5307 +       /* set the dump_compression_list structure up */
5308 +       dump_register_compression(&dump_none_compression);
5309 +
5310 +       /* grab the total memory size now (not if/when we crash) */
5311 +       si_meminfo(&info);
5312 +
5313 +       /* set the memory size */
5314 +       dump_header.dh_memory_size = (u64)info.totalram;
5315 +
5316 +       sysctl_header = register_sysctl_table(kernel_root, 0);
5317 +       dump_sysrq_register();
5318 +
5319 +       notifier_chain_register(&panic_notifier_list, &panic_block);
5320 +       dump_function_ptr = dump_execute;
5321 +
5322 +       pr_info("Crash dump driver initialized.\n");
5323 +       return 0;
5324 +}
5325 +
5326 +static void __exit
5327 +dump_cleanup(void)
5328 +{
5329 +       dump_okay = 0;
5330 +
5331 +       if (dump_config.dumper)
5332 +               dump_unconfigure();
5333 +
5334 +       /* arch-specific cleanup routine */
5335 +       __dump_cleanup();
5336 +
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;
5343 +}
5344 +
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);
5351 +
5352 +EXPORT_SYMBOL(__dump_irq_enable);
5353 +EXPORT_SYMBOL(__dump_irq_restore);
5354 +
5355 +MODULE_AUTHOR("Matt D. Robinson <yakker@sourceforge.net>");
5356 +MODULE_DESCRIPTION("Linux Kernel Crash Dump (LKCD) driver");
5357 +MODULE_LICENSE("GPL");
5358 +
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
5365 @@ -0,0 +1,161 @@
5366 +/*
5367 + * Generic dump device interfaces for flexible system dump 
5368 + * (Enables variation of dump target types e.g disk, network, memory)
5369 + *
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 
5374 + * dump i/o.
5375 + *
5376 + * Started: Oct 2002 - Suparna Bhattacharya (suparna@in.ibm.com)
5377 + *
5378 + * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
5379 + * Copyright (C) 2002 International Business Machines Corp. 
5380 + *
5381 + * This code is released under version 2 of the GNU GPL.
5382 + */
5383 +
5384 +#ifndef _LINUX_DUMPDEV_H
5385 +#define _LINUX_DUMPDEV_H
5386 +
5387 +#include <linux/kernel.h>
5388 +#include <linux/wait.h>
5389 +#include <linux/bio.h>
5390 +
5391 +/* Determined by the dump target (device) type */
5392 +
5393 +struct dump_dev;
5394 +
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);
5408 +};
5409 +
5410 +struct dump_dev {
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;
5416 +};
5417 +
5418 +/*
5419 + * dump_dev type variations: 
5420 + */
5421 +
5422 +/* block */
5423 +struct dump_blockdev {
5424 +       struct dump_dev ddev;
5425 +       dev_t kdev_id;
5426 +       struct block_device *bdev;
5427 +       struct bio *bio;
5428 +       loff_t start_offset;
5429 +       loff_t limit;
5430 +       int err;
5431 +};
5432 +
5433 +static inline struct dump_blockdev *DUMP_BDEV(struct dump_dev *dev)
5434 +{
5435 +       return container_of(dev, struct dump_blockdev, ddev);
5436 +}
5437 +
5438 +
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;
5450 +};     
5451 +
5452 +static inline struct dump_memdev *DUMP_MDEV(struct dump_dev *dev)
5453 +{
5454 +       return container_of(dev, struct dump_memdev, ddev);
5455 +}
5456 +
5457 +/* Todo/future - meant for raw dedicated interfaces e.g. mini-ide driver */
5458 +struct dump_rdev {
5459 +       struct dump_dev ddev;
5460 +       char name[32];
5461 +       int (*reset)(struct dump_rdev *, unsigned int, 
5462 +               unsigned long);
5463 +       /* ... to do ... */
5464 +};
5465 +
5466 +/* just to get the size right when saving config across a soft-reboot */
5467 +struct dump_anydev {
5468 +       union {
5469 +               struct dump_blockdev bddev;
5470 +               /* .. add other types here .. */
5471 +       };
5472 +};
5473 +
5474 +
5475 +
5476 +/* Dump device / target operation wrappers */
5477 +/* These assume that dump_dev is initiatized to dump_config.dumper->dev */
5478 +
5479 +extern struct dump_dev *dump_dev;
5480 +
5481 +static inline int dump_dev_open(unsigned long arg)
5482 +{
5483 +       return dump_dev->ops->open(dump_dev, arg);
5484 +}
5485 +
5486 +static inline int dump_dev_release(void)
5487 +{
5488 +       return dump_dev->ops->release(dump_dev);
5489 +}
5490 +
5491 +static inline int dump_dev_silence(void)
5492 +{
5493 +       return dump_dev->ops->silence(dump_dev);
5494 +}
5495 +
5496 +static inline int dump_dev_resume(void)
5497 +{
5498 +       return dump_dev->ops->resume(dump_dev);
5499 +}
5500 +
5501 +static inline int dump_dev_seek(loff_t offset)
5502 +{
5503 +       return dump_dev->ops->seek(dump_dev, offset);
5504 +}
5505 +
5506 +static inline int dump_dev_write(void *buf, unsigned long len)
5507 +{
5508 +       return dump_dev->ops->write(dump_dev, buf, len);
5509 +}
5510 +
5511 +static inline int dump_dev_ready(void *buf)
5512 +{
5513 +       return dump_dev->ops->ready(dump_dev, buf);
5514 +}
5515 +
5516 +static inline int dump_dev_ioctl(unsigned int cmd, unsigned long arg)
5517 +{
5518 +       if (!dump_dev->ops->ioctl)
5519 +               return -EINVAL;
5520 +       return dump_dev->ops->ioctl(dump_dev, cmd, arg);
5521 +}
5522 +
5523 +extern int dump_register_device(struct dump_dev *);
5524 +extern void dump_unregister_device(struct dump_dev *);
5525 +
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
5531 @@ -0,0 +1,376 @@
5532 +/*
5533 + * Kernel header file for Linux crash dumps.
5534 + *
5535 + * Created by: Matt Robinson (yakker@sgi.com)
5536 + * Copyright 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
5537 + *
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.
5541 + *
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).
5546 + *
5547 + * This code is released under version 2 of the GNU GPL.
5548 + */
5549 +
5550 +/* This header file includes all structure definitions for crash dumps. */
5551 +#ifndef _DUMP_H
5552 +#define _DUMP_H
5553 +
5554 +#if defined(CONFIG_CRASH_DUMP) || defined (CONFIG_CRASH_DUMP_MODULE)
5555 +
5556 +#include <linux/list.h>
5557 +#include <linux/notifier.h>
5558 +#include <linux/dumpdev.h>
5559 +
5560 +/* 
5561 + * Predefine default DUMP_PAGE constants, asm header may override.
5562 + *
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.
5566 + */
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
5571 +
5572 +/* keep DUMP_PAGE_SIZE constant to 4K = 1<<12
5573 + * it may be different from PAGE_SIZE then.
5574 + */
5575 +#define DUMP_PAGE_SIZE         4096
5576 +
5577 +/* 
5578 + * Predefined default memcpy() to use when copying memory to the dump buffer.
5579 + *
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.
5584 + */
5585 +#define DUMP_memcpy            memcpy
5586 +
5587 +/* necessary header files */
5588 +#include <asm/dump.h>                  /* for architecture-specific header */
5589 +
5590 +/* 
5591 + * Size of the buffer that's used to hold:
5592 + *
5593 + *     1. the dump header (padded to fill the complete buffer)
5594 + *     2. the possibly compressed page headers and data
5595 + */
5596 +#define DUMP_BUFFER_SIZE       (64 * 1024)  /* size of dump buffer         */
5597 +#define DUMP_HEADER_SIZE       DUMP_BUFFER_SIZE
5598 +
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         */
5604 +
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 */
5612 +
5613 +
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             */
5618 +
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     */
5622 +
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         */
5626 +
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        */
5635 +
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"
5643 +
5644 +#define DUMP_SYSRQ_KEY         'd'     /* key to use for MAGIC_SYSRQ key   */
5645 +
5646 +/* CTL_DUMP names: */
5647 +enum
5648 +{
5649 +       CTL_DUMP_DEVICE=1,
5650 +       CTL_DUMP_COMPRESS=3,
5651 +       CTL_DUMP_LEVEL=3,
5652 +       CTL_DUMP_FLAGS=4,
5653 +       CTL_DUMP_ADDR=5,
5654 +       CTL_DUMP_TEST=6,
5655 +};
5656 +
5657 +
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)
5660 +
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      */
5670 +
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             */
5680 +
5681 +/*
5682 + * Structure: __dump_header
5683 + *  Function: This is the header dumped at the top of every valid crash
5684 + *            dump.  
5685 + */
5686 +struct __dump_header {
5687 +       /* the dump magic number -- unique to verify dump is valid */
5688 +       u64     dh_magic_number;
5689 +
5690 +       /* the version number of this dump */
5691 +       u32     dh_version;
5692 +
5693 +       /* the size of this header (in case we can't read it) */
5694 +       u32     dh_header_size;
5695 +
5696 +       /* the level of this dump (just a header?) */
5697 +       u32     dh_dump_level;
5698 +
5699 +       /* 
5700 +        * We assume dump_page_size to be 4K in every case.
5701 +        * Store here the configurable system page size (4K, 8K, 16K, etc.) 
5702 +        */
5703 +       u32     dh_page_size;
5704 +
5705 +       /* the size of all physical memory */
5706 +       u64     dh_memory_size;
5707 +
5708 +       /* the start of physical memory */
5709 +       u64     dh_memory_start;
5710 +
5711 +       /* the end of physical memory */
5712 +       u64     dh_memory_end;
5713 +
5714 +       /* the number of hardware/physical pages in this dump specifically */
5715 +       u32     dh_num_dump_pages;
5716 +
5717 +       /* the panic string, if available */
5718 +       char    dh_panic_string[DUMP_PANIC_LEN];
5719 +
5720 +       /* timeval depends on architecture, two long values */
5721 +       struct {
5722 +               u64 tv_sec;
5723 +               u64 tv_usec;
5724 +       } dh_time; /* the time of the system crash */
5725 +
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];
5736 +
5737 +       /* the address of current task (OLD = void *, NEW = u64) */
5738 +       u64     dh_current_task;
5739 +
5740 +       /* what type of compression we're using in this dump (if any) */
5741 +       u32     dh_dump_compress;
5742 +
5743 +       /* any additional flags */
5744 +       u32     dh_dump_flags;
5745 +
5746 +       /* any additional flags */
5747 +       u32     dh_dump_device;
5748 +} __attribute__((packed));
5749 +
5750 +/*
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
5756 + *            conversions.
5757 + *
5758 + * dp_byte_offset and dp_page_index are landmarks that are helpful when
5759 + * looking at a hex dump of /dev/vmdump,
5760 + */
5761 +struct __dump_page {
5762 +       /* the address of this dump page */
5763 +       u64     dp_address;
5764 +
5765 +       /* the size of this dump page */
5766 +       u32     dp_size;
5767 +
5768 +       /* flags (currently DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */
5769 +       u32     dp_flags;
5770 +} __attribute__((packed));
5771 +
5772 +/*
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.
5777 + */
5778 +struct __lkcdinfo {
5779 +       int     arch;
5780 +       int     ptrsz;
5781 +       int     byte_order;
5782 +       int     linux_release;
5783 +       int     page_shift;
5784 +       int     page_size;
5785 +       u64     page_mask;
5786 +       u64     page_offset;
5787 +       int     stack_offset;
5788 +};
5789 +
5790 +#ifdef __KERNEL__
5791 +
5792 +/*
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.
5798 + */
5799 +struct __dump_compress {
5800 +       /* the list_head structure for list storage */
5801 +       struct list_head list;
5802 +
5803 +       /* the type of compression to use (DUMP_COMPRESS_XXX) */
5804 +       int compress_type;
5805 +       const char *compress_name;
5806 +
5807 +       /* the compression function to call */
5808 +       u16 (*compress_func)(const u8 *, u16, u8 *, u16);
5809 +};
5810 +
5811 +/* functions for dump compression registration */
5812 +extern void dump_register_compression(struct __dump_compress *);
5813 +extern void dump_unregister_compression(int);
5814 +
5815 +/*
5816 + * Structure dump_mbank[]:
5817 + *
5818 + * For CONFIG_DISCONTIGMEM systems this array specifies the
5819 + * memory banks/chunks that need to be dumped after a panic.
5820 + *
5821 + * For classic systems it specifies a single set of pages from
5822 + * 0 to max_mapnr.
5823 + */
5824 +struct __dump_mbank {
5825 +       u64     start;
5826 +       u64     end;
5827 +       int     type;
5828 +       int     pad1;
5829 +       long    pad2;
5830 +};
5831 +
5832 +#define DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY            1
5833 +#define DUMP_MBANK_TYPE_OTHER                          2
5834 +
5835 +#define MAXCHUNKS 256
5836 +extern int dump_mbanks;
5837 +extern struct __dump_mbank dump_mbank[MAXCHUNKS];
5838 +
5839 +/* notification event codes */
5840 +#define DUMP_BEGIN             0x0001  /* dump beginning */
5841 +#define DUMP_END               0x0002  /* dump ending */
5842 +
5843 +/* Scheduler soft spin control.
5844 + *
5845 + * 0 - no dump in progress
5846 + * 1 - cpu0 is dumping, ...
5847 + */
5848 +extern unsigned long dump_oncpu;
5849 +extern void dump_execute(const char *, const struct pt_regs *);
5850 +
5851 +/*
5852 + *     Notifier list for kernel code which wants to be called
5853 + *     at kernel dump. 
5854 + */
5855 +extern struct notifier_block *dump_notifier_list;
5856 +static inline int register_dump_notifier(struct notifier_block *nb)
5857 +{
5858 +       return notifier_chain_register(&dump_notifier_list, nb);
5859 +}
5860 +static inline int unregister_dump_notifier(struct notifier_block * nb)
5861 +{
5862 +       return notifier_chain_unregister(&dump_notifier_list, nb);
5863 +}
5864 +
5865 +extern void (*dump_function_ptr)(const char *, const struct pt_regs *);
5866 +static inline void dump(char * str, struct pt_regs * regs)
5867 +{
5868 +       if (dump_function_ptr)
5869 +               dump_function_ptr(str, regs);
5870 +}
5871 +
5872 +/*
5873 + * Common Arch Specific Functions should be declared here.
5874 + * This allows the C compiler to detect discrepancies.
5875 + */
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);
5884 +#ifdef CONFIG_SMP
5885 +extern void    __dump_save_other_cpus(void);
5886 +#else
5887 +#define        __dump_save_other_cpus()
5888 +#endif
5889 +
5890 +/* to track all used (compound + zero order) pages */
5891 +#define PageInuse(p)   (PageCompound(p) || page_count(p))
5892 +
5893 +#endif /* __KERNEL__ */
5894 +
5895 +#else  /* !CONFIG_CRASH_DUMP */
5896 +
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)
5904 +
5905 +#endif /* !CONFIG_CRASH_DUMP */
5906 +
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
5912 @@ -0,0 +1,82 @@
5913 +/*
5914 + *  linux/drivers/net/netconsole.h
5915 + *
5916 + *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
5917 + *
5918 + *  This file contains the implementation of an IRQ-safe, crash-safe
5919 + *  kernel console implementation that outputs kernel messages to the
5920 + *  network.
5921 + *
5922 + * Modification history:
5923 + *
5924 + * 2001-09-17    started by Ingo Molnar.
5925 + */
5926 +
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.
5932 + *
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.
5937 + *
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.
5941 + *
5942 + ****************************************************************/
5943 +
5944 +#define NETCONSOLE_VERSION 0x03
5945 +
5946 +enum netdump_commands {
5947 +       COMM_NONE = 0,
5948 +       COMM_SEND_MEM = 1,
5949 +       COMM_EXIT = 2,
5950 +       COMM_REBOOT = 3,
5951 +       COMM_HELLO = 4,
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,
5958 +       COMM_SYSRQ = 11,
5959 +};
5960 +
5961 +typedef struct netdump_req_s {
5962 +       u64 magic;
5963 +       u32 nr;
5964 +       u32 command;
5965 +       u32 from;
5966 +       u32 to;
5967 +} req_t;
5968 +
5969 +enum netdump_replies {
5970 +       REPLY_NONE = 0,
5971 +       REPLY_ERROR = 1,
5972 +       REPLY_LOG = 2,
5973 +       REPLY_MEM = 3,
5974 +       REPLY_RESERVED = 4,
5975 +       REPLY_HELLO = 5,
5976 +       REPLY_NR_PAGES = 6,
5977 +       REPLY_PAGE_SIZE = 7,
5978 +       REPLY_START_NETDUMP = 8,
5979 +       REPLY_END_NETDUMP = 9,
5980 +       REPLY_REGS = 10,
5981 +       REPLY_MAGIC = 11,
5982 +       REPLY_START_WRITE_NETDUMP = 12,
5983 +       REPLY_SYSRQ = 13,
5984 +};
5985 +
5986 +typedef struct netdump_reply_s {
5987 +       u32 nr;
5988 +       u32 code;
5989 +       u32 info;
5990 +} reply_t;
5991 +
5992 +#define HEADER_LEN (1 + sizeof(reply_t))
5993 +
5994 +
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
5999 @@ -0,0 +1,93 @@
6000 +/*
6001 + * Kernel header file for Linux crash dumps.
6002 + *
6003 + * Created by: Matt Robinson (yakker@sgi.com)
6004 + *
6005 + * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
6006 + *
6007 + * This code is released under version 2 of the GNU GPL.
6008 + */
6009 +
6010 +/* This header file holds the architecture specific crash dump header */
6011 +#ifndef _ASM_DUMP_H
6012 +#define _ASM_DUMP_H
6013 +
6014 +/* necessary header files */
6015 +#include <asm/ptrace.h>
6016 +#include <asm/page.h>
6017 +#include <linux/threads.h>
6018 +#include <linux/mm.h>
6019 +
6020 +/* definitions */
6021 +#define DUMP_ASM_MAGIC_NUMBER  0xdeaddeadULL   /* magic number            */
6022 +#define DUMP_ASM_VERSION_NUMBER        0x3     /* version number          */
6023 +
6024 +/* max number of cpus */
6025 +#define DUMP_MAX_NUM_CPUS 32
6026 +
6027 +/*
6028 + * Structure: __dump_header_asm
6029 + *  Function: This is the header for architecture-specific stuff.  It
6030 + *            follows right after the dump header.
6031 + */
6032 +struct __dump_header_asm {
6033 +       /* the dump magic number -- unique to verify dump is valid */
6034 +       u64             dha_magic_number;
6035 +
6036 +       /* the version number of this dump */
6037 +       u32             dha_version;
6038 +
6039 +       /* the size of this header (in case we can't read it) */
6040 +       u32             dha_header_size;
6041 +
6042 +       /* the esp for i386 systems */
6043 +       u32             dha_esp;
6044 +
6045 +       /* the eip for i386 systems */
6046 +       u32             dha_eip;
6047 +
6048 +       /* the dump registers */
6049 +       struct pt_regs  dha_regs;
6050 +
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));
6059 +
6060 +#ifdef __KERNEL__
6061 +
6062 +extern struct __dump_header_asm dump_header_asm;
6063 +
6064 +#ifdef CONFIG_SMP
6065 +extern cpumask_t irq_affinity[];
6066 +extern int (*dump_ipi_function_ptr)(struct pt_regs *);
6067 +extern void dump_send_ipi(void);
6068 +#else
6069 +#define dump_send_ipi() do { } while(0)
6070 +#endif
6071 +
6072 +static inline void get_current_regs(struct pt_regs *regs)
6073 +{
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();
6088 +}
6089 +
6090 +#endif /* __KERNEL__ */
6091 +
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
6097 @@ -0,0 +1,31 @@
6098 +/*
6099 + * kerntypes.c
6100 + *
6101 + * Copyright (C) 2000 Tom Morano (tjm@sgi.com) and
6102 + *                    Matt D. Robinson (yakker@alacritech.com)
6103 + *
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.
6109 + *
6110 + * This source code is released under version 2 of the GNU GPL.
6111 + */
6112 +
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>
6119 +
6120 +#ifdef LINUX_COMPILE_VERSION_ID_TYPE
6121 +/* Define version type for version validation of dump and kerntypes */
6122 +LINUX_COMPILE_VERSION_ID_TYPE;
6123 +#endif
6124 +
6125 +void
6126 +kerntypes_dummy(void)
6127 +{
6128 +}
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
6133 @@ -0,0 +1,348 @@
6134 +/*
6135 + * Generic interfaces for flexible system dump 
6136 + *
6137 + * Started: Oct 2002 -  Suparna Bhattacharya (suparna@in.ibm.com)
6138 + *
6139 + * Copyright (C) 2002 International Business Machines Corp. 
6140 + *
6141 + * This code is released under version 2 of the GNU GPL.
6142 + */
6143 +
6144 +#ifndef _LINUX_DUMP_METHODS_H
6145 +#define _LINUX_DUMP_METHODS_H
6146 +
6147 +/*
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.
6151 + *
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).
6159 + * 
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.
6167 + *
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
6172 + * them.
6173 + */
6174 +
6175 +#include <linux/sched.h>
6176 +#include <linux/slab.h>
6177 +#include <linux/highmem.h>
6178 +#include <linux/dumpdev.h>
6179 +
6180 +#define MAX_PASSES     6
6181 +#define MAX_DEVS       4
6182 +
6183 +
6184 +/* To customise selection of pages to be dumped in a given pass/group */
6185 +struct dump_data_filter{
6186 +       char name[32];
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 */
6190 +};
6191 +
6192 +
6193 +/* 
6194 + * Determined by the kind of dump mechanism and appropriate 
6195 + * overall scheme 
6196 + */ 
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); 
6202 +
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); 
6214 +};
6215 +
6216 +struct dump_scheme {
6217 +       /* the name serves as an anchor to locate the scheme after reboot */
6218 +       char name[32]; 
6219 +       struct dump_scheme_ops *ops;
6220 +       struct list_head list;
6221 +};
6222 +
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;
6229 +
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);
6242 +};
6243 +
6244 +struct dump_fmt {
6245 +       unsigned long magic; 
6246 +       char name[32];  /* lcrash, crash, elf-core etc */
6247 +       struct dump_fmt_ops *ops;
6248 +       struct list_head list;
6249 +};
6250 +
6251 +/* 
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.
6255 + * Still Todo.
6256 + */
6257 +
6258 +/* The combined dumper profile (mechanism, scheme, dev, fmt) */
6259 +struct dumper {
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 */
6268 +       int curr_pass;
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 */
6275 +       int header_len; 
6276 +       struct list_head dumper_list; /* links to other dumpers */
6277 +};     
6278 +
6279 +/* Starting point to get to the current configured state */
6280 +struct dump_config {
6281 +       ulong level;
6282 +       ulong flags;
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;
6287 +};     
6288 +
6289 +extern struct dump_config dump_config;
6290 +
6291 +/* Used to save the dump config across a reboot for 2-stage dumps: 
6292 + * 
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.
6297 + */
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 */
6308 +};
6309 +
6310 +
6311 +/* Wrappers that invoke the methods for the current (active) dumper */
6312 +
6313 +/* Scheme operations */
6314 +
6315 +static inline int dump_sequencer(void)
6316 +{
6317 +       return dump_config.dumper->scheme->ops->sequencer();
6318 +}
6319 +
6320 +static inline int dump_iterator(int pass, int (*action)(unsigned long, 
6321 +       unsigned long), struct dump_data_filter *filter)
6322 +{
6323 +       return dump_config.dumper->scheme->ops->iterator(pass, action, filter);
6324 +}
6325 +
6326 +#define dump_save_data dump_config.dumper->scheme->ops->save_data
6327 +#define dump_skip_data dump_config.dumper->scheme->ops->skip_data
6328 +
6329 +static inline int dump_write_buffer(void *buf, unsigned long len)
6330 +{
6331 +       return dump_config.dumper->scheme->ops->write_buffer(buf, len);
6332 +}
6333 +
6334 +static inline int dump_configure(unsigned long devid)
6335 +{
6336 +       return dump_config.dumper->scheme->ops->configure(devid);
6337 +}
6338 +
6339 +static inline int dump_unconfigure(void)
6340 +{
6341 +       return dump_config.dumper->scheme->ops->unconfigure();
6342 +}
6343 +
6344 +/* Format operations */
6345 +
6346 +static inline int dump_configure_header(const char *panic_str, 
6347 +       const struct pt_regs *regs)
6348 +{
6349 +       return dump_config.dumper->fmt->ops->configure_header(panic_str, regs);
6350 +}
6351 +
6352 +static inline void dump_save_context(int cpu, const struct pt_regs *regs, 
6353 +               struct task_struct *tsk)
6354 +{
6355 +       dump_config.dumper->fmt->ops->save_context(cpu, regs, tsk);
6356 +}
6357 +
6358 +static inline int dump_save_this_cpu(const struct pt_regs *regs)
6359 +{
6360 +       int cpu = smp_processor_id();
6361 +
6362 +       dump_save_context(cpu, regs, current);
6363 +       return 1;
6364 +}
6365 +
6366 +static inline int dump_update_header(void)
6367 +{
6368 +       return dump_config.dumper->fmt->ops->update_header();
6369 +}
6370 +
6371 +static inline int dump_update_end_marker(void)
6372 +{
6373 +       return dump_config.dumper->fmt->ops->update_end_marker();
6374 +}
6375 +
6376 +static inline int dump_add_data(unsigned long loc, unsigned long sz)
6377 +{
6378 +       return dump_config.dumper->fmt->ops->add_data(loc, sz);
6379 +}
6380 +
6381 +/* Compression operation */
6382 +static inline int dump_compress_data(char *src, int slen, char *dst)
6383 +{
6384 +       return dump_config.dumper->compress->compress_func(src, slen, 
6385 +               dst, DUMP_DPC_PAGE_SIZE);
6386 +}
6387 +
6388 +
6389 +/* Prototypes of some default implementations of dump methods */
6390 +
6391 +extern struct __dump_compress dump_none_compression;
6392 +
6393 +/* Default scheme methods (dump_scheme.c) */
6394 +
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);
6403 +
6404 +/* Default scheme template */
6405 +extern struct dump_scheme dump_scheme_singlestage;
6406 +
6407 +/* Default dump format methods */
6408 +
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);
6416 +
6417 +/* Default format (lcrash) template */
6418 +extern struct dump_fmt dump_fmt_lcrash;
6419 +
6420 +/* Default dump selection filter table */
6421 +
6422 +/* 
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.
6428 + */   
6429 +extern struct dump_data_filter dump_filter_table[];
6430 +
6431 +/* Some pre-defined dumpers */
6432 +extern struct dumper dumper_singlestage;
6433 +extern struct dumper dumper_stage1;
6434 +extern struct dumper dumper_stage2;
6435 +
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 */
6442 +
6443 +/* Helpers - move these to dump.h later ? */
6444 +
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);
6448 +
6449 +static inline void dumper_reset(void)
6450 +{
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;
6456 +}
6457 +
6458 +/* 
6459 + * May later be moulded to perform boot-time allocations so we can dump 
6460 + * earlier during bootup 
6461 + */
6462 +static inline void *dump_alloc_mem(unsigned long size)
6463 +{
6464 +       return kmalloc(size, GFP_KERNEL);
6465 +}
6466 +
6467 +static inline void dump_free_mem(void *buf)
6468 +{
6469 +       struct page *page;
6470 +
6471 +       /* ignore reserved pages (e.g. post soft boot stage) */
6472 +       if (buf && (page = virt_to_page(buf))) {
6473 +               if (PageReserved(page))
6474 +                       return;
6475 +       }
6476 +
6477 +       kfree(buf);
6478 +}
6479 +
6480 +
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 @@
6487  
6488  export MODVERDIR := .tmp_versions
6489  
6490 +ifeq ($(CONFIG_CRASH_DUMP),)
6491 +      CFLAGS += -g
6492 +endif
6493 +
6494  # The temporary file to save gcc -MD generated dependencies must not
6495  # contain a comma
6496  comma := ,