diff options
author | Eric Andersen <andersen@codepoet.org> | 2003-04-24 11:41:28 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2003-04-24 11:41:28 +0000 |
commit | 2c1de61023d384fd0a365405925940c3528cb75a (patch) | |
tree | 5839e97767864319de033cec3448767e0e43d016 | |
parent | afc01cd48544d4e0e7575a8518e575dd499e297c (diff) | |
download | busybox-w32-2c1de61023d384fd0a365405925940c3528cb75a.tar.gz busybox-w32-2c1de61023d384fd0a365405925940c3528cb75a.tar.bz2 busybox-w32-2c1de61023d384fd0a365405925940c3528cb75a.zip |
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
-rw-r--r-- | init/init.c | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/init/init.c b/init/init.c index be91d6a8f..8adff1cd2 100644 --- a/init/init.c +++ b/init/init.c | |||
@@ -46,6 +46,10 @@ | |||
46 | #ifdef CONFIG_SYSLOGD | 46 | #ifdef CONFIG_SYSLOGD |
47 | # include <sys/syslog.h> | 47 | # include <sys/syslog.h> |
48 | #endif | 48 | #endif |
49 | #if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) | ||
50 | #include <sys/reboot.h> | ||
51 | #endif | ||
52 | |||
49 | 53 | ||
50 | #if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_MMU__) | 54 | #if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_MMU__) |
51 | #define fork vfork | 55 | #define fork vfork |
@@ -80,13 +84,6 @@ struct serial_struct { | |||
80 | }; | 84 | }; |
81 | 85 | ||
82 | 86 | ||
83 | #if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) | ||
84 | #include <sys/reboot.h> | ||
85 | #define init_reboot(magic) reboot(magic) | ||
86 | #else | ||
87 | #define init_reboot(magic) reboot(0xfee1dead, 672274793, magic) | ||
88 | #endif | ||
89 | |||
90 | #ifndef _PATH_STDPATH | 87 | #ifndef _PATH_STDPATH |
91 | #define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin" | 88 | #define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin" |
92 | #endif | 89 | #endif |
@@ -663,6 +660,23 @@ static void run_actions(int action) | |||
663 | } | 660 | } |
664 | 661 | ||
665 | #ifndef DEBUG_INIT | 662 | #ifndef DEBUG_INIT |
663 | static void init_reboot(unsigned long magic) | ||
664 | { | ||
665 | pid_t pid; | ||
666 | /* We have to fork here, since the kernel calls do_exit(0) in | ||
667 | * linux/kernel/sys.c, which can cause the machint to panic when | ||
668 | * the init process is killed.... */ | ||
669 | if ((pid = fork()) == 0) { | ||
670 | #if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) | ||
671 | reboot(magic); | ||
672 | #else | ||
673 | reboot(0xfee1dead, 672274793, magic); | ||
674 | #endif | ||
675 | _exit(0); | ||
676 | } | ||
677 | waitpid (pid, NULL, 0); | ||
678 | } | ||
679 | |||
666 | static void shutdown_system(void) | 680 | static void shutdown_system(void) |
667 | { | 681 | { |
668 | sigset_t block_signals; | 682 | sigset_t block_signals; |