事情是这样的,昨天下午本人正在苦逼的搬砖,旁边的同事突然说有台服务器的防火墙无法启动了。昨天该同事一直在补每台服务器的防火墙规则漏洞,发现这台服务器的防火墙规则和配置文件中的不一样,就想重启一下结果无法启动了。


以前也遇到过系统上正在运行的防火墙规则和配置文件的不一致,一般都是重启下防火墙就可以了,这台服务器估计是上架后没有注意一直没有发现,所以就想补下这个漏洞。


然后我就上服务器操作了下,service iptables restart 没反应,一直卡在“应用防火墙规则”这一步,service iptables status 提示没有加载防火墙模块,第一个反应就是模块不知怎么的没有了,那就手动加载下呗,

modprobe ip_tables 没反应,停掉。仔细一想,防火墙启动的时候会自动加载相关模块,没有模块是因为防火墙没有启动,那为什么手动加模块没有反应呢。找日志,一般这么妖的问题系统日志总能找到一点蛛丝马迹。


wKioL1ci_kSCfI4QAABkOQpQfB8276.png


具体日志如下:

INFO: task modprobe:29339 blocked for more than 120 seconds.

Not tainted 2.6.32-431.el6.x86_64 #1

"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.

modprobe      D 0000000000000009     0 29339      1 0x00000080

ffff880202857e48 0000000000000086 ffffea0005e17460 ffffffff810129de

ffff880202857dd8 ffffffff811238d1 ffffffff8100bb8e ffff880202857e48

ffff8802bc5c05f8 ffff880202857fd8 000000000000fbc8 ffff8802bc5c05f8

Call Trace:

[<ffffffff810129de>] ? copy_user_generic+0xe/0x20

[<ffffffff811238d1>] ? probe_kernel_write+0x41/0x70

[<ffffffff8100bb8e>] ? apic_timer_interrupt+0xe/0x20

[<ffffffff810555dd>] ? mutex_spin_on_owner+0x8d/0xc0

[<ffffffff8152907e>] __mutex_lock_slowpath+0x13e/0x180

[<ffffffffa01f4000>] ? ip_tables_init+0x0/0xb0 [ip_tables]

[<ffffffff81528f1b>] mutex_lock+0x2b/0x50

[<ffffffffa01f4000>] ? ip_tables_init+0x0/0xb0 [ip_tables]

[<ffffffff8145709d>] register_pernet_subsys+0x1d/0x50

[<ffffffffa01f4015>] ip_tables_init+0x15/0xb0 [ip_tables]

[<ffffffff8100204c>] do_one_initcall+0x3c/0x1d0

[<ffffffff810bc531>] sys_init_module+0xe1/0x250

[<ffffffff8100b072>] system_call_fastpath+0x16/0x1b



时间点比较吻合,根据关键字百度了下,有个人碰到一样的问题,系统日志也极其相似,说是有2个iptables的操作造成死锁了。

文章链接: http://www.ithao123.cn/content-8293762.html


这时候我就仔细问了下同事的操作过程,同事说下完service iptables restart后防火墙一直没有重启完成在等待某个进程的响应,就把这个命令给kill了,再执行service iptables restart就不行了。


那就去看下是否有相关进程卡住了,top后发现有个进程的状态一直是R的状态,根据我的理解(不知道对不对)进程的状态一般都是S(interruptible sleep),这个R状态的进程有点异常,根据top里面的该进程的command去ps果然发现了一个与防火墙相关的异常进程

#ps aux|grep modprobe

wKiom1cjAluyippaAAAe7QgTQGI119.png


有一个加载防火墙内核的进程状态为D,不可中断的睡眠进程,所谓D,就是不接收任何外来信号的进程。果然kill、kill -9 都无法杀死这个进程。处于uninterruptible sleep状态的进程通常是在等待IO,比如磁盘IO,网络IO,其他外设IO。那会不会是IO等待引起的呢。这时候使用iotop去观察服务器的IO情况,并没有发现该进程有大量的IO操作,同时检测NFS的状态也是正常的,那么就不是IO等待引起的。


这个进程到底卡在哪一步了,执行 ps axopid,comm,wchan | grep modprobe 

wKiom1cjBXfxyLagAAATTO24uMo667.png

发现进程运行到register_pernet_subsys这一步,搜了下相关资料,register_pernet_subsys就是防火墙启动加载内核模块这一步.

参考资料:http://blog.chinaunix.net/uid-20786208-id-5132450.html


这时候又生一计,这个进程杀不死,那能不能把该进程的父进程给kill了呢,ps一样发现进程的父进程ID居然是1。

wKioL1cjBzTyPu7-AAAcOXAvYvo654.png

正常情况下,子进程被终止时会通过 SIGCHLD 信号通知父进程,父进程可以做一些清理工作或者重新启动一个新的进程。但在某些情况下,父进程会在子进程之前被终止,那么这些子进程就没有了“父亲”,被称为孤儿进程。
init 进程会成为所有孤儿进程的父进程。init 的 pid 为1,是Linux系统的第一个进程,也是所有进程的父进程。

如果把PID为1的进程给kill了,那这个系统基本就瘫痪了。


所以折腾到最后的结果是,只能reboot系统才能解决这个问题。