如何清理掉系统上 D 住的进程?

43 天前
 hexler

有没有懂内核的大佬想过这个问题,我知道 D 住的是已经处于不可响应中断的状态,也知道把一个预期在等待的进程强行干掉是不好的动作。 但是我还是不能理解,linux 上我可以删掉根目录,但是却对一个 D 住的进程无可奈何,这点我很困扰。 不知道有没有专家想过这个问题,或者提供一些思路供研究,谢谢!

1659 次点击
所在节点    Linux
25 条回复
PTLin
43 天前
给你举几个 uninterruptible 状态进程的例子。
等待文件读。
拥有内核自旋锁。
就拿内核自旋锁举例,假如这个进程在锁的临界区被 kill 的话可能导致整个系统 hung 住。
idontnowhat2say
43 天前
改变进程信息结构在内存中的状态?从 D 改成其他的状态。我记得我同事说有命令可以,但我忘了
yyzh
43 天前
hexler
43 天前
@idontnowhat2say 这种方式我已经试过了,加载一个模块用来修改 task 的 state 值,如果 D 住的原因是进程进入了不可响应中断的状态的话是不可行的。
hexler
43 天前
@PTLin 我其实在想,能不能针对不同的情况来处理 D 住的进程,但是知识面太浅了,这才来 v2 找大佬要点灵感
PTLin
43 天前
那我建议你还是用 perf 或者 bpftrace 找一找变成 D 的原因和调用栈。
xwwsxp
43 天前
不是很懂,什么是 D 进程;但是,我知道的之所以能在 Linux 上将根也删除,是因为你删除的时候,Linux 是跑在内存中的,Linux 认为你可以删除 / 下的文件系统;但是,当重启之后,Linux 就会启动不了,因为需要从硬盘上加载内核(systemd 或 init),都没有对应的文件了,当然启动不了
xwwsxp
43 天前
其实,也可能压根重启不了,因为 Linux 的命令分为内部命令( shell 中的)和外部命令(硬盘上的,如:/usr/loca/bin ),所谓的内部命令就是 Linux 启动的时候,shell 会直接加载到内存中,所以 shell 下的命令也会加载进内存;但是,对于外部命令就不会了,外部命令会通过 hash 算法缓存起来,以便加快访问速度,可以通过 hash 命令来查看。
nagisaushio
43 天前
D 进程只是表象,原因有很多,比如 nfs 挂了,显卡挂了,系统忙于 swap 等等都有可能。你需要解决的是对应的具体问题
iminto
43 天前
没考虑过,直接手动删除 /proc/ 下对应的文件,估计没这么简单

你纠结能不能清理有啥意义呢,大概率是想眼不见为净,那就从读取进程信息的地方看起,不让它读出来,你应该去看读这块的代码
mightybruce
43 天前
D 状态的进程是无法杀掉的。事实上,在 Linux 内核里,内核中是无法杀掉任何进程的,所有的进程都只能自杀。

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

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

很多 D 状态( Uninterruptible Sleep State )进程都是硬件离线之类的故障导致的,基本不可控制。

用 strace 查看 进程发起哪些系统调用,是什么导致这个原因。
强行的做法 是写一个内核模块,插入模块修改进程结构将一个 uninterruptable 的进程变成 stopped 并杀掉,不过你自己承担可能出现的各种问题。
http://blog.chinaunix.net/uid-20301055-id-2741526.html
hexler
43 天前
@PTLin 我就是希望能有一种通用的方案自动处理这种情况
hexler
43 天前
@xwwsxp .........我只是举个例子
PTLin
43 天前
@PTLin 一楼我说错了,自旋锁是防止内核抢占,不是 D 状态,记错了
hexler
43 天前
@nagisaushio 我就是希望有一个通用的方案来解决 D 住的问题,至于原因 cat kstack ,看下源码,大概率就知道为啥卡住了。
比如现在一种情况,插了一个 u 盘,dd 读写,然后我 u 盘在读写的某个过程中拔掉了,并且物理破坏了这个 u 盘,虽然有些极端,但是存在很多场景相应的块设备无法再恢复的情况,这种情况居然没有一种办法恢复!我一直深受其扰
hexler
43 天前
@iminto 这个不现实,/proc 下面应该很多都没有实现删除的方法吧,直接报错的
Hawthorne
43 天前
这个想法挺好。既然能破坏性的删掉根目录,也应该允许 kill 掉 D 进程。

有一个方法是 gdb 或许可以尝试,比如跳过卡住的代码,设置直接搞挂进程。
hexler
43 天前
@mightybruce 哥,我试过修改进程状态了,不好使,不过你针对 D 状态的说法很多。
hexler
43 天前
@Hawthorne 大部分卡在内核栈,gdb 修改不了
asilin
43 天前
之前在线上解决过同事写的一个大量产生 D 进程的程序,我的解决方案是跑在 Docker 中即可,主程序自己判断当前的 D 进程数量,超过 1000 就自杀,容器重启,D 进程就自然而然的消失了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1027162

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX