Re: linux-kernel-digest V1 #104

Drew Eckhardt (drew@poohsticks.org)
Mon, 03 Jul 1995 22:57:51 -0600


In message <m0sShc8-00013gC@iiit.swan.ac.uk>, iialan@iifeak.swan.ac.uk writes:
>Marek Writes:
>> I heard that some other systems actually do a crash dump to swap space.
>> This might be useful, but of course we should be sure that we are writing
>> in the right place... Maybe just check for swap-space signature first?
>> A full memory dump might be very helpful in tracking down some problems.
>
>Often the swap data is also needed for the 'complete picture'. Also I have
>heard enough horror stories of crash dumps from confused machines writing
>to the wrong partition. At the point the machine crashes something is very
>wrong. Drew discussed the ideas of a checksummed crash dumper in Germany,
>that might be safe.

I hashed out a rough design a while ago, but have been more concerned about
other projects (non Linux). Now that I'm poking at Linux again,
I'm more interested in avoiding crashes than making them useful :-)

The problem :

We want complete state information to go from RAM to
some non-volatile storage media.

The constraints we are working under :

1. If the system panic()'d, everything in RAM may be corrupted. So, to
do a crash dump, we need to reinitialize all of the parts we are going
to use.

2. Reinitializing destroys state information that we may want. It
also gets nasty in a hurry - what if the memory management code
screwed up and we can't dynamically allocate more space for the
new copy of our code?

Neat problem, isn't it?

A solution to the problem consistant with our constraints is to
implement separate crash dump drivers, thus avoiding the problems
which come with reinitialization, and the problems which come
with using existing structures.

Many of the Linux device drivers are immense due to their general
nature : some support totally different devices, they need to be
compatable with a multi-tasking environment and not hog the CPU
excessively, lots of complexity has gone into performance enhancements,
they attempt to _recover_ from many obscure error conditions, etc.

When crashing, we only care about one thing : dumping core. We
don't need to restart what we were executing before. We only need
to accomodate devices suitable for core dumps. We don't care
about wasting cycles. We don't care too much about performance. If we
run into an obscure error condition, we double panic. These limitations
make core-dump drivers fairly simple; to have the NCR53c810 and t128
drivers able to dump core to a SCSI disk would take a screenfull
of code each.

Your core dump drivers could be described by a structure like this :

struct dump_driver {
/*
* We have a kernel command line option
* dump=<driver> dump=<numeric parameters>
* which sets the core driver to the one selected, and calls
* dump->setup() with ints a pointer to the number parameters
* to set various dump driver specific parameters;
*
* For the SCSI+IDE drivers, these could be
* port, disk target ID, starting sector, max size.
*
* This is probably better than using "higher level"
* parameters, since it allows our kernel to core dump
* much earlier in the boot process. We also don't depend
* on things like the partition table, which may be dead.
*
* To idiot proof things, the command line option could be
* generated by some script or LILO itself based on /proc
* and/or boot messages.
*
* Ie,
* dumpdev /dev/sda1
* or
* dumpdev=/dev/sda1 in the LILO configuration file.
*
* Returns 0 on success, -1 on error
*
* Call from init/main.c; EARLY.
*/

int setup(int *ints);

/*
* what() specifies what will be dumped. We do this when
* we're sane because the information needed to determine
* what to dump may be lost when the time actually comes.
*
* what() takes an array in the format
* size
* { address, length }*
*
* Assume an implicit top-priority element consisting
* of state information - a header plus processor state which
* is passed into the dump function.
*
* Returns number of areas which will be saved in the advent
* of a dump (could be less than requested; ie SCSI boards
* which do 16 S/G segments and want to use one SCSI command)
* -1 on error.
*
* Call whenever what we're interested in changes - as new
* drivers are added, system boots, whatever.
*
* Normal priority could be
* - Kernel space
* - Frame buffers
* - Rest of RAM
*
* This information should be stored in an integrity checked
* piece of memory (could be *specific for simplicity).
*/

int what(size_t *);

/*
* dump() takes a pointer to the header + state structure,
* saves it and all regions designated with where to the
* device previously selected with setup.
*
* Returns 0 on success (should reboot), -1 on failure (double panic)
*
* Should be called from panic(), with interrupts disabled,
* paging disabled to (can keep current state of page tables,
* and not have to worry about setting up sane page tables).
*/

int dump(struct foo *);

/*
* Each driver is going to need its own set of unique parameters.
* these should be stored in a single (read : easy to integrity
* check) structure. Point to that and how long it is. This is
* probably a structure in initialized data space.
*/

int specific_len;
void *specific;

/*
* We can find out the start and end of driver text and protect
* it too.
*/
int text_len;
void *text;

/*
* These are some sort of integrity protection mechanism for
* the kernel code and all our data. Could be checksum or CRC
* depending on how paranoid we feel.
*/
int text_protection;
int struct_protection;
int specific_protection;
};