免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 6836 | 回复: 13
打印 上一主题 下一主题

[中断] printk在执行过程中如果发生了NMI中断,并在NMI中也调用了printk,那会怎样?? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-06-21 16:00 |只看该作者 |倒序浏览
小弟有这样一个疑问,在执行printk的过程中必定是要在开始和结尾进行lock unlock的动作,那如果在执行printk的时候,发生了NMI中断,并在NMI中也进行了printk调用,那会发生什么事情呢?

1.printk在开始的时候进行了加锁,则NMI中的printk会block导致NMI handler一直等待?
2.NMI中的printk会正确执行下去,这样的话printk buffer中的数据岂不就会乱掉了?而且是否意味着lock失效?

百思不得其解~~~~求大牛指导~~

论坛徽章:
0
2 [报告]
发表于 2013-06-21 17:26 |只看该作者
本帖最后由 frank529 于 2013-06-21 17:27 编辑

瞄了下内核代码,貌似逻辑还比较清楚。vprintk中有对printk递归调用作判断,如果发生了Oops,则输出打印。否则,不输出,记录发生了printk递归错误,退出。然后再调用printk输出消息的时候,会输出"BUG: recent printk recursion!"错误。

论坛徽章:
2
射手座
日期:2014-09-03 00:18:022015年辞旧岁徽章
日期:2015-03-03 16:54:15
3 [报告]
发表于 2014-08-25 19:39 |只看该作者
本帖最后由 wLiu2007 于 2014-08-25 20:20 编辑

同问,如果一个进程正在执行printk,数据写了一半,发生了NMI,NMI也需要调用printk,
因为NMI中断无法屏蔽,进程写了一半的缓冲器是怎么保护的,内核是怎么处理的?

论坛徽章:
9
辰龙
日期:2014-08-18 20:38:42未羊
日期:2014-09-04 08:50:45丑牛
日期:2014-09-06 00:12:55寅虎
日期:2014-12-22 20:50:56摩羯座
日期:2015-01-14 22:28:15巳蛇
日期:2015-01-23 20:39:272015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之青岛
日期:2016-03-13 23:37:1915-16赛季CBA联赛之深圳
日期:2016-03-29 18:52:38
4 [报告]
发表于 2014-08-25 22:42 |只看该作者
回复 3# wLiu2007

frank529都自己看代码了,你怎么不自己去看呢?
13年的贴你还翻出来追问。

如果不错任何处理,在NMI里头调用有加锁操作的函数是会导致死锁的。但prink实现里头加入的了检测。



   

论坛徽章:
2
射手座
日期:2014-09-03 00:18:022015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2014-08-25 22:55 |只看该作者
回复 4# Tinnal

手头没有下内核代码,突然想到这个问题了,所以搜了一下,就接着问了,呵呵
   

论坛徽章:
9
辰龙
日期:2014-08-18 20:38:42未羊
日期:2014-09-04 08:50:45丑牛
日期:2014-09-06 00:12:55寅虎
日期:2014-12-22 20:50:56摩羯座
日期:2015-01-14 22:28:15巳蛇
日期:2015-01-23 20:39:272015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之青岛
日期:2016-03-13 23:37:1915-16赛季CBA联赛之深圳
日期:2016-03-29 18:52:38
6 [报告]
发表于 2014-08-25 23:50 |只看该作者
wLiu2007 发表于 2014-08-25 22:55
回复 4# Tinnal

手头没有下内核代码,突然想到这个问题了,所以搜了一下,就接着问了,呵呵


http://lxr.oss.org.cn/

论坛徽章:
2
射手座
日期:2014-09-03 00:18:022015年辞旧岁徽章
日期:2015-03-03 16:54:15
7 [报告]
发表于 2014-08-26 14:04 |只看该作者
本帖最后由 wLiu2007 于 2014-08-26 17:24 编辑

回复 6# Tinnal

