造成irqs_disabled非空的条件有哪些,及由此引出的一个BUG

常书 P2P 其他  2015-12-14 03:22:35
目前我了解到的只有local_irq_save和local_irq_disable会导致irqs_disabled返回非空,大家还有知道其它什么函数吗
我遇到在irqs_disabled时调用了local_bh_enable,但我找不到谁引起了irqs_disabled,也就是发生问题时没人
调用local_irq_save和local_irq_disable:
芯片:ARM
内核:3.1
BUG是概率出现,大概重启15次出现一次,从LOG中可以看到,在进入destroy_conntrack时,处于中断禁用状态(pre为128),但这个禁用
状态不是由local_irq_save(若是则f2为0)和local_irq_disable(若是则flsg为0)引起的

jimtest pre destroy_conntrack,inirq:0,disable:0,flag:1,f2:1
jimtest aft destroy_conntrack,inirq:0,disable:0,flag:1,f2:1
jimtest pre destroy_conntrack,inirq:0,disable:128,flag:1,f2:1
jimtest pre destroy_conntrack,inirq:0,disable:128,flag:1,f2:1
jimtest aft destroy_conntrack,inirq:0,disable:128,flag:1,f2:1
------------[ cut here ]------------
WARNING: at kernel/softirq.c:159 local_bh_enable+0x9c/0xc4()
Modules linked in: nfs nfs_acl lockd sunrpc hi3521_adec(P) hi3521_aenc(P) hi3521_ao(P) hi3521_ai(P) hi3521_sio(P) hidmac tw2865 gpioi2c hi3521_jpegd hi3521_hdmi(P) hi3521_vfmw(P) hi3521_vdec(P) hifb(P) vcmp(P) hi3521_region(P)

hi3521_vda(P) hi3521_ive(P) hi3521_vpss(P) hi3521_vou(P) hi3521_viu(P) hi3521_jpege(P) hi3521_rc(P) hi3521_h264e(P) hi3521_chnl(P) hi3521_group(P) hi3521_venc(P) hi3521_dsu(P) hi3521_tde(P) hi3521_sys(P) hi3521_base(P) hiuser mmz
Backtrace:
[<c0036e00>] (dump_backtrace+0x0/0x110) from [<c03dea14>] (dump_stack+0x18/0x1c)
r6:0000009f r5:c004afd0 r4:00000000 r3:60000193
[<c03de9fc>] (dump_stack+0x0/0x1c) from [<c0043c9c>] (warn_slowpath_common+0x5c/0x6c)
[<c0043c40>] (warn_slowpath_common+0x0/0x6c) from [<c0043cd0>] (warn_slowpath_null+0x24/0x2c)
r8:00000000 r7:00000004 r6:c39ac0c0 r5:c2d330d8 r4:c053c420
r3:00000009
[<c0043cac>] (warn_slowpath_null+0x0/0x2c) from [<c004afd0>] (local_bh_enable+0x9c/0xc4)
[<c004af34>] (local_bh_enable+0x0/0xc4) from [<c02f8668>] (destroy_conntrack+0x114/0x168)
r4:c0561148 r3:60000193
[<c02f8554>] (destroy_conntrack+0x0/0x168) from [<c02f3124>] (nf_conntrack_destroy+0x24/0x38)
r5:ffdfe010 r4:c39ac0c0
[<c02f3100>] (nf_conntrack_destroy+0x0/0x38) from [<c02ccb2c>] (skb_release_head_state+0xc0/0xfc)
[<c02cca6c>] (skb_release_head_state+0x0/0xfc) from [<c02cc874>] (__kfree_skb+0x14/0xd0)
r4:c39ac0c0 r3:00000001
[<c02cc860>] (__kfree_skb+0x0/0xd0) from [<c02cc958>] (consume_skb+0x28/0x4c)
r4:c384eb40 r3:00000001
[<c02cc930>] (consume_skb+0x0/0x4c) from [<c022a21c>] (stmmac_poll+0x290/0xa74)
[<c0229f8c>] (stmmac_poll+0x0/0xa74) from [<c02d4d48>] (net_rx_action+0x134/0x2d4)
[<c02d4c14>] (net_rx_action+0x0/0x2d4) from [<c004aae4>] (__do_softirq+0xd0/0x1b4)
[<c004aa14>] (__do_softirq+0x0/0x1b4) from [<c004ad94>] (irq_exit+0x4c/0x50)
[<c004ad48>] (irq_exit+0x0/0x50) from [<c002c044>] (asm_do_IRQ+0x44/0x8c)
[<c002c000>] (asm_do_IRQ+0x0/0x8c) from [<c0032c58>] (__irq_svc+0x38/0x80)
Exception stack(0xc04d3f40 to 0xc04d3f88)
3f40: c04d2000 c04d2008 c04d3f88 00000000 c056114c c0561150 c04d2000 c04fb804
3f60: 00000001 413fc090 c04dc068 c04d3f94 c04d3f98 c04d3f88 c0034088 c003408c
3f80: 60000013 ffffffff
r6:00000077 r5:fe300100 r4:ffffffff r3:60000013
[<c0034060>] (default_idle+0x0/0x60) from [<c0034764>] (cpu_idle+0xbc/0x110)
[<c00346a8>] (cpu_idle+0x0/0x110) from [<c03dbea0>] (rest_init+0x74/0x78)
[<c03dbe2c>] (rest_init+0x0/0x78) from [<c0008a48>] (start_kernel+0x354/0x360)
[<c00086f4>] (start_kernel+0x0/0x360) from [<8000803c>] (0x8000803c)
---[ end trace 76bb1ab04f33e3d3 ]---
jimtest pre destroy_conntrack,inirq:0,disable:0,flag:1,f2:1
jimtest pre destroy_conntrack,inirq:0,disable:0,flag:1,f2:1
jimtest aft destroy_conntrack,inirq:0,disable:0,flag:1,f2:1

