处于 D 状态的进程如何杀掉

2,900 views
Skip to first unread message

Bojie Li

unread,
Feb 10, 2014, 3:12:58 AM2/10/14
to USTC_LUG
有个 freeshell 关不掉了,openvz container 里面有个 apache 进程处于 D 状态。lsof 也没有看到网络连接,这可能是卡在什么地方了?如何排查?

boj@scgyshell-7:~$ sudo lsof -n | grep root/378
/usr/sbin 21299        root  cwd       DIR             144,77     4096    9981270 /home/vz/root/378
/usr/sbin 21299        root  rtd       DIR             144,77     4096    9981270 /home/vz/root/378
/usr/sbin 21299        root    0r      CHR                1,3      0t0    9981292 /home/vz/root/378/dev/null
/usr/sbin 21299        root    1w      CHR                1,3      0t0    9981292 /home/vz/root/378/dev/null
/usr/sbin 21299        root    2w      REG             144,77     4018   10255497 /home/vz/root/378/var/log/apache2/error.log
/usr/sbin 21299        root    3r      CHR                1,9      0t0    9981275 /home/vz/root/378/dev/urandom
boj@scgyshell-7:~$ ps aux | grep 21299
root     21299  0.0  0.0      0     0 ?        Ds   Jan05   1:12 [/usr/sbin/apach]
boj      31421  0.0  0.0   7552   884 pts/0    S+   16:05   0:00 grep 21299

奇怪的是 /proc 里这个进程的 exe 符号链接打不开:

boj@scgyshell-7:~$ sudo ls -l /proc/21299/exe
ls: cannot read symbolic link /proc/21299/exe: No such file or directory
lrwxrwxrwx 1 root root 0 Feb 10 15:54 /proc/21299/exe

Zhang Cheng

unread,
Feb 10, 2014, 3:23:58 AM2/10/14
to USTC LUG
D状态的进程是无法杀掉的。事实上,在Linux内核里,内核中是无法杀掉任何进程的,所有的进程都只能自杀。

kill的本质是向进程发送一个信号,每个进程每次在离开内核态前(例如刚被切换过来、从某个中断函数出来等),会检查自己是否收到信号,如果有就做相应的动作,如果是SIGKILL,就自杀。

D状态的进程,处于不可中断的状态,因此无法得知自己收到了信号,也就无法被杀掉。


--
-- 来自USTC LUG
请使用gmail订阅,不要灌水。
更多信息more info:http://groups.google.com/group/ustc_lug?hl=en?hl=en
 
---
You received this message because you are subscribed to the Google Groups "USTC_LUG" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ustc_lug+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Cheng,
Best Regards

Zhang Cheng

unread,
Feb 10, 2014, 3:27:32 AM2/10/14
to USTC LUG
On Mon, Feb 10, 2014 at 4:12 PM, Bojie Li <boj...@gmail.com> wrote:
boj@scgyshell-7:~$ ps aux | grep 21299
root     21299  0.0  0.0      0     0 ?        Ds   Jan05   1:12 [/usr/sbin/apach]
boj      31421  0.0  0.0   7552   884 pts/0    S+   16:05   0:00 grep 21299

奇怪的是 /proc 里这个进程的 exe 符号链接打不开:

boj@scgyshell-7:~$ sudo ls -l /proc/21299/exe
ls: cannot read symbolic link /proc/21299/exe: No such file or directory
lrwxrwxrwx 1 root root 0 Feb 10 15:54 /proc/21299/exe

​从ps的结果看,21299这个进程​的名字被中括号包住,说明这是一个内核进程(这个进程只有内核态代码,没有用户态代码)。
我对openvz不了解,不清楚openvz的进程是怎么启动的。



--
Cheng,
Best Regards

Bojie Li

unread,
Feb 10, 2014, 3:33:47 AM2/10/14
to USTC_LUG

openvz 的进程都是由虚拟机里的 /sbin/init fork 出来的,虚拟机启动就是在新的内核命名空间执行 /sbin/init。

--

Yifan Gao

unread,
Feb 10, 2014, 3:46:43 AM2/10/14
to ustc...@googlegroups.com
以前遇到的 D状态(Uninterruptible Sleep State)进程都是硬件离线之类的故障导致的,貌似只能重启,不受内核控制. 

Bojie Li <boj...@gmail.com>于2014年2月10日星期一写道:

Guo, Jiahua

unread,
Feb 10, 2014, 3:57:13 AM2/10/14
to ustc...@googlegroups.com
似乎用 strace attach 上去,可以看进程卡在哪个系统调用上。

