aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/reboot.c
diff options
context:
space:
mode:
authorJoel Stanley <joel@jms.id.au>2015-04-15 19:16:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-15 19:35:23 -0400
commit7a54f46b301cfab8a0d7365aa186545f8b98f22e (patch)
tree40fe2cd79ce33d15e6fa5bcca62c92c65bc1820e /kernel/reboot.c
parent7975a9b7323d5a47e5b651bac810f3271e7156df (diff)
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>
Diffstat (limited to 'kernel/reboot.c')
-rw-r--r--kernel/reboot.c53
1 files changed, 48 insertions, 5 deletions
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 5925f5ae8dff..d20c85d9f8c0 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -387,8 +387,9 @@ void ctrl_alt_del(void)
387} 387}
388 388
389char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; 389char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
390static const char reboot_cmd[] = "/sbin/reboot";
390 391
391static int __orderly_poweroff(bool force) 392static int run_cmd(const char *cmd)
392{ 393{
393 char **argv; 394 char **argv;
394 static char *envp[] = { 395 static char *envp[] = {
@@ -397,8 +398,7 @@ static int __orderly_poweroff(bool force)
397 NULL 398 NULL
398 }; 399 };
399 int ret; 400 int ret;
400 401 argv = argv_split(GFP_KERNEL, cmd, NULL);
401 argv = argv_split(GFP_KERNEL, poweroff_cmd, NULL);
402 if (argv) { 402 if (argv) {
403 ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); 403 ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
404 argv_free(argv); 404 argv_free(argv);
@@ -406,8 +406,33 @@ static int __orderly_poweroff(bool force)
406 ret = -ENOMEM; 406 ret = -ENOMEM;
407 } 407 }
408 408
409 return ret;
410}
411
412static int __orderly_reboot(void)
413{
414 int ret;
415
416 ret = run_cmd(reboot_cmd);
417
418 if (ret) {
419 pr_warn("Failed to start orderly reboot: forcing the issue\n");
420 emergency_sync();
421 kernel_restart(NULL);
422 }
423
424 return ret;
425}
426
427static int __orderly_poweroff(bool force)
428{
429 int ret;
430
431 ret = run_cmd(poweroff_cmd);
432
409 if (ret && force) { 433 if (ret && force) {
410 pr_warn("Failed to start orderly shutdown: forcing the issue\n"); 434 pr_warn("Failed to start orderly shutdown: forcing the issue\n");
435
411 /* 436 /*
412 * I guess this should try to kick off some daemon to sync and 437 * I guess this should try to kick off some daemon to sync and
413 * poweroff asap. Or not even bother syncing if we're doing an 438 * poweroff asap. Or not even bother syncing if we're doing an
@@ -436,15 +461,33 @@ static DECLARE_WORK(poweroff_work, poweroff_work_func);
436 * This may be called from any context to trigger a system shutdown. 461 * This may be called from any context to trigger a system shutdown.
437 * If the orderly shutdown fails, it will force an immediate shutdown. 462 * If the orderly shutdown fails, it will force an immediate shutdown.
438 */ 463 */
439int orderly_poweroff(bool force) 464void orderly_poweroff(bool force)
440{ 465{
441 if (force) /* do not override the pending "true" */ 466 if (force) /* do not override the pending "true" */
442 poweroff_force = true; 467 poweroff_force = true;
443 schedule_work(&poweroff_work); 468 schedule_work(&poweroff_work);
444 return 0;
445} 469}
446EXPORT_SYMBOL_GPL(orderly_poweroff); 470EXPORT_SYMBOL_GPL(orderly_poweroff);
447 471
472static void reboot_work_func(struct work_struct *work)
473{
474 __orderly_reboot();
475}
476
477static DECLARE_WORK(reboot_work, reboot_work_func);
478
479/**
480 * orderly_reboot - Trigger an orderly system reboot
481 *
482 * This may be called from any context to trigger a system reboot.
483 * If the orderly reboot fails, it will force an immediate reboot.
484 */
485void orderly_reboot(void)
486{
487 schedule_work(&reboot_work);
488}
489EXPORT_SYMBOL_GPL(orderly_reboot);
490
448static int __init reboot_setup(char *str) 491static int __init reboot_setup(char *str)
449{ 492{
450 for (;;) { 493 for (;;) {