[PATCH] init: handle kexec clean reboot
Jeremy Kerr
jk at ozlabs.org
Mon May 20 05:49:31 UTC 2013
Currently, busybox init won't allow us to do a clean kexec; we have to
invoke kexec -e, which calls the reboot(LINUX_REBOOT_CMD_KEXEC) system
call directly, bypassing any shutdown/reboot init actions.
It'd be better if we can halt the system properly before the kernel
kexec, in order to unmount filesystems, take network devices down, etc.
As far as I can tell, this is handled in other inits in differring ways:
A kexec on systemd is performed by invoking `systemctl kexec`,
(alternatively `shutdown -r` will detect the presence of a loaded kexec
and change the reboot() magic accordingly). Upstart doesn't seem to
have native kexec support, so a clean kexec on Ubuntu is implemented
with an init script that calls `kexec -e` late in the shutdown path and
never returns.
This change adds a '-k' option to /sbin/reboot, which tells init (via
a SIGALRM) that we're requesting a kexec rather than a normal reboot.
init then handles this by specifying the correct magic to the reboot
syscall.
RFC: a couple of open items:
* Not sure that SIGALRM is the best signal for this, let me know if
there's something more appropriate
* We could handle kexec in a method similar to upstart, by adding an
rc.d script that performs the reboot() syscall with the correct
kexec magic. However, this is a little inconsistent with the existing
reboot methods.
Signed-off-by: Jeremy Kerr <jk at ozlabs.org>
---
init/halt.c | 12 +++++++++---
init/init.c | 9 +++++++--
init/reboot.h | 6 ++++++
3 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/init/halt.c b/init/halt.c
index 7974adb..68a60a7 100644
--- a/init/halt.c
+++ b/init/halt.c
@@ -65,6 +65,7 @@
//usage: "\n -d SEC Delay interval"
//usage: "\n -n Do not sync"
//usage: "\n -f Force (don't go through init)"
+//usage: "\n -k Reboot to preloaded kexec kernel"
#include "libbb.h"
#include "reboot.h"
@@ -101,9 +102,11 @@ int halt_main(int argc UNUSED_PARAM, char **argv)
static const int magic[] = {
RB_HALT_SYSTEM,
RB_POWER_OFF,
- RB_AUTOBOOT
+ RB_AUTOBOOT,
+ RB_KEXEC,
};
- static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM };
+ static const smallint signals[] =
+ { SIGUSR1, SIGUSR2, SIGTERM, SIGALRM };
int delay = 0;
int which, flags, rc;
@@ -118,7 +121,7 @@ int halt_main(int argc UNUSED_PARAM, char **argv)
* in order to not break scripts.
* -i (shut down network interfaces) is ignored.
*/
- flags = getopt32(argv, "d:nfwi", &delay);
+ flags = getopt32(argv, "d:nfwik", &delay);
sleep(delay);
@@ -130,6 +133,9 @@ int halt_main(int argc UNUSED_PARAM, char **argv)
if (!(flags & 2)) /* no -n */
sync();
+ if (applet_name[0] == 'r' && flags & 0x20)
+ which = 4;
+
/* Perform action. */
rc = 1;
if (!(flags & 4)) { /* no -f */
diff --git a/init/init.c b/init/init.c
index 15aad47..7c806d7 100644
--- a/init/init.c
+++ b/init/init.c
@@ -175,8 +175,8 @@
#define CTRLALTDEL 0x20
/*
* Start these before killing all processes in preparation for
- * running RESTART actions or doing low-level halt/reboot/poweroff
- * (initiated by SIGUSR1/SIGTERM/SIGUSR2).
+ * running RESTART actions or doing low-level halt/reboot/poweroff/kexec
+ * (initiated by SIGUSR1/SIGTERM/SIGUSR2/SIGALRM).
* Wait for completion before proceeding.
*/
#define SHUTDOWN 0x40
@@ -393,6 +393,7 @@ static void reset_sighandlers_and_unblock_sigs(void)
+ (1 << SIGHUP)
+ (1 << SIGTSTP)
+ (1 << SIGSTOP)
+ + (1 << SIGALRM)
, SIG_DFL);
sigprocmask_allsigs(SIG_UNBLOCK);
}
@@ -811,6 +812,9 @@ static void halt_reboot_pwoff(int sig)
} else if (sig == SIGUSR2) {
m = "poweroff";
rb = RB_POWER_OFF;
+ } else if (sig == SIGALRM) {
+ m = "kexec";
+ rb = RB_KEXEC;
}
message(L_CONSOLE, "Requesting system %s", m);
pause_and_low_level_reboot(rb);
@@ -1124,6 +1128,7 @@ int init_main(int argc UNUSED_PARAM, char **argv)
+ (1 << SIGUSR1) /* halt */
+ (1 << SIGTERM) /* reboot */
+ (1 << SIGUSR2) /* poweroff */
+ + (1 << SIGALRM) /* kexec */
, halt_reboot_pwoff);
signal(SIGQUIT, restart_handler); /* re-exec another init */
diff --git a/init/reboot.h b/init/reboot.h
index 9497639..ea8b1ac 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -17,6 +17,12 @@
# endif
#endif
+#ifdef LINUX_REBOOT_CMD_KEXEC
+# define RB_KEXEC LINUX_REBOOT_CMD_KEXEC
+#else
+# define RB_KEXEC 0
+#endif
+
/* Stop system and switch power off if possible. */
#ifndef RB_POWER_OFF
# if defined(RB_POWERDOWN)
More information about the busybox
mailing list