Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Joel Stanley and committed by
Linus Torvalds
7a54f46b 7975a9b7

+50 -6
+2 -1
include/linux/reboot.h
··· 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.
+48 -5
kernel/reboot.c
··· 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[] = { ··· 398 397 NULL 399 398 }; 400 399 int ret; 401 - 402 - argv = argv_split(GFP_KERNEL, poweroff_cmd, NULL); 400 + argv = argv_split(GFP_KERNEL, cmd, NULL); 403 401 if (argv) { 404 402 ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); 405 403 argv_free(argv); ··· 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 ··· 461 436 * This may be called from any context to trigger a system shutdown. 462 437 * If the orderly shutdown fails, it will force an immediate shutdown. 463 438 */ 464 - int orderly_poweroff(bool force) 439 + void orderly_poweroff(bool force) 465 440 { 466 441 if (force) /* do not override the pending "true" */ 467 442 poweroff_force = true; 468 443 schedule_work(&poweroff_work); 469 - return 0; 470 444 } 471 445 EXPORT_SYMBOL_GPL(orderly_poweroff); 446 + 447 + static void reboot_work_func(struct work_struct *work) 448 + { 449 + __orderly_reboot(); 450 + } 451 + 452 + static DECLARE_WORK(reboot_work, reboot_work_func); 453 + 454 + /** 455 + * orderly_reboot - Trigger an orderly system reboot 456 + * 457 + * This may be called from any context to trigger a system reboot. 458 + * If the orderly reboot fails, it will force an immediate reboot. 459 + */ 460 + void orderly_reboot(void) 461 + { 462 + schedule_work(&reboot_work); 463 + } 464 + EXPORT_SYMBOL_GPL(orderly_reboot); 472 465 473 466 static int __init reboot_setup(char *str) 474 467 {