When the kernel gets into a situation where it does not know how to proceed (most often during booting, but at other times), it issues a kernel panic by calling the panic(msg) routine defined in kernel/panic.c (Good name, huh?) This is a call from which No One Ever Returns.
The panic() routine adds text to the front of the message, telling you more about what the system was actually doing when the panic occurred … basically how big and bad the trail of debris in the filesystem is likely to be. This is where the “not syncing” part comes from, and when you see that, it’s good. (panic() does try to issue a sinc() system-call to push all buffered data out to the hard-disks before it goes down.)
The second part of the message is what was provided by the original call to panic(). For example, we find panic(“Tried to kill init!”) in kernel/exit.c.
So, what does this actually mean? Well, in this case it really doesn’t mean that someone tried to kill the magical init process (process #1…), but simply that it tried to die. This process is not allowed to die or to be killed.
When you see this message, it’s almost always at boot-time, and the real messages … the cause of the actual failure … will be found in the startup messages immediately preceding this one. This is often the case with kernel-panics. init encountered something “really bad,” and it didn’t know what to do, so it died, so the kernel died too.
BTW, the kernel-panic code is rather cute. It can blink lights and beep the system-speaker in Morse code. It can reboot the system automagically. Obviously the people who wrote this stuff encountered it a lot…
In diagnosing, or at least understanding, kernel-panics, I find it extremely helpful to have on-hand a copy of the Linux source-code, which is usually stored someplace like /usr/src/linux-2.x. You can use the grep utility to locate the actual code which caused the panic to occur.