张伟

unread,
Feb 10, 2014, 3:58:15 AM2/10/14
to ustc...@googlegroups.com
D状态是卡在IO上了吧,大概和磁盘故障有关系,估计也只能sync下再重启了

Bojie Li

unread,
Feb 10, 2014, 5:06:23 AM2/10/14
to USTC_LUG

我 sync 过了,很正常。之前有一次 freeshell 虚拟机重启时出现D状态,确实是磁盘负载很高,卡在关机时的 sync 上了,等磁盘不忙了就好了。

Zhang Cheng

unread,
Feb 10, 2014, 5:08:02 AM2/10/14
to USTC LUG
2014-02-10 18:06 GMT+08:00 Bojie Li <boj...@gmail.com>:

我 sync 过了,很正常。之前有一次 freeshell 虚拟机重启时出现D状态,确实是磁盘负载很高,卡在关机时的 sync 上了,等磁盘不忙了就好了。

2014-2-10 下午5:02于 "张伟" <zwei...@gmail.com>写道:

D状态是卡在IO上了吧,大概和磁盘故障有关系,估计也只能sync下再重启了

不一定是卡在磁盘IO,也有可能是网络IO,还有可能在处理io时发生了死锁。​



--
Cheng,
Best Regards

Bojie Li

unread,
Feb 11, 2014, 12:58:52 AM2/11/14
to USTC_LUG
$ sudo strace -p 21299
attach: ptrace(PTRACE_ATTACH, ...): Permission denied

这是怎么回事?这个进程仍然存在,还是老样子(D状态)。

strace 其他进程是正常的。比如一个 nginx worker 进程:

$ sudo strace -p 2922
Process 2922 attached - interrupt to quit
epoll_wait(25, {}, 512, 500)            = 0
epoll_wait(25, {}, 512, 500)            = 0
epoll_wait(25, {}, 512, 500)            = 0
epoll_wait(25, {}, 512, 500)            = 0
epoll_wait(25, {}, 512, 500)            = 0
epoll_wait(25, {}, 512, 500)            = 0
epoll_wait(25, {}, 512, 500)            = 0
epoll_wait(25, {}, 512, 500)            = 0
epoll_wait(25, ^C <unfinished ...>
Process 2922 detached


Guo, Jiahua

unread,
Feb 11, 2014, 1:22:03 AM2/11/14
to ustc...@googlegroups.com
说不定就是个内核线程。

内核线程不能被 ptrace attach。

闫林

unread,
Feb 13, 2014, 2:35:50 AM2/13/14
to ustc...@googlegroups.com

Bojie Li

unread,
Feb 15, 2014, 12:33:35 AM2/15/14
to USTC_LUG
On Thu, Feb 13, 2014 at 3:35 PM, 闫林 <godspe...@gmail.com> wrote:

我想知道这种方法有没有副作用?比如一个 uninterruptable 的进程通过上述方法变成 stopped 并杀掉后,如果 I/O 操作完成了,会发生什么?

闫林

unread,
Feb 15, 2014, 2:15:07 AM2/15/14
to ustc...@googlegroups.com
我是这样想的
一个进程产生的IO操作只有他自己关心,IO操作的结果无论是成功还是失败对其他进程都没有太大影响(读操作完全没有,写操作有可能有)。
所以有没有副作用取决于I/O操作的类型。

毕竟,无论什么情况下强行终止进程都是有风险的。


--

Bojie Li

unread,
Feb 25, 2014, 3:51:07 PM2/25/14
to USTC_LUG

内核在调用 schedule 之前会把当前进程描述符的指针 current 放入等待队列。如果强制杀掉这个进程 (先变成 stopped 状态再发 sigkill 信号),释放了 current 指向的内存,以后万一 uninterruptable 的操作完成了 (不论是 I/O 完成还是死锁解除),准备唤醒这个进程,是否会发生非法指针解引用?这可是致命问题,我不知道销毁进程的过程中会不会从等待队列里去掉这个进程。

即使这个问题不存在,用这种方式强制杀掉进程后,是不是会造成内核空间内存泄漏,以及某些此进程正在使用的资源的引用计数永远也无法减到0?

Bojie Li

unread,
Mar 17, 2014, 2:27:06 PM3/17/14
to USTC_LUG
写了个小内核模块打印出 freeshell 两个杀不死的进程的 kernel stack trace,看起来挺有意思的,一起分析分析吧。

Kernel: 2.6.32-5-openvz-amd64 (in Debian package linux-image-2.6.32-5-openvz-amd64, 2.6.32-48squeeze4)

Pid 21299 on freeshell 378 on node 7:
User-mode process: /usr/sbin/apache2

[<ffffffff81051b55>] ? do_exit+0xdf/0x75b
[<ffffffff8104e7ee>] ? release_console_sem+0x192/0x1c4
[<ffffffff812ec5bc>] ? oops_end+0xaf/0xb4
[<ffffffff81032353>] ? no_context+0x1e9/0x1f8
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff81032506>] ? __bad_area_nosemaphore+0x1a4/0x1c8
[<ffffffff810bf313>] ? release_pages+0x17b/0x18d
[<ffffffff8101172e>] ? apic_timer_interrupt+0xe/0x20
[<ffffffff812eba85>] ? page_fault+0x25/0x30
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff812eb619>] ? _spin_lock_irqsave+0x1a/0x34
[<ffffffff8107365f>] ? uncharge_beancounter+0x1f/0x50
[<ffffffff810741d4>] ? ub_slab_uncharge+0x29/0x42
[<ffffffff810e9314>] ? kmem_cache_free+0xc3/0xd1
[<ffffffff8117d290>] ? prio_tree_remove+0xbd/0xc5
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff810d3df2>] ? exit_mmap+0xf4/0x14d
[<ffffffff8104bbca>] ? mmput+0x2b/0xf4
[<ffffffff810502dc>] ? exit_mm+0x115/0x120
[<ffffffff81051c7c>] ? do_exit+0x206/0x75b
[<ffffffff81052247>] ? do_group_exit+0x76/0x9d
[<ffffffff81052280>] ? sys_exit_group+0x12/0x16
[<ffffffff81010c12>] ? system_call_fastpath+0x16/0x1b

