There have been many reports of init failing to reboot and/or failing to halt

over the years.  Well I finally took the time to track this down.  It turns out
that inside linux/kernel/sys.c the kernel will call
    machine_halt();
    do_exit(0);
when halting, or will call
    machine_power_off();
    do_exit(0);

during a reboot.  Unlike sysv init, we call reboot from within the init
process, so if the call to machine_halt() or machine_power_off() returns,                                       the call to do_exit(0) will cause the kernel to panic.  Which is a very
bad thing to happen.

So I just added this little patch to fork and call the reboot
syscall from within the forked child process, thereby neatly
avoiding the problem.

But IMHO, both calls to do_exit(0) within linux/kernel/sys.c
are bugs and should be fixed.

 -Erik
This commit is contained in:
Eric Andersen 2003-04-24 11:41:28 +00:00
parent afc01cd485
commit 2c1de61023

View File

@ -46,6 +46,10 @@
#ifdef CONFIG_SYSLOGD #ifdef CONFIG_SYSLOGD
# include <sys/syslog.h> # include <sys/syslog.h>
#endif #endif
#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__)
#include <sys/reboot.h>
#endif
#if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_MMU__) #if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_MMU__)
#define fork vfork #define fork vfork
@ -80,13 +84,6 @@ struct serial_struct {
}; };
#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__)
#include <sys/reboot.h>
#define init_reboot(magic) reboot(magic)
#else
#define init_reboot(magic) reboot(0xfee1dead, 672274793, magic)
#endif
#ifndef _PATH_STDPATH #ifndef _PATH_STDPATH
#define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin" #define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin"
#endif #endif
@ -663,6 +660,23 @@ static void run_actions(int action)
} }
#ifndef DEBUG_INIT #ifndef DEBUG_INIT
static void init_reboot(unsigned long magic)
{
pid_t pid;
/* We have to fork here, since the kernel calls do_exit(0) in
* linux/kernel/sys.c, which can cause the machint to panic when
* the init process is killed.... */
if ((pid = fork()) == 0) {
#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__)
reboot(magic);
#else
reboot(0xfee1dead, 672274793, magic);
#endif
_exit(0);
}
waitpid (pid, NULL, 0);
}
static void shutdown_system(void) static void shutdown_system(void)
{ {
sigset_t block_signals; sigset_t block_signals;