LOG对应代码
void nf_conntrack_destroy(struct nf_conntrack *nfct)
{
void (*destroy)(struct nf_conntrack *);
rcu_read_lock();
destroy = rcu_dereference(nf_ct_destroy);//这里即destroy_conntrack
BUG_ON(destroy == NULL);
destroy(nfct);
rcu_read_unlock();
}

static void
destroy_conntrack(struct nf_conntrack *nfct)
{
....
#if JIMDEBUG
char flag1,flag2;
flag1=in_irq();
flag2=irqs_disabled();
printk("jimtest pre destroy_conntrack,inirq:%d,disable:%d,flag:%d,f2:%d\r\n",flag1,flag2,g_jim_flag,g_jim_flag_save);
#endif
spin_lock_bh(&nf_conntrack_lock);
#if JIMDEBUG
flag1=in_irq();
flag2=irqs_disabled();
printk("jimtest pre destroy_conntrack,inirq:%d,disable:%d,flag:%d,f2:%d\r\n",flag1,flag2,g_jim_flag,g_jim_flag_save);
#endif
....
#if JIMDEBUG
flag1=in_irq();
flag2=irqs_disabled();
printk("jimtest aft destroy_conntrack,inirq:%d,disable:%d,flag:%d,f2:%d\r\n",flag1,flag2,g_jim_flag,g_jim_flag_save);
#endif
spin_unlock_bh(&nf_conntrack_lock);
...
}