之前有这个疑问是因为看到printk介绍:It can be called from any context.
以为它在任何场景下都能够正确输出我们给它的数据,上午在公司看了一下代码,发现它在2个场景下应该不会输出我们给它的内容,只会
打印一个"BUG: recent printk recursion!",
1:printk嵌套的时候,我理解嵌套应该是在printk里面调用了输出到终端等驱动程序,比如写串口,然后串口驱动里面又调用了printk;
2,printk拿到logbuf_lock之后,NMI中断产生,NMI中断处理程序里面调用printk;

        /*
         * Ouch, printk recursed into itself!
         */
        if (unlikely(printk_cpu == this_cpu)) {
                /*
                 * If a crash is occurring during printk() on this CPU,
                 * then try to get the crash message out but make sure
                 * we can't deadlock. Otherwise just return to avoid the
                 * recursion and return - but flag the recursion so that
                 * it can be printed at the next appropriate moment:
                 */
                if (!oops_in_progress) {
                        recursion_bug = 1;
                        goto out_restore_irqs;
                }
                zap_locks();
        }

        lockdep_off();  //current->lockdep_recursion++;
        spin_lock(&logbuf_lock);
        printk_cpu = this_cpu;


        处于临界区,写log_buf;
        输出到终端;

        printk_cpu = UINT_MAX;
        //如果在这里发生NMI中断,而且调用printk,上面的条件printk_cpu == this_cpu将不成立,锁还没有被释放,然后又去拿锁,应该就会形成死锁了吧
        spin_unlock(&logbuf_lock);

1,看这段代码有个疑问:用printk_cpu == this_cpu检查是否嵌套好像还不是很准确,如果在上面释放锁标红的地方被NMI抢占且NMI调用printk的话,应该会发生死锁吧,不过这个概率应该很小?

2,如果检测到递归了,且是oops,会调用zap_locks,看代码里面有比较时间,不知道是何用意?而且第一次比较oops_timestamp;好像没有初始值
/*
* Zap console related locks when oopsing. Only zap at most once
* every 10 seconds, to leave time for slow consoles to print a
* full oops.
*/
static void zap_locks(void)
{
        static unsigned long oops_timestamp;

        if (time_after_eq(jiffies, oops_timestamp) &&
                        !time_after(jiffies, oops_timestamp + 30 * HZ))
                return;

        oops_timestamp = jiffies;

        /* If a crash is occurring, make sure we can't deadlock */
        spin_lock_init(&logbuf_lock);
        /* And make sure that we print immediately */
        init_MUTEX(&console_sem);
}

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
8 [报告]
发表于 2014-08-27 00:01 |只看该作者
问题2,这个是静态变量,初始化后就起不到效果了。。比较时间的目前看似需要在阻塞30s后才做相应处理,没有时间看代码,明天再看看代码,同时看看问题1...

论坛徽章:
9
辰龙
日期:2014-08-18 20:38:42未羊
日期:2014-09-04 08:50:45丑牛
日期:2014-09-06 00:12:55寅虎
日期:2014-12-22 20:50:56摩羯座
日期:2015-01-14 22:28:15巳蛇
日期:2015-01-23 20:39:272015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之青岛
日期:2016-03-13 23:37:1915-16赛季CBA联赛之深圳
日期:2016-03-29 18:52:38
9 [报告]
发表于 2014-08-27 10:58 |只看该作者
回复 7# wLiu2007


    回复 7# wLiu2007

发现它在2个场景下应该不会输出我们给它的内容,只会打印一个"BUG: recent printk recursion!",

这个要注意,是在嵌套退出后,在下一次打印是添这一句。正在嵌套时是不会增加任何输出的。

1:printk嵌套的时候,我理解嵌套应该是在printk里面调用了输出到终端等驱动程序,比如写串口,然后串口驱动里面又调用了printk;

理解的没错,还有就是NMI里头。这两者都会使printk嵌套。

2,printk拿到logbuf_lock之后,NMI中断产生,NMI中断处理程序里面调用printk;

这个也是嵌套场景。

