上次写了一篇《ftrace function_graph分析》,是为了解决一个bug,所以在不停的撸代码。
最近这个bug终于有了头绪了。
这个bug的现象是在打开ftrace function graph之后,设备老是crash掉。
35.509913: <6> Unable to handle kernel NULL pointer dereference at virtual address 00000071
-
35.517215: <6> pgd = ffffffc00007d000
-
35.520602: <2> [00000071] *pgd=000000008dd0b003, *pmd=000000008dd0c003, *pte=00e000000b000407
-
35.528880: <6> Internal error: Oops: 96000006 [#1] PREEMPT SMP
-
36.645457: <2> scm_call 33554690 ffffffc074017bf0 //address of desc
-
36.650038: <2> Modules linked in: qdrbg_module(O) qcrypto_module(O)
-
36.650073: <6> CPU: 2 PID: 0 Comm: swapper/2 Tainted: G W O 3.10.73-g356530d-05963-ga8723d9-dirty #13
-
36.650101: <6> task: ffffffc00ddfb000 ti: ffffffc07400c000 task.ti: ffffffc07400c000
-
36.650147: <2> PC is at scm_call2_atomic+0x190/0x1bc
-
36.650180: <2> LR is at scm_call2_atomic+0x118/0x1bc
-
36.650204: <2> pc : [<ffffffc0003e1904>] lr : [<ffffffc0003e188c>] pstate: 200001c5
-
36.650223: <2> sp : ffffffc07400fd90
-
36.650282: <2> x29: ffffffc07400fd90 x28: ffffffc000c1f350
-
36.650340: <2> x27: ffffffc003e65658 x26: 0000000000000040
-
36.650398: <2> x25: ffffffc001588000 x24: ffffffc0016376d0
-
36.650455: <2> x23: 0000000000000002 x22: 0000000000000001
-
36.650512: <2> x21: ffffffc00149d000 x20: 0000000000000000
-
36.650570: <2> x19: 0000000000000001 x18: 0000000000000000
-
36.650627: <2> x17: 0000000000000000 x16: 0000000000000000
-
36.650684: <2> x15: 0000000000000000 x14: 0000000000000000
-
36.650741: <2> x13: 0000000000000000 x12: 0000000004c5d83d
-
36.650797: <2> x11: 0000000000000001 x10: 0000000000000000
-
36.650856: <2> x9 : ffffffc000084000 x8 : 00000032b5193519
-
36.650914: <2> x7 : 000000008007d000 x6 : ffffffc0016640e8
-
36.650971: <2> x5 : ffffffc0013c3b40 x4 : ffffffc07400c000
-
36.651028: <2> x3 : 0000000075ad7000 x2 : ffffffc076e7c218
-
36.651086: <2> x1 : 0000000000000000 x0 : 0000000000000000
-
-
36.656822: <2> Call trace:
-
36.656859: <2> [<ffffffc0003e1904>] scm_call2_atomic+0x190/0x1bc
-
36.656895: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
-
36.656928: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
-
36.656960: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
-
36.656993: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
-
36.657026: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
-
36.657059: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
-
36.657090: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
-
36.657131: <2> [<ffffffc000c0a0f8>] secondary_start_kernel+0x108/0x118
从这个stack dump上看不出太多的信息,每次调用scm call进入PC 的时候,总是crash掉。scm_call2_atomic返回的时候,一个保存在栈中的参数X19被破坏掉了。之前花了一个多月的时候来分析这个问题,但是没什么太大的进展。在搞清楚设备的suspend/resume过程后,尝试给cpu_suspend的子函数全部使用notrace关键字,居然解决掉这个问题。但是一直没有找到这个问题的root cause。
由于这个stack dump中一直出现scm_call2_atomic函数,把我误导了(在此省略一个月的无效调试),一直以为这个问题是出现在scm call进入power collapse失败的时候。最终发现不是,居然是power collapse成功从cpu_resume返回的时候出问题。
还用从ftrace function graph的设计原理来细说。 通过分析代码,发现cpu_suspend调用的很多子函数中都有notrace关键字,为什么要添加这样的关键字呢?
答案就是__cpu_suspend_enter的子函数不允许function graph!
当一个CPU要进入power collapse进入低功耗的时候,
__cpu_suspend
->
__cpu_suspend_enter
->
->scm_call2_atomic
->__scm_call_armv8_32 ---- power collapse 掉电 (PSCI的情况类似)
cpu_resume
.......
->__cpu_suspend中
__cpu_suspend_enter函数的下一条指令
(在此省略讲解suspend中如何保持CPU的context,resume的时候如何恢复CPU context 的相关代码)
->cpus_suspend
每次调用一个非notrace的函数时,ftrace_caller会修改子函数的stack中的LR,将原来的LR保存在task_struct->ret_stack和task_struct->current_ret_stack.
那么如果CPU成功进入power collapse并从cpu_resume返回时,执行完__cpu_suspend(注意__cpu_suspend本身是打开了ftrace function
graph)的,它的LR已经被修改了,所以__cpu_suspend函数执行完毕返回时,需要从task_struct中去获得LR。
那么问题来了?如果
__cpu_suspend_enter的子函数开启了ftrace function grpah,那么其子函数同样会保持LR到ret_stack数组中,并递加curr_ret_stack.
那么从cpu_resume返回时,__cpu_suspend执行完毕时,curr_ret_stack被子函数递加过,无法正常返回了。
这就是为什么我们会从上面看到奇怪的stack dump了,scm_call2_atomic完全是误导,因为scm_call2_atomic是一个非notrace的函数。所以cpu_resume返回时,
就获得了从task_struct中获取到了错误的LR。所以__cpu_suspend返回时跳转到了这个错误的LR。
这个问题在ARM PSCI driver同样存在。虽然可以通过在__cpu_suspend_enter的前后加入pause_graph_tracing/unpause_graph_tracing来解决这个问题。
但是我觉得这个问题的根据解决还是通过加notrace。这一点从cpu_suspend的相关代码中可以明显看出痕迹。代码提交者就考虑到了这个问题,所以很多地方用了notrace关键词。
但是PSCI是后来加入的代码,并没有充分考虑到这一点。
好吧,内核4.4已经解决了这个问题
阅读(2129) | 评论(0) | 转发(0) |