There have been many reports of init failing to reboot and/or failing to halt
authorEric Andersen <andersen@codepoet.org>
Thu, 24 Apr 2003 11:41:28 +0000 (11:41 -0000)
committerEric Andersen <andersen@codepoet.org>
Thu, 24 Apr 2003 11:41:28 +0000 (11:41 -0000)
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

init/init.c

index be91d6a8f075696b10830b61ba78ba46172673bb..8adff1cd2e8047ff650bdffc20758ce309aa15b1 100644 (file)
 #ifdef CONFIG_SYSLOGD
 # include <sys/syslog.h>
 #endif
+#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__)
+#include <sys/reboot.h>
+#endif
+
 
 #if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_MMU__)
 #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
 #define _PATH_STDPATH  "/usr/bin:/bin:/usr/sbin:/sbin"
 #endif
@@ -663,6 +660,23 @@ static void run_actions(int action)
 }
 
 #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)
 {
        sigset_t block_signals;