2,如果检测到递归了,且是oops,会调用zap_locks,看代码里面有比较时间,不知道是何用意?而且第一次比较oops_timestamp;好像没有初始值

这个批注说得很清楚了。Only zap at most once  every 10 seconds, to leave time for slow consoles to print a  full oops.




   

论坛徽章:
9
辰龙
日期:2014-08-18 20:38:42未羊
日期:2014-09-04 08:50:45丑牛
日期:2014-09-06 00:12:55寅虎
日期:2014-12-22 20:50:56摩羯座
日期:2015-01-14 22:28:15巳蛇
日期:2015-01-23 20:39:272015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之青岛
日期:2016-03-13 23:37:1915-16赛季CBA联赛之深圳
日期:2016-03-29 18:52:38
10 [报告]
发表于 2014-08-27 10:58 |只看该作者
本帖最后由 Tinnal 于 2014-08-27 11:00 编辑
1,看这段代码有个疑问:用printk_cpu == this_cpu检查是否嵌套好像还不是很准确,如果在上面释放锁标红的地方被NMI抢占且NMI调用printk的话,应该会发生死锁吧,不过这个概率应该很小?

重新看了一个内核源码,在NMI的处理上,的确现在的处理流程会有问题。

邮件列表也有相关的讨论:
Liu, Chuansheng 在2012/7/4 想到的是检测到在NMI环境里头,就别打印了,详情如下:
https://lkml.org/lkml/2012/7/4/273

Petr Mladek 在2014/5/9/时,发了一个1000多行的patchset,想达到的效果是想让NMI也能支持打印。
https://lkml.org/lkml/2014/5/9/118

但linus对这个事情很反对:
On Tue, Jun 10, 2014 at 9:46 AM, Frederic Weisbecker <fweisbec@gmail.com> wrote:
>
> There is also a big risk that if we push back this bugfix, nobody will actually do
> that desired rewrite.
>
> Lets be crazy and Cc Linus on that.

Quite frankly, I hate seeing something like this:

kernel/printk/printk.c              | 1218 +++++++++++++++++++++++++----------
for something that is stupid and broken. Printing from NMI context
isn't really supposed to work, and we all *know* it's not supposed to
work.

I'd much rather disallow it, and if there is one or two places that
really want to print a warning and know that they are in NMI context,
have a special workaround just for them, with something that does
*not* try to make printk in general work any better.

Dammit, NMI context is special. I absolutely refuse to buy into the
broken concept that we should make more stuff work in NMI context.
Hell no, we should *not* try to make more crap work in NMI. NMI people
should be careful.

Make a trivial "printk_nmi()" wrapper that tries to do a trylock on
logbuf_lock, and *maybe* the existing sequence of

        if (console_trylock_for_printk())
                console_unlock();
then works for actually triggering the printout. But the wrapper
should be 15 lines of code for "if possible, try to print things", and
*not* a thousand lines of changes.

             Linus

On Wed, Jun 18, 2014 at 05:58:40AM -1000, Linus Torvalds wrote:
> On Jun 18, 2014 4:36 AM, "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
> wrote:
> >
> > I could easily add an option to RCU to allow people to tell it not to
> > use NMIs to dump the stack.
>
> I don't think it should be an "option".
>
> We should stop using nmi as if it was something "normal". It isn't. Code
> running in nmi context should be special, and should be very very aware
> that it is special. That goes way beyond "don't use printk". We seem to
> have gone way way too far in using nmi context.
>
> So we should get *rid* of code in nmi context rather than then complain
> about printk being buggy.


他们最大的争议是在RCU检测里,用的到NMI,同时也需要打栈。
邮件中间也提出过免锁printk方案,以下目前suse的修正方案(专门给NMI提供了空间存储)这个方案比Petr Mladek的方案代码量少点,只加了2百多行:
http://kernel.suse.com/cgit/kern ... 99f05dbd9c9742b14c9

唉,看来这个话题是又是一个持久战呀,目前3.16的printk代码都还不支持NMI里头调用。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP