Kernel函数解析之kernel_restart

该函数实现在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个函数:

  1. kernel_restart_prepare(cmd)
    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停下来,以防止系统挂死。

  2. migrate_to_reboot_cpu();
    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的而不是第二个第三个,主要原因一是为了简单,二是防止在重启时再有什么任务迁移。

  3. syscore_shutdown()
    /**
     * 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则在此处调用。

  4. kmsg_dump(KMSG_DUMP_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

    };

    可以根据重启的不同场景,然后传递对应的重启原因。
  5. machine_restart(cmd);
    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停下来,然后调用重启接口重启系统。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值