kernel/reboot.c: add orderly_reboot for graceful reboot
The kernel has orderly_poweroff which allows the kernel to initiate a graceful shutdown of userspace, by running /sbin/poweroff. This adds orderly_reboot that will cause userspace to shut itself down by calling /sbin/reboot. This will be used for shutdown initiated by a system controller on platforms that do not use ACPI. orderly_reboot() should be used when the system wants to allow userspace to gracefully shut itself down. For cases where the system may imminently catch on fire, the existing emergency_restart() provides an immediate reboot without involving userspace. Signed-off-by: Joel Stanley <joel@jms.id.au> Cc: Fabian Frederick <fabf@skynet.be> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Jeremy Kerr <jk@ozlabs.org> Cc: David S. Miller <davem@davemloft.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
7975a9b732
commit
7a54f46b30
|
@ -70,7 +70,8 @@ void ctrl_alt_del(void);
|
||||||
#define POWEROFF_CMD_PATH_LEN 256
|
#define POWEROFF_CMD_PATH_LEN 256
|
||||||
extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
|
extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
|
||||||
|
|
||||||
extern int orderly_poweroff(bool force);
|
extern void orderly_poweroff(bool force);
|
||||||
|
extern void orderly_reboot(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emergency restart, callable from an interrupt handler.
|
* Emergency restart, callable from an interrupt handler.
|
||||||
|
|
|
@ -387,8 +387,9 @@ void ctrl_alt_del(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
|
char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
|
||||||
|
static const char reboot_cmd[] = "/sbin/reboot";
|
||||||
|
|
||||||
static int __orderly_poweroff(bool force)
|
static int run_cmd(const char *cmd)
|
||||||
{
|
{
|
||||||
char **argv;
|
char **argv;
|
||||||
static char *envp[] = {
|
static char *envp[] = {
|
||||||
|
@ -397,8 +398,7 @@ static int __orderly_poweroff(bool force)
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
argv = argv_split(GFP_KERNEL, cmd, NULL);
|
||||||
argv = argv_split(GFP_KERNEL, poweroff_cmd, NULL);
|
|
||||||
if (argv) {
|
if (argv) {
|
||||||
ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
|
ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
|
||||||
argv_free(argv);
|
argv_free(argv);
|
||||||
|
@ -406,8 +406,33 @@ static int __orderly_poweroff(bool force)
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __orderly_reboot(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = run_cmd(reboot_cmd);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_warn("Failed to start orderly reboot: forcing the issue\n");
|
||||||
|
emergency_sync();
|
||||||
|
kernel_restart(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __orderly_poweroff(bool force)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = run_cmd(poweroff_cmd);
|
||||||
|
|
||||||
if (ret && force) {
|
if (ret && force) {
|
||||||
pr_warn("Failed to start orderly shutdown: forcing the issue\n");
|
pr_warn("Failed to start orderly shutdown: forcing the issue\n");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* I guess this should try to kick off some daemon to sync and
|
* I guess this should try to kick off some daemon to sync and
|
||||||
* poweroff asap. Or not even bother syncing if we're doing an
|
* poweroff asap. Or not even bother syncing if we're doing an
|
||||||
|
@ -436,15 +461,33 @@ static DECLARE_WORK(poweroff_work, poweroff_work_func);
|
||||||
* This may be called from any context to trigger a system shutdown.
|
* This may be called from any context to trigger a system shutdown.
|
||||||
* If the orderly shutdown fails, it will force an immediate shutdown.
|
* If the orderly shutdown fails, it will force an immediate shutdown.
|
||||||
*/
|
*/
|
||||||
int orderly_poweroff(bool force)
|
void orderly_poweroff(bool force)
|
||||||
{
|
{
|
||||||
if (force) /* do not override the pending "true" */
|
if (force) /* do not override the pending "true" */
|
||||||
poweroff_force = true;
|
poweroff_force = true;
|
||||||
schedule_work(&poweroff_work);
|
schedule_work(&poweroff_work);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(orderly_poweroff);
|
EXPORT_SYMBOL_GPL(orderly_poweroff);
|
||||||
|
|
||||||
|
static void reboot_work_func(struct work_struct *work)
|
||||||
|
{
|
||||||
|
__orderly_reboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLARE_WORK(reboot_work, reboot_work_func);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* orderly_reboot - Trigger an orderly system reboot
|
||||||
|
*
|
||||||
|
* This may be called from any context to trigger a system reboot.
|
||||||
|
* If the orderly reboot fails, it will force an immediate reboot.
|
||||||
|
*/
|
||||||
|
void orderly_reboot(void)
|
||||||
|
{
|
||||||
|
schedule_work(&reboot_work);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(orderly_reboot);
|
||||||
|
|
||||||
static int __init reboot_setup(char *str)
|
static int __init reboot_setup(char *str)
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
Loading…
Reference in New Issue