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 <[email protected]> --- 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) _______________________________________________ busybox mailing list [email protected] http://lists.busybox.net/mailman/listinfo/busybox
