基于A64的linux4.18内核进入panic后无法自动重启

基于A64的linux4.18内核进入panic后无法自动重启

背景

最近几天公司的一个做矿机的客户遇到了这样一种情况:使用tf卡加载程序时,内核进入panic可以自动重启;使用nor flash时,内核进入panic无法自动重启。由于客户的挖矿管理程序bug很多,很容易造成不同情况的panic,但是量产在即,容不得那么多时间去一一排查bug,所以就往内核添加了只要进入panic就自动重启的配置,来规避这些bug。客户找到我,让我帮忙解决内核进入panic后无法自动重启的bug,毕竟我们是提供芯片的,量还比较大,所以就有了后面的文档。

平台

  • 芯片:全志A64
  • 内核:linux4.18
  • flash烧写方法:采用dd命令

复现bug现象

拿到内核源码进行编译

拿到客户的源码后,在编译环境顶层目录下,第一次运行编译指令:

make  

上述操作是生成整个内核源码和tf卡映像文件scard.img,scard.img是后面用来升级nor flash中代码使用的。之后每次修改内核代码时,直接使用如下指令:

make linux-rebuild

上述操作是编译内核源码的命令,使其生成映像文件Image.lzma。之后这映像文件要被写入到nor flash上。

烧录代码

客户这个a64的板子是先通过tf卡加载内核,进入文件系统的。然后再插根网线,使用ssh连接进入到目标机的内核文件系统。

进入内核文件系统之前,先通过ssh将Image.lzma拷贝到目标机的tmp目录下:

scp Image.lzma root@192.168.2.21:/tmp

拷贝完成之后,进入到目标机的文件系统中,执行nor flash写入命令:

dd if=/tmp/Image.lzma of=/dev/mtdblock3 bs=4k

等待dd写入完成后,拔掉tf卡,断电重启,就会从nor flash执行新的内核程序。

复现步骤

使用如下指令,主动触发panic:

echo 1 > /proc/sys/kernel/sysrq
echo c > /proc/sysrq-trigger

执行上述步骤后,会进入panic,log如下:

# echo 1 > /proc/sys/kernel/sysrq
# echo c > /proc/sysrq-trigger
[  116.820488] sysrq: SysRq : Trigger a crash
[  116.824659] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
[  116.833448] Mem abort info:
[  116.836291]   ESR = 0x96000046
[  116.839360]   Exception class = DABT (current EL), IL = 32 bits
[  116.845296]   SET = 0, FnV = 0
[  116.848361]   EA = 0, S1PTW = 0
[  116.851519] Data abort info:
[  116.854410]   ISV = 0, ISS = 0x00000046
[  116.858263]   CM = 0, WnR = 1
[  116.861237] user pgtable: 4k pages, 48-bit VAs, pgdp = 0000000041ff400f
[  116.867866] [0000000000000000] pgd=00000000471b5003, pud=00000000497d1003, pmd=0000000000000000
[  116.876575] Internal error: Oops: 96000046 [#1] PREEMPT SMP
[  116.882140] Modules linked in: at24 lm75 gpio_counter(O) soft_pwm(O) 8021q garp stp mrp llc
[  116.890514] CPU: 0 PID: 1115 Comm: sh Tainted: G           O      4.18.0 #19
[  116.897550] Hardware name: Clover10 (DT)
[  116.901470] pstate: 60000005 (nZCv daif -PAN -UAO)
[  116.906266] pc : sysrq_handle_crash+0x20/0x2c
[  116.910618] lr : sysrq_handle_crash+0xc/0x2c
[  116.914880] sp : ffff00000abdbcf0
[  116.918189] x29: ffff00000abdbcf0 x28: ffff80000cb21a00
[  116.923498] x27: ffff0000085e1000 x26: 0000000000000040
[  116.928805] x25: 0000000000000125 x24: 0000000000000000
[  116.934113] x23: 0000000000000063 x22: 0000000000000007
[  116.939421] x21: ffff0000090dd000 x20: ffff0000090c8000
[  116.944728] x19: ffff000009117c80 x18: 000000000000000a
[  116.950037] x17: 0000000000000000 x16: 0000000000000000
[  116.955345] x15: 00000000000c8508 x14: ffff000089158ce7
[  116.960653] x13: ffffffffffffffff x12: 0000000000000030
[  116.965961] x11: 00000000fffffffe x10: ffff000009158cef
[  116.971269] x9 : 0000000005f5e0ff x8 : 0000000000000000
[  116.976577] x7 : 54203a2071527379 x6 : 0000000000000007
[  116.981885] x5 : 0000000000000000 x4 : 0000000000000000
[  116.987193] x3 : ffffffffffffffff x2 : b2c272ddd92d4900
[  116.992500] x1 : 0000000000000000 x0 : 0000000000000001
[  116.997810] Process sh (pid: 1115, stack limit = 0x000000008542075c)
[  117.004152] Call trace:
[  117.006598]  sysrq_handle_crash+0x20/0x2c
[  117.010605]  __handle_sysrq+0x9c/0x14c
[  117.014351]  write_sysrq_trigger+0x74/0x7c
[  117.018445]  proc_reg_write+0x68/0x98
[  117.022108]  __vfs_write+0x34/0x140
[  117.025594]  vfs_write+0xb4/0x188
[  117.028906]  ksys_write+0x5c/0xbc
[  117.032220]  sys_write+0xc/0x14
[  117.035360]  el0_svc_naked+0x30/0x34
[  117.038936] Code: 52800020 b90e2820 d5033e9f d2800001 (39000020)
[  117.045022] ---[ end trace f45817332c9b5658 ]---
[  117.049634] Kernel panic - not syncing: Fatal exception
[  117.054855] SMP: stopping secondary CPUs
[  117.058778] Kernel Offset: disabled
[  117.062263] CPU features: 0x24802004
[  117.065833] Memory Limit: none
[  117.068890] Rebooting in 1 seconds..

上面是整个触发过程的log,现在是会一直停在Rebooting in 1 seconds上,没有其它反应,这个使用的是nor flash。

如果上述过程使用的是tf加载的话,再进行上述手动进入panic操作,就可以正常重启。

源码跟踪

加入打印后跟踪到代码一直停在emergency_restart()这个函数内部:

在这里插入图片描述

目前不清楚为啥一直停在这个函数内部,看样子是当时的环境不允许执行重启操作。因为这个函数并不是一个完整的重启,可能在重启前需要使用到一些环境条件。所以才可能出现一直停在函数内部的情况。

解决方案

从emergency_restart函数的注释可以看出,这是一个不完全的重启操作,在重启前应该需要一些环境条件满足,才会重启。所以将其替换为kernel_restart函数,通过注释可以发现,这个函数直接完全地重启:

/**
 *	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);
	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_RESTART);
	machine_restart(cmd);
}
EXPORT_SYMBOL_GPL(kernel_restart);

所以解决的方案如下:

    if (panic_timeout != 0) {
        kernel_restart(0);
        /*
		 * This will not be a clean reboot, with everything
		 * shutting down.  But if there is a chance of
		 * rebooting the system it will be rebooted.
		 */
//        emergency_restart();
	}

将emergency_restart屏蔽掉,替换为kernel_restart即可。kernel_restart被调用时,需要smp调度关闭,中断关闭等。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值