==========================================

Pid 8772 on freeshell 397 on node 5:
Kernel thread: apache2
Additional info: Process (e.g. ps aux) becomes uninterruptible while reading /proc/8772/cmdline

[<ffffffff8107fe51>] ? __module_text_address+0x9/0x56
[<ffffffff812eb527>] ? rwsem_down_failed_common+0x8c/0xa8
[<ffffffff812eb58a>] ? rwsem_down_read_failed+0x22/0x2b
[<ffffffff81182514>] ? call_rwsem_down_read_failed+0x14/0x30
[<ffffffff811a48b9>] ? vgacon_cursor+0x0/0x140
[<ffffffff812eaf3d>] ? down_read+0x17/0x19
[<ffffffff81088b46>] ? acct_collect+0x3e/0x16c
[<ffffffff81051c47>] ? do_exit+0x1d1/0x75b
[<ffffffff8104e7ee>] ? release_console_sem+0x192/0x1c4
[<ffffffff812ec5bc>] ? oops_end+0xaf/0xb4
[<ffffffff81032353>] ? no_context+0x1e9/0x1f8
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff81032506>] ? __bad_area_nosemaphore+0x1a4/0x1c8
[<ffffffff8108036a>] ? search_module_extables+0x3c/0x66
[<ffffffff812eda9a>] ? do_page_fault+0x185/0x2fc
[<ffffffff812eba85>] ? page_fault+0x25/0x30
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff812eb619>] ? _spin_lock_irqsave+0x1a/0x34
[<ffffffff8107365f>] ? uncharge_beancounter+0x1f/0x50
[<ffffffff810741d4>] ? ub_slab_uncharge+0x29/0x42
[<ffffffff810e9314>] ? kmem_cache_free+0xc3/0xd1
[<ffffffff8117d290>] ? prio_tree_remove+0xbd/0xc5
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff810d3c30>] ? unmap_region+0xf1/0x132
[<ffffffff810d4dfe>] ? do_munmap+0x273/0x2e1
[<ffffffff810d4eac>] ? sys_munmap+0x40/0x59
[<ffffffff81010c12>] ? system_call_fastpath+0x16/0x1b


另外,把进程状态变成 TASK_INTERRUPTBLE, TASK_RUNNING, TASK_STOPPED 后,kill -9 仍然杀不掉。我首先尝试的改变进程状态,发现进程状态改变了但仍然杀不掉,再看 stack trace 就知道这是徒劳了:这两个进程已经深陷 do_exit 这个给自己收尸的地方,肯定不会“浮”上来响应信号的。

Bojie Li

