你能在页面错误处理程序中启用中断吗?是否存在抢占式调度的ARM内核争用?
我通过CONFIG_PREEMPT在UDP接收代码中获得了ARM内核oops,或者在故障处理程序中启用了中断。
问题类似于what another user reported here。但在我的情况下,当我向系统发送110%加载UDP数据包(系统丢弃大约10%数据包)时,内核会在几分钟内完成。只有在运行一些busybox shell脚本时才会发生这种情况,而不是只有UDP接收程序正在运行。我已经跟踪了它总是看起来很好的数据地址,缓冲区在被释放之前被分配和使用。
有两种方法可以避免它:
[1]当从preempt(CONFIG_PREEMPT)更改为preempt_voluntary时,问题就会消失。这是内核2.6.39上ARM的已知问题吗?通过抢先调度,我也会在很长一段时间后看到jffs2中的问题,但是没有preempt_voluntary。
我怀疑是以太网DMA完全利用了总线,从而阻止CPU加载其TLB条目,从而导致页面错误。我推断,因为busybox脚本需要在图片中,当产生脚本时,它会创建地址空间并加载许多TLB条目,从而使总线过载。如果preempt_voluntary是一个解决方案,可以排除DMA阻塞总线吗?
我正在运行的测试是基于phy3250的系统上的LTIB内核2.6.39.4 lpclinux。
[2]更多测试显示页面错误处理程序嵌套在以太网中断中。在内核页面错误处理程序__dabt_svc中禁用中断但在用户页面错误处理程序__dabt_user中保持启用时,问题就会消失。如果没有,巢水平上升到4并且它已经过了。所以问题是:在页面错误处理程序中启用中断是否正确?
[2]的测试代码如下。添加或修改带@@@@的行。然后在do_DataAbort()中捕获嵌套级别。
file arch/arm/kernel/entry-armv.S:
__dabt_svc:
svc_entry
... ...
@
@ set desired IRQ state, then call main handler
@
debug_entry r1
@@@@Not_Enable_Irq_In_Dabtsvc
ldr r2, =armv_dabtsvc_count @@@@
ldr r3, [r2] @@@@
add r3, r3, #1 @@@@
str r3, [r2] @@@@
msr cpsr_c, r9 @@@@disable thisk
mov r2, r2 @@@@add this extra inst
mov r2, sp
bl do_DataAbort
@
@ IRQs off again before pulling preserved data off the stack
@
disable_irq_notrace
ldr r2, =armv_dabtsvc_count @@@@
ldr r3, [r2] @@@@
sub r3, r3, #1 @@@@
str r3, [r2] @@@@
@
@ restore SPSR and restart the instruction
@
ldr r2, [sp, #S_PSR]
svc_exit r2 @ return from exception
UNWIND(.fnend )
ENDPROC(__dabt_svc)
并将变量添加到文件中:
file arch/arm/kernel/entry-armv.S:
@@@@save nesting level:
.data @@@@
.align @@@@
armv_dabtsvc_count: @@@@
.long 0 @ count svc entry @@@@
我正在尝试将所有这些联系起来。内核专家能否看出所有测试是否有意义?在页面错误处理程序中禁用中断是一种有效的解决方案吗?
编辑:页面错误处理程序中的oops不是第一次失败。在进行中的对齐处理程序中有一个“do_bad_area”。随后,未对齐访问的修复失败导致页面错误。是的,正如有人在下面评论,修复未对齐的访问是非常麻烦的。那些未对齐的访问来自ip_input,ip_fragment和udp stack。一旦我修复了堆栈中的所有内容,问题就消失了。
再次编辑:问题在于对齐处理程序中的两个操作:它获取指令,并获取指令所引用的数据。通过数据访问报告oops,但原因是在第一页故障失败时获取指令失败。由于fetch指令在内核空间中,因此页面始终有效,表示硅bug。如果将代码更改为再次获取它将成功,这证实它更可能是一个硅bug。由于它引入了过多的TLB刷新,中断进入画面。简而言之,TLB加载是自动的,因此在内核空间中获取指令不会失败。但它仍然失败了。
答案 0 :(得分:1)
我想这是答案(不完整,需要测试):
过早启用中断时出现问题。假定在__get_user()与do_alignment()中启用的中断一起使用时,它将在原子上下文中使用。如果中断启用被推迟到该点之后,一切都应该没问题。
请查看两个内核提交。 2011年6月25日的第一个推迟启用中断的。第二个是2013年2月25日,它将__get_user()的用法更改为probling_kernel_address()。
第一次提交:
3.x内核在低级处理程序__dabt_svc和__dabt_user等中删除了中断启用。提交消息:
git diff 8b418616..02fe2845 entry-armv.S
commit 02fe2845d6a837ab02f0738f6cf4591a02cc88d4
Author: Russell King <rmk+kernel@rm.linux.org.uk>
Date: Sat Jun 25 11:44:06 2011 +0100
ARM: entry: avoid enabling interrupts in prefetch/data abort handlers
Avoid enabling interrupts if the parent context had interrupts enabled
in the abort handler assembly code, and move this into the breakpoint/
page/alignment fault handlers instead.
This gets rid of some special-casing for the breakpoint fault handlers
from the low level abort handler path.
Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
commit 8b4186160b7894ca4583f702a562856d5d9e9118
Author: Russell King <rmk+kernel@rm.linux.org.uk>
Date: Sat Jun 25 19:25:02 2011 +0100
代码差异片段:
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index d644d02..c46bafa 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -185,20 +185,15 @@ ENDPROC(__und_invalid)
__dabt_svc:
svc_entry
... ...
dabt_helper
@
- @ set desired IRQ state, then call main handler
+ @ call main handler
@
- debug_entry r1
- msr cpsr_c, r9
mov r2, sp
bl do_DataAbort
......
确认中断不需要在故障处理程序中过早启用。
第二次提交:
commit b255188f90e2bade1bd11a986dd1ca4861869f4d
Author: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Mon Feb 25 16:10:42 2013 +0000
ARM: fix scheduling while atomic warning in alignment handling code
Paolo Pisati reports that IPv6 triggers this warning:
BUG: scheduling while atomic: swapper/0/0/0x40000100
[<c001b1c4>] (unwind_backtrace+0x0/0xf0) from [<c0503c5c>] (__schedule_bug+0x48/0x5c)
[<c0503c5c>] (__schedule_bug+0x48/0x5c) from [<c0508608>] (__schedule+0x700/0x740)
[<c0508608>] (__schedule+0x700/0x740) from [<c007007c>] (__cond_resched+0x24/0x34)
[<c007007c>] (__cond_resched+0x24/0x34) from [<c05086dc>] (_cond_resched+0x3c/0x44)
[<c05086dc>] (_cond_resched+0x3c/0x44) from [<c0021f6c>] (do_alignment+0x178/0x78c)
[<c0021f6c>] (do_alignment+0x178/0x78c) from [<c00083e0>] (do_DataAbort+0x34/0x98)
[<c00083e0>] (do_DataAbort+0x34/0x98) from [<c0509a60>] (__dabt_svc+0x40/0x60)
Exception stack(0xc0763d70 to 0xc0763db8)
[<c0509a60>] (__dabt_svc+0x40/0x60) from [<c02a8490>] (__csum_ipv6_magic+0x8/0xc8)
Fix this by using probe_kernel_address() stead of __get_user().
arch/arm/mm/alignment.c | 11 ++++-------