【问题标题】:Kernel panic inside mod_timer()mod_timer() 中的内核恐慌
【发布时间】:2017-06-08 16:21:48
【问题描述】:

我正在编写一个使用多个计时器的程序。每 5 秒,他们将使用一个相同的网络链接与用户空间进行通信。

更具体地说,每个计时器每 5 秒调用一次 func()func() 将执行锁定、发送信息、解锁以及:

delay_us(200);        
if(!timer_pending(&timer1)){
    mod_timer(&timer1, jiffies+RTL_SECONDS_TO_JIFFIES(5));
}

奇怪的是在极少数情况下,系统会在mod_timer()内部崩溃,我反汇编发现它在tne zero,v0,0xc崩溃

这段代码(MIPS 指令)如下:

    /*
     * This is a common optimization triggered by the
     * networking code - if the timer is re-modified
     * to be the same thing then just return:
     */
    if (timer_pending(timer) && timer->expires == expires)
800216bc:   8e020000    lw  v0,0(s0)
800216c0:   50400005    beqzl   v0,800216d8 <mod_timer+0x98>
800216c4:   8e020010    lw  v0,16(s0)
800216c8:   8e020008    lw  v0,8(s0)
800216cc:   10510042    beq v0,s1,800217d8 <mod_timer+0x198>
800216d0:   24130001    li  s3,1
800216d4:   8e020010    lw  v0,16(s0)
800216d8:   2c420001    sltiu   v0,v0,1
800216dc:   00020336    tne zero,v0,0xc

调试非常痛苦。我怀疑计时器比赛,但从技术上讲,如果是这样,崩溃不应该在mod_timer() 内,对吗?看起来很可能会发生某种比赛,但这超出了我的知识范围。感谢您提出任何调试建议。

编辑:我只是在下面添加一些重要的转储消息:

Call Trace:
[<800243a4>] mod_timer+0x9c/0x1b8
[<8002399c>] call_timer_fn+0x20/0x88
[<80023bd0>] run_timer_softirq+0x1cc/0x244
[<8001de80>] __do_softirq+0x118/0x218
[<8001e05c>] do_softirq+0x58/0x78
[<8001e0e0>] irq_exit+0x64/0x80
[<8000044c>] ret_from_irq+0x0/0x4
[<800036cc>] __copy_user_common+0x44/0x2b8
[<8006701c>] file_read_actor+0x9c/0x114
[<8006a47c>] generic_file_aio_read+0x4f4/0x7f4
[<80092f00>] do_sync_read+0x90/0xd4
[<80093fc8>] vfs_read+0xb0/0x158
[<80094170>] SyS_read+0x60/0x9c
[<800017b0>] stack_done+0x20/0x40


Code: 24130001  8e020010  2c420001 <00020336> 02002021  0c008f12  27a50010  8e030000  10600015

编辑:回调函数如下:

void send_info(unsigned long task_priv)
{
    unsigned long flags;

    struct target_priv *priv = (struct target_priv *)task_priv;

    SMP_LOCK(flags);

    construct_netlink_send(priv);

    SMP_UNLOCK(flags);

    delay_us(200);

    if ((!strcmp(priv->name, "timer0")) && (!timer_pending(&priv->timer0))){
                mod_timer(&priv->timer0, jiffies+SECONDS_TO_JIFFIES(5));
                    return;
            }
    ...//do same for the rest 9 timers
}

【问题讨论】:

  • 什么是delay_us? Linux内核中没有这个功能,你的意思是udelay()吗?至于错误调试:如果这是mod_timer中的错误,你应该报告它,而不是在这里发布。但很可能是您的代码中的一个错误(可能是因为种族)损坏计时器结构。几乎有无限种方法可以破坏 Linux 内核中的某些内部结构,因此如果没有完整的代码,我们不可能为您提供帮助。至于可能的调试方向 - 确定(使用崩溃报告)给定指令中的 exact 参数是错误的,并尝试在代码中跟踪它。
  • 您好 Tsyvarev,感谢您的回复,代码的其他部分太长且无法发布(并且可能不相关)。 delay_us 是 udelay() ,我对它进行了封装。我知道在这里找到确切的解决方案是不可能的,所以任何猜测都会有很大帮助。从技术上讲,多个计时器可以共享同一个网络链接吗?
  • can multiple timer share same netlink? - 定时器的函数可以做原子上下文中允许的所有事情。由于不同计时器的函数可能并行运行,因此您需要适当的同步才能访问其中的相同对象。 any guessing is greatly helping. - 猜猜你没有显示的代码有什么问题?这不是堆栈溢出的工作方式。不是每个编程问题都应该在这里问,有时你只需要调试你的代码。
  • @Tsyvarev 好的,我会记住这一点。谢谢。

标签: c linux-kernel linux-device-driver embedded-linux


【解决方案1】:

对您的一些建议确实可以调试此问题。

  1. 减少计时器计数,确保只有一个计时器时一切正常。

  2. 请附上一些恐慌信息,也许我能找到一些有用的信息来帮助您解决问题。

  3. 我不确定“delay_us(200);”是否可能会导致问题。定时器回调在软中断内容中,不能被阻塞。所以,你使用的锁也需要检查它是否会阻塞内容。

【讨论】:

  • 嗨,吉米,感谢您的建议!我刚刚添加了一些消息。
  • @MichaelPeng,能否附上回调的代码。
  • 嗨,吉米,刚刚添加。我用谷歌搜索了你关于延迟的第三个建议,发现它看起来确实是一个可能的原因。
  • 嗨,吉米,很抱歉回复晚了。我后来发现的根本原因是当应用程序关闭时,计时器不小心没有正确删除。下次应用程序运行时,它会再次添加计时器并导致问题。对了,我的老家也在武汉,很高兴在这里认识你,哈哈。
  • @MichaelPeng,很高兴在这里见到你。最高兴的是你的家乡也在武汉,说不定我们有机会见面。
【解决方案2】:

此代码可能会导致问题:

if ((!strcmp(priv->name, "timer0")) && (!timer_pending(&priv->timer0))){
            mod_timer(&priv->timer0, jiffies+SECONDS_TO_JIFFIES(5));
                return;
        }

您不能修改回调中的其他计时器。它可能会破坏计时器的链接。

【讨论】:

  • 嗨,Jimmy,虽然每个定时器都使用这个功能,但它们的名称(priv->name)不同,所以只能修改自己的定时器。你可能会看到代码末尾的注释,它是灰色的,不容易看到..
  • 好的,你能不能把“delay_us(200);”去掉,看看问题是否依然存在。或者增加时间,比如“delay_us(2000);”检查问题是否绝对发生。
猜你喜欢
  • 2013-12-12
  • 2020-01-28
  • 1970-01-01
  • 2012-02-08
  • 2015-12-11
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多