1. 问题描述
光猫下挂一个机顶盒,机顶盒通过DHCP从光猫获取地址上网,在机顶盒上面切换节目的时候,光猫出现重启,串口打印softirq: huh, entered softirq 3 NET_RX c0348f54 with preempt_count 00000101, exited with 00000302?。
2. 分析解决思路
(1) 根据串口的打印确认问题的原因是进入RX软中断前和RX软中断处理后,抢占计数不一致导致;
(2) 既然是处理RX软中断的时候出了问题,那肯定是机顶盒切换节目的时候发了某些特殊的数据包导致,然后我使用wireshark在机顶盒切换节目的时候进行了抓包;
(3) 数据包这么多,如何确认是哪一个包导致的问题呢 ? 我的思路是既然是因为特殊数据包进了协议栈导致的重启,那我能不能在防火墙的mangle表 PREROUTING链加一些规则丢掉这些特殊包不让它进行传输,不就可以确认是哪个数据包了吗?(mangle一般不会用来做数据包过滤,过滤是在filter表里面做,我这里这么做,只是因为mangle表的优先级高一点,如果是异常包,早点丢弃而已);
(4) 分析了抓包,记下了几个我认为可能会导致问题的包(选问题包的思路是一个是视频相关的包,二是看起来比较怪异的包),分析了一下这些包的内容,然后分别添加了如下规则 iptables -t mangle -I PREROUTING -m string --string "XX" --algo bm -j DROP(XX代表数据包里面的内容)。
(5) 经过(4)中的尝试,确认是协议栈处理rtsp TEARDOWN报文的时候出现了问题,因为我用防火墙丢掉这个包之后,没有出现重启。
(6) 确认了是TEARDOWN报文的问题,那么现在就去重点分析源码了,直接找和TEARDOWN报文相关的处理,一眼就看出了问题 ,系统收到TEARDOWN报文之后,会先获取一把自旋锁,然后进行了一些处理后直接返回了,没有释放自旋锁,因为获取自旋锁的时候,会增加抢占计数,如果直接返回,就会出现抢占计数泄露,和串口的log也能对的上,后面我在返回前释放了相关的自旋锁,切换节目的时候,没有再出现重启。
3. 题外话
遇到问题,不要一上来就分析源码,先学会观察,自己去分析哪里可能有问题,去确认问题的大致范围,然后再去看源码,这样效率更高。