1340 lines · 33.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* *  linux/kernel/reboot.c * *  Copyright (C) 2013  Linus Torvalds */ #define pr_fmt(fmt)	"reboot: " fmt #include <linux/atomic.h>#include <linux/ctype.h>#include <linux/export.h>#include <linux/kexec.h>#include <linux/kmod.h>#include <linux/kmsg_dump.h>#include <linux/reboot.h>#include <linux/suspend.h>#include <linux/syscalls.h>#include <linux/syscore_ops.h>#include <linux/uaccess.h> /* * this indicates whether you can reboot with ctrl-alt-del: the default is yes */ static int C_A_D = 1;struct pid *cad_pid;EXPORT_SYMBOL(cad_pid); #if defined(CONFIG_ARM)#define DEFAULT_REBOOT_MODE		= REBOOT_HARD#else#define DEFAULT_REBOOT_MODE#endifenum reboot_mode reboot_mode DEFAULT_REBOOT_MODE;EXPORT_SYMBOL_GPL(reboot_mode);enum reboot_mode panic_reboot_mode = REBOOT_UNDEFINED; /* * This variable is used privately to keep track of whether or not * reboot_type is still set to its default value (i.e., reboot= hasn't * been set on the command line).  This is needed so that we can * suppress DMI scanning for reboot quirks.  Without it, it's * impossible to override a faulty reboot quirk without recompiling. */int reboot_default = 1;int reboot_cpu;enum reboot_type reboot_type = BOOT_ACPI;int reboot_force; struct sys_off_handler {	struct notifier_block nb;	int (*sys_off_cb)(struct sys_off_data *data);	void *cb_data;	enum sys_off_mode mode;	bool blocking;	void *list;	struct device *dev;}; /* * This variable is used to indicate if a halt was initiated instead of a * reboot when the reboot call was invoked with LINUX_REBOOT_CMD_POWER_OFF, but * the system cannot be powered off. This allowes kernel_halt() to notify users * of that. */static bool poweroff_fallback_to_halt; /* * Temporary stub that prevents linkage failure while we're in process * of removing all uses of legacy pm_power_off() around the kernel. */void __weak (*pm_power_off)(void); /* *	Notifier list for kernel code which wants to be called *	at shutdown. This is used to stop any idling DMA operations *	and the like. */static BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); /** *	emergency_restart - reboot the system * *	Without shutting down any hardware or taking any locks *	reboot the system.  This is called when we know we are in *	trouble so this is our best effort to reboot.  This is *	safe to call in interrupt context. */void emergency_restart(void){	kmsg_dump(KMSG_DUMP_EMERG);	system_state = SYSTEM_RESTART;	machine_emergency_restart();}EXPORT_SYMBOL_GPL(emergency_restart); void kernel_restart_prepare(char *cmd){	blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);	system_state = SYSTEM_RESTART;	usermodehelper_disable();	device_shutdown();} /** *	register_reboot_notifier - Register function to be called at reboot time *	@nb: Info about notifier function to be called * *	Registers a function with the list of functions *	to be called at reboot time. * *	Currently always returns zero, as blocking_notifier_chain_register() *	always returns zero. */int register_reboot_notifier(struct notifier_block *nb){	return blocking_notifier_chain_register(&reboot_notifier_list, nb);}EXPORT_SYMBOL(register_reboot_notifier); /** *	unregister_reboot_notifier - Unregister previously registered reboot notifier *	@nb: Hook to be unregistered * *	Unregisters a previously registered reboot *	notifier function. * *	Returns zero on success, or %-ENOENT on failure. */int unregister_reboot_notifier(struct notifier_block *nb){	return blocking_notifier_chain_unregister(&reboot_notifier_list, nb);}EXPORT_SYMBOL(unregister_reboot_notifier); static void devm_unregister_reboot_notifier(struct device *dev, void *res){	WARN_ON(unregister_reboot_notifier(*(struct notifier_block **)res));} int devm_register_reboot_notifier(struct device *dev, struct notifier_block *nb){	struct notifier_block **rcnb;	int ret; 	rcnb = devres_alloc(devm_unregister_reboot_notifier,			    sizeof(*rcnb), GFP_KERNEL);	if (!rcnb)		return -ENOMEM; 	ret = register_reboot_notifier(nb);	if (!ret) {		*rcnb = nb;		devres_add(dev, rcnb);	} else {		devres_free(rcnb);	} 	return ret;}EXPORT_SYMBOL(devm_register_reboot_notifier); /* *	Notifier list for kernel code which wants to be called *	to restart the system. */static ATOMIC_NOTIFIER_HEAD(restart_handler_list); /** *	register_restart_handler - Register function to be called to reset *				   the system *	@nb: Info about handler function to be called *	@nb->priority:	Handler priority. Handlers should follow the *			following guidelines for setting priorities. *			0:	Restart handler of last resort, *				with limited restart capabilities *			128:	Default restart handler; use if no other *				restart handler is expected to be available, *				and/or if restart functionality is *				sufficient to restart the entire system *			255:	Highest priority restart handler, will *				preempt all other restart handlers * *	Registers a function with code to be called to restart the *	system. * *	Registered functions will be called from machine_restart as last *	step of the restart sequence (if the architecture specific *	machine_restart function calls do_kernel_restart - see below *	for details). *	Registered functions are expected to restart the system immediately. *	If more than one function is registered, the restart handler priority *	selects which function will be called first. * *	Restart handlers are expected to be registered from non-architecture *	code, typically from drivers. A typical use case would be a system *	where restart functionality is provided through a watchdog. Multiple *	restart handlers may exist; for example, one restart handler might *	restart the entire system, while another only restarts the CPU. *	In such cases, the restart handler which only restarts part of the *	hardware is expected to register with low priority to ensure that *	it only runs if no other means to restart the system is available. * *	Currently always returns zero, as atomic_notifier_chain_register() *	always returns zero. */int register_restart_handler(struct notifier_block *nb){	return atomic_notifier_chain_register(&restart_handler_list, nb);}EXPORT_SYMBOL(register_restart_handler); /** *	unregister_restart_handler - Unregister previously registered *				     restart handler *	@nb: Hook to be unregistered * *	Unregisters a previously registered restart handler function. * *	Returns zero on success, or %-ENOENT on failure. */int unregister_restart_handler(struct notifier_block *nb){	return atomic_notifier_chain_unregister(&restart_handler_list, nb);}EXPORT_SYMBOL(unregister_restart_handler); /** *	do_kernel_restart - Execute kernel restart handler call chain * *	Calls functions registered with register_restart_handler. * *	Expected to be called from machine_restart as last step of the restart *	sequence. * *	Restarts the system immediately if a restart handler function has been *	registered. Otherwise does nothing. */void do_kernel_restart(char *cmd){	atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd);} void migrate_to_reboot_cpu(void){	/* The boot cpu is always logical cpu 0 */	int cpu = reboot_cpu; 	cpu_hotplug_disable(); 	/* Make certain the cpu I'm about to reboot on is online */	if (!cpu_online(cpu))		cpu = cpumask_first(cpu_online_mask); 	/* Prevent races with other tasks migrating this task */	current->flags |= PF_NO_SETAFFINITY; 	/* Make certain I only run on the appropriate processor */	set_cpus_allowed_ptr(current, cpumask_of(cpu));} /* *	Notifier list for kernel code which wants to be called *	to prepare system for restart. */static BLOCKING_NOTIFIER_HEAD(restart_prep_handler_list); static void do_kernel_restart_prepare(void){	blocking_notifier_call_chain(&restart_prep_handler_list, 0, NULL);} /** *	kernel_restart - reboot the system *	@cmd: pointer to buffer containing command to execute for restart *		or %NULL * *	Shutdown everything and perform a clean reboot. *	This is not safe to call in interrupt context. */void kernel_restart(char *cmd){	kernel_restart_prepare(cmd);	do_kernel_restart_prepare();	migrate_to_reboot_cpu();	syscore_shutdown();	if (!cmd)		pr_emerg("Restarting system\n");	else		pr_emerg("Restarting system with command '%s'\n", cmd);	kmsg_dump(KMSG_DUMP_SHUTDOWN);	machine_restart(cmd);}EXPORT_SYMBOL_GPL(kernel_restart); static void kernel_shutdown_prepare(enum system_states state){	blocking_notifier_call_chain(&reboot_notifier_list,		(state == SYSTEM_HALT) ? SYS_HALT : SYS_POWER_OFF, NULL);	system_state = state;	usermodehelper_disable();	device_shutdown();}/** *	kernel_halt - halt the system * *	Shutdown everything and perform a clean system halt. */void kernel_halt(void){	kernel_shutdown_prepare(SYSTEM_HALT);	migrate_to_reboot_cpu();	syscore_shutdown();	if (poweroff_fallback_to_halt)		pr_emerg("Power off not available: System halted instead\n");	else		pr_emerg("System halted\n");	kmsg_dump(KMSG_DUMP_SHUTDOWN);	machine_halt();}EXPORT_SYMBOL_GPL(kernel_halt); /* *	Notifier list for kernel code which wants to be called *	to prepare system for power off. */static BLOCKING_NOTIFIER_HEAD(power_off_prep_handler_list); /* *	Notifier list for kernel code which wants to be called *	to power off system. */static ATOMIC_NOTIFIER_HEAD(power_off_handler_list); static int sys_off_notify(struct notifier_block *nb,			  unsigned long mode, void *cmd){	struct sys_off_handler *handler;	struct sys_off_data data = {}; 	handler = container_of(nb, struct sys_off_handler, nb);	data.cb_data = handler->cb_data;	data.mode = mode;	data.cmd = cmd;	data.dev = handler->dev; 	return handler->sys_off_cb(&data);} static struct sys_off_handler platform_sys_off_handler; static struct sys_off_handler *alloc_sys_off_handler(int priority){	struct sys_off_handler *handler;	gfp_t flags; 	/*	 * Platforms like m68k can't allocate sys_off handler dynamically	 * at the early boot time because memory allocator isn't available yet.	 */	if (priority == SYS_OFF_PRIO_PLATFORM) {		handler = &platform_sys_off_handler;		if (handler->cb_data)			return ERR_PTR(-EBUSY);	} else {		if (system_state > SYSTEM_RUNNING)			flags = GFP_ATOMIC;		else			flags = GFP_KERNEL; 		handler = kzalloc(sizeof(*handler), flags);		if (!handler)			return ERR_PTR(-ENOMEM);	} 	return handler;} static void free_sys_off_handler(struct sys_off_handler *handler){	if (handler == &platform_sys_off_handler)		memset(handler, 0, sizeof(*handler));	else		kfree(handler);} /** *	register_sys_off_handler - Register sys-off handler *	@mode: Sys-off mode *	@priority: Handler priority *	@callback: Callback function *	@cb_data: Callback argument * *	Registers system power-off or restart handler that will be invoked *	at the step corresponding to the given sys-off mode. Handler's callback *	should return NOTIFY_DONE to permit execution of the next handler in *	the call chain or NOTIFY_STOP to break the chain (in error case for *	example). * *	Multiple handlers can be registered at the default priority level. * *	Only one handler can be registered at the non-default priority level, *	otherwise ERR_PTR(-EBUSY) is returned. * *	Returns a new instance of struct sys_off_handler on success, or *	an ERR_PTR()-encoded error code otherwise. */struct sys_off_handler *register_sys_off_handler(enum sys_off_mode mode,			 int priority,			 int (*callback)(struct sys_off_data *data),			 void *cb_data){	struct sys_off_handler *handler;	int err; 	handler = alloc_sys_off_handler(priority);	if (IS_ERR(handler))		return handler; 	switch (mode) {	case SYS_OFF_MODE_POWER_OFF_PREPARE:		handler->list = &power_off_prep_handler_list;		handler->blocking = true;		break; 	case SYS_OFF_MODE_POWER_OFF:		handler->list = &power_off_handler_list;		break; 	case SYS_OFF_MODE_RESTART_PREPARE:		handler->list = &restart_prep_handler_list;		handler->blocking = true;		break; 	case SYS_OFF_MODE_RESTART:		handler->list = &restart_handler_list;		break; 	default:		free_sys_off_handler(handler);		return ERR_PTR(-EINVAL);	} 	handler->nb.notifier_call = sys_off_notify;	handler->nb.priority = priority;	handler->sys_off_cb = callback;	handler->cb_data = cb_data;	handler->mode = mode; 	if (handler->blocking) {		if (priority == SYS_OFF_PRIO_DEFAULT)			err = blocking_notifier_chain_register(handler->list,							       &handler->nb);		else			err = blocking_notifier_chain_register_unique_prio(handler->list,									   &handler->nb);	} else {		if (priority == SYS_OFF_PRIO_DEFAULT)			err = atomic_notifier_chain_register(handler->list,							     &handler->nb);		else			err = atomic_notifier_chain_register_unique_prio(handler->list,									 &handler->nb);	} 	if (err) {		free_sys_off_handler(handler);		return ERR_PTR(err);	} 	return handler;}EXPORT_SYMBOL_GPL(register_sys_off_handler); /** *	unregister_sys_off_handler - Unregister sys-off handler *	@handler: Sys-off handler * *	Unregisters given sys-off handler. */void unregister_sys_off_handler(struct sys_off_handler *handler){	int err; 	if (IS_ERR_OR_NULL(handler))		return; 	if (handler->blocking)		err = blocking_notifier_chain_unregister(handler->list,							 &handler->nb);	else		err = atomic_notifier_chain_unregister(handler->list,						       &handler->nb); 	/* sanity check, shall never happen */	WARN_ON(err); 	free_sys_off_handler(handler);

Lines 1–500 of 1340.