unread,
Mar 19, 2014, 5:43:19 PM3/19/14
to USTC_LUG
5号节点上的 PID 8772 是进程虚拟内存的读写锁 (process task_struct -> mm -> mmap_sem) 发生了重入死锁,把这个锁强制解开 (up_read) 后,等在这个锁上的 8772 进程、ps aux、虚拟机管理进程都“复活”了,等待了一个多月的虚拟机重启操作终于成功,397 号 freeshell 也恢复正常了。

7号节点上的 PID 21299(内核线程)问题比较严重,在退出 (do_exit) 过程中发生了缺页异常,然后时钟中断来了,又引发缺页异常,然后 do_exit 重入(中间的过程没想清楚),由于外层 do_exit 已经设置正在退出的标志位,重入的 do_exit 打印错误信息提示需要重启,这个进程将永远不再被调度。我首先是尝试调用 __put_task_struct 给进程收尸,结果进程没有消失掉,被唤醒的 OpenVZ 的内核守护线程 vmmond 却挂了(因为有些指针处于不一致状态)。

于是我决定让这个内核线程继续僵死下去,修改 OpenVZ 内核数据结构,把这个内核线程所在的虚拟机 378 从全局列表中移除,这样 OpenVZ 就不知道这个“僵尸”的存在了,启动一个新的虚拟机实例就不会报冲突。但发现相同 ID 的虚拟机建立失败,先后发现了两个原因:(1)有文件尚未关闭,无法初始化虚拟机文件系统配额。解决方法是找到虚拟机挂载点的 dentry,清空 d_subdirs 列表和 d_count 引用计数,使得 VFS 认为这里面所有文件都关闭了(事实上尚未关闭)。更完美的做法是遍历打开的子目录和文件逐个清空,我懒得这么做了。(2)内核 fairsched 调度器是以虚拟机 ID 为索引的,建立新的调度实例时发生冲突。以虚拟机 ID 为参数调用删除函数会因为引用计数未清零而失败,而 fairsched 全局数据结构的符号没有导出。最后是通过僵尸进程的 task_struct 找到这个虚拟机的调度实例并将引用计数清零。

整个过程没有对其他虚拟机造成影响,出问题的两个虚拟机也都恢复正常。5号节点问题清晰(死锁),解决方法简单直接,不过由于锁住的是进程虚拟内存,症状比较严重(ps aux 中的 read /proc/8772/cmdline 无限等待)。7号节点由于没搞清楚问题根源,用了比较 dirty 的办法,造成了一些内存泄漏,也不确定是否有“后遗症”。服务器维护小组的小伙伴们如果对这个 do_exit 重入问题感兴趣,可以登录 s7.freeshell.ustc.edu.cn 找 PID 21299。

最后啰嗦几句:以后服务器出现问题的时候,不要总想着按电源键。init 6 是更不可取的,很可能关机过程卡死在逐个关闭虚拟机的过程中,因为这种在内核里锁死的进程是不会响应信号退出的。按电源键也许几分钟就解决了,而在线(不重启物理机)修复这两个虚拟机前前后后花了我10个小时,从成本上说显然不划算,但我认为这是难得的练手机会。

Zuyi Hu

unread,
Mar 19, 2014, 11:49:07 PM3/19/14
to ustc...@googlegroups.com
刚刚reboot我的6个freeshell后,有个连不上了,分别是126,377,378,720,难道不能随便reboot
For more options, visit https://groups.google.com/d/optout.

Bojie Li

unread,
Mar 20, 2014, 7:03:51 AM3/20/14
to USTC_LUG
其中两个 freeshell 是在已经宕机的7号节点上。另两个出问题的 freeshell 在6号节点,出现了 do_exit 重入的问题。出现问题的都是虚拟机的唯一内核线程,也就是在虚拟机关闭过程中出现的问题。前几天我没有动6号节点,因此这个问题是自然发生的。6号节点的另一个虚拟机 678 也出现了同样的问题。这三个问题进程的内核调用路径几乎相同,其中有两个完全相同,可见这不是偶发问题,而是比较容易重现的 OpenVZ bug。

PID 5942 [logger], freeshell 377
PID 11524 [sshd], freeshell 720

