Commit 7a54f46b301cfab8a0d7365aa186545f8b98f22e

Authored by Joel Stanley
Committed by Linus Torvalds
1 parent 7975a9b732

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>

Showing 2 changed files with 50 additions and 6 deletions Side-by-side Diff

include/linux/reboot.h
... ... @@ -70,7 +70,8 @@
70 70 #define POWEROFF_CMD_PATH_LEN 256
71 71 extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
72 72  
73   -extern int orderly_poweroff(bool force);
  73 +extern void orderly_poweroff(bool force);
  74 +extern void orderly_reboot(void);
74 75  
75 76 /*
76 77 * Emergency restart, callable from an interrupt handler.
... ... @@ -387,8 +387,9 @@
387 387 }
388 388  
389 389 char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
  390 +static const char reboot_cmd[] = "/sbin/reboot";
390 391  
391   -static int __orderly_poweroff(bool force)
  392 +static int run_cmd(const char *cmd)
392 393 {
393 394 char **argv;
394 395 static char *envp[] = {
... ... @@ -397,8 +398,7 @@
397 398 NULL
398 399 };
399 400 int ret;
400   -
401   - argv = argv_split(GFP_KERNEL, poweroff_cmd, NULL);
  401 + argv = argv_split(GFP_KERNEL, cmd, NULL);
402 402 if (argv) {
403 403 ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
404 404 argv_free(argv);
405 405  
... ... @@ -406,8 +406,33 @@
406 406 ret = -ENOMEM;
407 407 }
408 408  
  409 + return ret;
  410 +}
  411 +
  412 +static 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 +
  427 +static int __orderly_poweroff(bool force)
  428 +{
  429 + int ret;
  430 +
  431 + ret = run_cmd(poweroff_cmd);
  432 +
409 433 if (ret && force) {
410 434 pr_warn("Failed to start orderly shutdown: forcing the issue\n");
  435 +
411 436 /*
412 437 * I guess this should try to kick off some daemon to sync and
413 438 * poweroff asap. Or not even bother syncing if we're doing an
414 439  
415 440  
... ... @@ -436,14 +461,32 @@
436 461 * This may be called from any context to trigger a system shutdown.
437 462 * If the orderly shutdown fails, it will force an immediate shutdown.
438 463 */
439   -int orderly_poweroff(bool force)
  464 +void orderly_poweroff(bool force)
440 465 {
441 466 if (force) /* do not override the pending "true" */
442 467 poweroff_force = true;
443 468 schedule_work(&poweroff_work);
444   - return 0;
445 469 }
446 470 EXPORT_SYMBOL_GPL(orderly_poweroff);
  471 +
  472 +static void reboot_work_func(struct work_struct *work)
  473 +{
  474 + __orderly_reboot();
  475 +}
  476 +
  477 +static 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 + */
  485 +void orderly_reboot(void)
  486 +{
  487 + schedule_work(&reboot_work);
  488 +}
  489 +EXPORT_SYMBOL_GPL(orderly_reboot);
447 490  
448 491 static int __init reboot_setup(char *str)
449 492 {