Commit 7a54f46b301cfab8a0d7365aa186545f8b98f22e
Committed by
Linus Torvalds
1 parent
7975a9b732
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
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. |
kernel/reboot.c
... | ... | @@ -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 | { |