[<ffffffff81051b55>] ? do_exit+0xdf/0x75b
[<ffffffff8104e7ee>] ? release_console_sem+0x192/0x1c4
[<ffffffff812ec5bc>] ? oops_end+0xaf/0xb4
[<ffffffff81032353>] ? no_context+0x1e9/0x1f8
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff81032506>] ? __bad_area_nosemaphore+0x1a4/0x1c8
[<ffffffff812eba85>] ? page_fault+0x25/0x30
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff812eb619>] ? _spin_lock_irqsave+0x1a/0x34
[<ffffffff8107365f>] ? uncharge_beancounter+0x1f/0x50
[<ffffffff810741d4>] ? ub_slab_uncharge+0x29/0x42
[<ffffffff810e9314>] ? kmem_cache_free+0xc3/0xd1
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff810d3df2>] ? exit_mmap+0xf4/0x14d
[<ffffffff8104bbca>] ? mmput+0x2b/0xf4
[<ffffffff810502dc>] ? exit_mm+0x115/0x120
[<ffffffff81051c7c>] ? do_exit+0x206/0x75b
[<ffffffff81052247>] ? do_group_exit+0x76/0x9d
[<ffffffff81052280>] ? sys_exit_group+0x12/0x16
[<ffffffff81010c12>] ? system_call_fastpath+0x16/0x1b

====================================

PID 30803 [mysqld], freeshell 678

[<ffffffff81051b55>] ? do_exit+0xdf/0x75b
[<ffffffff8104e7ee>] ? release_console_sem+0x192/0x1c4
[<ffffffff812ec5bc>] ? oops_end+0xaf/0xb4
[<ffffffff81032353>] ? no_context+0x1e9/0x1f8
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff81032506>] ? __bad_area_nosemaphore+0x1a4/0x1c8
[<ffffffff810bf313>] ? release_pages+0x17b/0x18d
[<ffffffff810e6b86>] ? add_partial+0x11/0x58
[<ffffffff810e8f4d>] ? __slab_free+0x7f/0x278
[<ffffffff812eba85>] ? page_fault+0x25/0x30
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff812eb619>] ? _spin_lock_irqsave+0x1a/0x34
[<ffffffff8107365f>] ? uncharge_beancounter+0x1f/0x50
[<ffffffff810741d4>] ? ub_slab_uncharge+0x29/0x42
[<ffffffff810e9314>] ? kmem_cache_free+0xc3/0xd1
[<ffffffff8117d290>] ? prio_tree_remove+0xbd/0xc5
[<ffffffff810d24dc>] ? free_pgtables+0x55/0xbd
[<ffffffff810d3df2>] ? exit_mmap+0xf4/0x14d
[<ffffffff8104bbca>] ? mmput+0x2b/0xf4
[<ffffffff810502dc>] ? exit_mm+0x115/0x120
[<ffffffff81051c7c>] ? do_exit+0x206/0x75b
[<ffffffff81052247>] ? do_group_exit+0x76/0x9d
[<ffffffff81052280>] ? sys_exit_group+0x12/0x16
[<ffffffff81010c12>] ? system_call_fastpath+0x16/0x1b

Zhang Cheng

unread,
Mar 20, 2014, 7:10:55 AM3/20/14
to USTC LUG
给openvz上游报bug?
Cheng,
Best Regards

Bojie Li

unread,
Mar 20, 2014, 7:36:52 AM3/20/14
to USTC_LUG
刚报到 OpenVZ developer mailing list 了。发现 OpenVZ 的 developer list 基本都是交 patch 的(但也有关于 new feature 的讨论),而 user list 基本都是问一些小白问题。像我遇到的这种 kernel bug,以后应该报到 developer 还是 user list?

张伟

unread,
Mar 20, 2014, 10:33:26 PM3/20/14
to ustc...@googlegroups.com
Linux® kernel 2.6.25 引入了一种新的进程状态,名为 TASK_KILLABLE,用于将进程置为睡眠状态,它可以替代有效但可能无法终止的 TASK_UNINTERRUPTIBLE 进程状态,以及易于唤醒但更加安全的 TASK_INTERRUPTIBLE 进程状态。  http://www.ibm.com/developerworks/cn/linux/l-task-killable/    是不是可以用用这个特性

Bojie Li

unread,
Mar 22, 2014, 2:53:32 PM3/22/14
to USTC_LUG
我们用的内核是 2.6.32,已经有 TASK_KILLABLE 特性了。不过,卡死在内核里的几个进程都是由于重入问题,不是锁重入就是
do_exit 重入,而这些重入本来是应该避免的,也就是内核逻辑出现了 bug。在这种情况下任务的状态是什么已经无关紧要了,即使把任务改成
TASK_RUNNING,在死锁的情况下内核控制路径还是在等锁而不会返回到内核态;而在 do_exit
里设置正在退出的标志位后,内核就再也不可能调度这个任务了。因此修改任务状态并不能解决 freeshell 遇到的问题。
Reply all
Reply to author
Forward
0 new messages