poweroff: add a config option for people needing VERY early poweroff
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
7398892ac0
commit
95121d98e6
54
init/halt.c
54
init/halt.c
@ -24,6 +24,17 @@
|
|||||||
//config: help
|
//config: help
|
||||||
//config: Stop all processes and reboot the system.
|
//config: Stop all processes and reboot the system.
|
||||||
//config:
|
//config:
|
||||||
|
//config:config FEATURE_WAIT_FOR_INIT
|
||||||
|
//config: bool "Before signaling init, make sure it is ready for it"
|
||||||
|
//config: default y
|
||||||
|
//config: depends on HALT || POWEROFF || REBOOT
|
||||||
|
//config: help
|
||||||
|
//config: In rare cases, poweroff may be commanded by firmware to OS
|
||||||
|
//config: even before init process exists. On Linux, this spawns
|
||||||
|
//config: "/sbin/poweroff" very early. This option adds code
|
||||||
|
//config: which checks that init is ready to receive poweroff
|
||||||
|
//config: commands. Code size increase of ~80 bytes.
|
||||||
|
//config:
|
||||||
//config:config FEATURE_CALL_TELINIT
|
//config:config FEATURE_CALL_TELINIT
|
||||||
//config: bool "Call telinit on shutdown and reboot"
|
//config: bool "Call telinit on shutdown and reboot"
|
||||||
//config: default y
|
//config: default y
|
||||||
@ -108,6 +119,47 @@ static void write_wtmp(void)
|
|||||||
#define write_wtmp() ((void)0)
|
#define write_wtmp() ((void)0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_FEATURE_WAIT_FOR_INIT
|
||||||
|
/* In Linux, "poweroff" may be spawned even before init.
|
||||||
|
* For example, with ACPI:
|
||||||
|
* linux/drivers/acpi/bus.c:
|
||||||
|
* static void sb_notify_work(struct work_struct *dummy)
|
||||||
|
* orderly_poweroff(true);
|
||||||
|
* linux/kernel/reboot.c:
|
||||||
|
* static int run_cmd(const char *cmd)
|
||||||
|
* ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
|
||||||
|
* poweroff_cmd[] = "/sbin/poweroff";
|
||||||
|
* static int __orderly_poweroff(bool force)
|
||||||
|
* ret = run_cmd(poweroff_cmd);
|
||||||
|
*
|
||||||
|
* We want to make sure init exists and listens to signals.
|
||||||
|
*/
|
||||||
|
static int init_was_not_there(void)
|
||||||
|
{
|
||||||
|
enum { initial = 5 }; /* 5 seconds should be plenty for timeout */
|
||||||
|
int cnt = initial - 1;
|
||||||
|
|
||||||
|
/* Just existence of PID 1 does not mean it installed
|
||||||
|
* the handlers already.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
while (kill(1, 0) != 0 && --cnt >= 0)
|
||||||
|
sleep(1);
|
||||||
|
#endif
|
||||||
|
/* ... so let's wait for some evidence a usual startup event,
|
||||||
|
* mounting of /proc, happened. By that time init should be ready
|
||||||
|
* for signals.
|
||||||
|
*/
|
||||||
|
while (access("/proc/meminfo", F_OK) != 0 && --cnt >= 0)
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
/* Does it look like init wasn't there? */
|
||||||
|
return (cnt != initial - 1);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* Assume it's always there */
|
||||||
|
# define init_was_not_there() 0
|
||||||
|
#endif
|
||||||
|
|
||||||
int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||||
int halt_main(int argc UNUSED_PARAM, char **argv)
|
int halt_main(int argc UNUSED_PARAM, char **argv)
|
||||||
@ -171,6 +223,8 @@ int halt_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
if (!ENABLE_FEATURE_CALL_TELINIT) {
|
if (!ENABLE_FEATURE_CALL_TELINIT) {
|
||||||
/* bbox init assumed */
|
/* bbox init assumed */
|
||||||
rc = kill(1, signals[which]);
|
rc = kill(1, signals[which]);
|
||||||
|
if (init_was_not_there())
|
||||||
|
rc = kill(1, signals[which]);
|
||||||
} else {
|
} else {
|
||||||
/* SysV style init assumed */
|
/* SysV style init assumed */
|
||||||
/* runlevels:
|
/* runlevels:
|
||||||
|
Loading…
Reference in New Issue
Block a user