什么可能导致preempt_count改变或workqueue在原子上下文中运行?

3

我一直在进行模块工作,但是会随机崩溃(通常在启动后10小时内)。

内核日志信息可能因每次崩溃而异,但有些情况下我会得到以下信息:

<4>huh, entered c90390a8 with preempt_count 0000010d, exited with c0340000?

生成此日志的代码来自2.6.14内核,即kernel/timer.c:

            int preempt_count = preempt_count();
            fn(data);
            if (preempt_count != preempt_count()) {
                printk(KERN_WARNING "huh, entered %p "
                       "with preempt_count %08x, exited"
                       " with %08x?\n",
                       fn, preempt_count,
                       preempt_count());
                BUG();
            }

要发生这种情况,必须发生什么(显然是 preempt_count 改变了,但是可能会导致这种情况的原因是什么)?

崩溃的另一个症状是,我在从工作队列执行 i2c 时看到 scheduling while atomic(这肯定不应该是原子操作,对吧?)。这可能是什么原因造成的?

我觉得这篇文章可能是一个很大的风险,但我真的只是想找到任何可以排除故障的东西。

1个回答

6

仅凭我自己的理解回答: "preempt_count"是一个32位的字段,分成多个子位字段用于不同的目的。这些子位字段在O'Reilly的《深入理解Linux内核》中有详细说明。再次强调,我不知道"c0340000"代表什么。但由于您的起始值为"0000010d",应该结束于"0000010d",所以您的计时器代码做了些非常糟糕的事情。

一个常见的原因是,如果您的计时器代码执行了spin_lock_bh()等操作,但忘记了执行spin_unlock_bh()。但通常只会导致起始和结束preempt_count值之间只有一个位差异。但在您的情况下,起始和结束值显示出了大量的变化。

迈克尔


结束值看起来几乎像一个地址。也许在计时器中运行的代码正在向内存中的随机位置写入?我正在工作的模块中没有计时器,但它确实有一个工作队列,当出现这个问题时,我会看到来自工作队列的调度消息,同时是原子的。无论如何,感谢您的评论 :) - josec
嗯,是的,我想c0340000可能是一个地址。但是最后4个十六进制数字都是0似乎对于一个地址来说太整齐了。无论如何,您可以执行“cat /proc/modules”命令,看看任何驱动程序地址是否包括c0340000。 - mwang25

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接