...全文
1208 点赞 收藏 10
写回复
10 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
jim138 2016-05-24
引用 4 楼 u010247038 的回复:
楼主,我现在做3531也出现这个问题了~~ 正在看呢~~~ 一模一样啊~~~
我的3520D也出现了这样的问题,我在$(KERNEL)/drivers/net/stmmac/stmmac_main.c 的855行、1402行,将dev_kfree_skb,更改为: dev_kfree_skb_any,但还是出现上面的问题?是要用4.4.2的__dev_kfree_skb_any函数代码来代替这边版本的代码么? 盼回复,谢谢。
回复
jim138 2016-05-24
我的3520D也出现了这样的问题,我在$(KERNEL)/drivers/net/stmmac/stmmac_main.c 的855行、1402行,将dev_kfree_skb,更改为: dev_kfree_skb_any,但还是出现上面的问题?是要用4.4.2的__dev_kfree_skb_any函数代码来代替这边版本的代码么? 盼回复,谢谢。
回复
nswcfd 2015-12-21
看明白了,stmmac_tx这个驱动的xmit接口,直接或者间接的关闭了中断(看起来是tnk_lock做的?) 那这种情况下,在驱动里面free skb的时候需要使用_any版本。 _any版本在关中断的情况下,不会直接free skb,而是先挂在一个队列上。 否则,释放skb会导致释放conntrack,导致bh_enable打印warning。
回复
常书 2015-12-15
引用 2 楼 nswcfd 的回复:
irq_disabled多半是会查询cpu的寄存器吧(比如x86的eflags)。 而in_irq是靠软件维护的counter(preempt_count的某一段bits)来计算的。 没有特别明白楼主的问题。 destory_conntrack的时候发生了什么特别的事情么? 是指local_bh_enable的时候发现irq是关闭的?
destory_conntrack->spin_unlock_bh(&nf_conntrack_lock)->local_bh_enable里有个警告: WARN_ON_ONCE(in_irq() || irqs_disabled()); 我这里因irqs_disabled触发了警告,理论上,在禁用本地中断的时候,不应该调用local_bh_enable,因它可能会打开中断,导致 预期不能被中断的代码被中断了 现在我已经找到引起irqs_disabled的原因了,是在stmmac_tx时,调用了tnk_lock引起的,也就是进入原子操作如信号量、自旋锁保护的代码也会屏蔽中断 目前因不知道为什么stmmac_tx时,要用tnk_lock保护,还不确定应该怎么修改
回复
孙小狗 2015-12-15
楼主 能加QQ么 353041817
回复
常书 2015-12-15
虽然解决了,但还不知道这个报警最终会引起什么样的问题,你那边有出现什么异常吗?
回复
常书 2015-12-15
引用 4 楼 u010247038 的回复:
楼主,我现在做3531也出现这个问题了~~ 正在看呢~~~ 一模一样啊~~~
我解决了哦,linux新版本比如最新的4.4.2修复了这个问题 __dev_kfree_skb_any函数增加对禁用irq时的SKB释放的处理,将这部分代码替换掉stmmac_tx里的 dev_kfree_skb就可以了
回复
孙小狗 2015-12-15
楼主,我现在做3531也出现这个问题了~~ 正在看呢~~~ 一模一样啊~~~
回复
nswcfd 2015-12-14
irq_disabled多半是会查询cpu的寄存器吧(比如x86的eflags)。 而in_irq是靠软件维护的counter(preempt_count的某一段bits)来计算的。 没有特别明白楼主的问题。 destory_conntrack的时候发生了什么特别的事情么? 是指local_bh_enable的时候发现irq是关闭的?
回复
常书 2015-12-14
我在irqflags.h加了如下调试信息:

#define local_irq_enable() \
	do { trace_hardirqs_on(); raw_local_irq_enable(); g_jim_flag=1;if(g_jim_print)printk("irq en!\r\n");} while (0)
#define local_irq_disable() \
	do { raw_local_irq_disable(); trace_hardirqs_off(); g_jim_flag=0;if(g_jim_print)printk("irq disable!\r\n");} while (0)
g_jim_print在进destroy_conntrack时会打开,但并没有相关打印
回复
相关推荐
发帖
Linux_Kernel
创建于2007-08-27

4148

社区成员

Linux/Unix社区 内核源代码研究区
申请成为版主
帖子事件
创建了帖子
2015-12-14 03:22
社区公告
暂无公告