ARM内核在页面错误处理程序中启用中断或使用抢占式调度时启动

时间:2013-05-21 23:40:06

标签: kernel arm tlb page-fault preemptive

你能在页面错误处理程序中启用中断吗?是否存在抢占式调度的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加载是自动的,因此在内核空间中获取指令不会失败。但它仍然失败了。

1 个答案:

答案 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 ++++-------