您可以在页面错误处理程序中启用中断吗?是否存在抢占式调度的 ARM 内核争用?
我在 UDP 中使用 CONFIG_PREEMPT 接收代码,或者在故障处理程序中启用了中断时,得到了一个 ARM 内核 oops。
该问题与其他用户在此处报告的问题相似。但在我的情况下,当我向系统发送 110% 负载 UDP 数据包(系统丢弃大约 10% 数据包)时,内核会在几分钟内发生错误。仅当有一些busybox shell 脚本正在运行时才会发生这种情况,而不是仅当UDP 接收程序正在运行时才会发生。我跟踪了看起来总是不错的数据地址,缓冲区在释放之前已分配和使用。
有两种方法可以避免:
[1] 将调度从抢占 (CONFIG_PREEMPT) 更改为抢占自愿时,问题就消失了。这是内核 2.6.39 上 ARM 的一个已知问题吗?通过抢占调度,我在很长一段时间后也看到了 jffs2 的问题,但 preempt_volunt 没有。
有一瞬间我怀疑是以太网 DMA 充分利用了总线,从而阻止 CPU 加载其 TLB 条目,从而导致页面错误。我推断是因为busybox脚本需要在图片中,当一个脚本被生成时,它会创建地址空间并加载许多TLB条目,从而使总线超载。如果 preempt_volunte 是一个解决方案,是否可以排除 DMA 阻塞总线?
我正在运行的测试是基于 phy3250 的系统上的 LTIB 内核 2.6.39.4 lpclinux。
[2] 更多测试表明页面错误处理程序嵌套在以太网中断中。当在内核页面错误处理程序 __dabt_svc 中禁用中断,但在用户页面错误处理程序 __dabt_user 中保持启用时,问题就消失了。如果不是,则嵌套级别上升到 4 并且它 oops'ed。所以问题是:在页面错误处理程序中启用中断是否正确?
[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 堆栈。一旦我修复了堆栈中的所有内容,问题就消失了。
再次编辑:问题在于对齐处理程序中的两个操作:它获取指令,并获取指令引用的数据。oops 由数据访问报告,但原因是获取指令失败,第一个页面错误失败。由于 fetch 指令在内核空间中,因此页面始终有效,这表明存在硅错误。如果更改代码以再次获取它会成功,这证实它更有可能是一个硅错误。中断进入画面是因为它带来了过多的 TLB 刷新。简而言之,TLB 加载是自动的,因此在内核空间中获取指令不会失败。但它仍然失败了。