该函数实现在kernel/reboot.c中,主要功能为重新启动kernel,比如发现kernel进入到了一个异常场景,此时我想重启kernel,那么该函数就可以调用。
-
void
kernel_restart(
char *cmd)
-
{
-
kernel_restart_prepare(cmd);
-
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);
-
}
那么接下来 我们解析下该函数的实现过程,该函数中,总共调用了5个函数:
-
void
kernel_restart_prepare(
char *cmd)
-
{
-
blocking_notifier_call_chain(&reboot_notifier_list,
SYS_RESTART, cmd);
-
system_state =
SYSTEM_RESTART;
-
usermodehelper_disable();
-
device_shutdown();
-
}
主要功能为回调注册到reboot_notifier_list链表中的回调函数,因为有部分模块,需要在重启系统前做一些模块相关的工作,举个简单的例子,比如系统要重启时edma正在搬移数据,那么回调后可以把EDMA停下来,以防止系统挂死。
-
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));
-
}
该函数主要是把当前调用重启接口的任务,绑定到固定的一个CPU上,通常为当前online的序号排第一的CPU。此处不用纠结为什么绑定到第一个online的而不是第二个第三个,主要原因一是为了简单,二是防止在重启时再有什么任务迁移。
-
/**
-
* syscore_shutdown - Execute all the registered system core shutdown callbacks.
-
*/
-
void syscore_shutdown(
void)
-
{
-
struct syscore_ops *ops;
-
-
mutex_lock(&syscore_ops_lock);
-
-
list_for_each_entry_reverse(ops, &syscore_ops_list, node)
-
if (ops->shutdown) {
-
if (initcall_debug)
-
pr_info(
"PM: Calling %pS\n", ops->shutdown);
-
ops->shutdown();
-
}
-
-
mutex_unlock(&syscore_ops_lock);
-
}
回调所有注册syscore shutdown回调的回调函数,通常注册syscore的回调有3个:suspend\resume\shutdown,其中suspend和resume在低功耗流程中调用,shutdown则在此处调用。
回调注册到dump_list中的dump回调,注册的模块可能会保存一些自己关心的数据。
在这里也简单说下传参:
enum kmsg_dump_reason {
KMSG_DUMP_UNDEF,
KMSG_DUMP_PANIC,
KMSG_DUMP_OOPS,
KMSG_DUMP_EMERG,
KMSG_DUMP_SHUTDOWN,
KMSG_DUMP_MAX
};
可以根据重启的不同场景,然后传递对应的重启原因。
-
void
machine_restart(
char *cmd)
-
{
-
local_irq_disable();
-
smp_send_stop();
-
-
if (arm_pm_restart)
-
arm_pm_restart(reboot_mode, cmd);
-
else
-
do_kernel_restart(cmd);
-
-
/* Give a grace period for failure to restart of 1s */
-
mdelay(
1000);
-
-
/* Whoops - the platform was unable to reboot. Tell the user! */
-
printk(
"Reboot failed -- System halted\n");
-
while (
1);
-
}
函数实现在arch/arm/kernel/reboot.c中,我们首先可以看到,复位cpu会通过smp_send_stop接口把其他cpu停下来,然后调用重启接口重启系统。