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

给你举几个 uninterruptible 状态进程的例子。等待文件读。拥有内核自旋锁。就拿内核自旋锁举例,假如这个进程在锁的临界区被 kill 的话可能导致整个系统 hung 住。

改变进程信息结构在内存中的状态?从 D 改成其他的状态。我记得我同事说有命令可以,但我忘了

www.unix.com/red-hat/281782-orphaned-process-d-state.html xiaoxiang.io/5daeac0626e1410001ba0706/这里有一些想法,能不能行就不知道了

这种方式我已经试过了,加载一个模块用来修改 task 的 state 值,如果 D 住的原因是进程进入了不可响应中断的状态的话是不可行的。

我其实在想,能不能针对不同的情况来处理 D 住的进程,但是知识面太浅了,这才来 v2 找大佬要点灵感

那我建议你还是用 perf 或者 bpftrace 找一找变成 D 的原因和调用栈。

不是很懂,什么是 D 进程;但是,我知道的之所以能在 Linux 上将根也删除,是因为你删除的时候,Linux 是跑在内存中的,Linux 认为你可以删除 / 下的文件系统;但是,当重启之后,Linux 就会启动不了,因为需要从硬盘上加载内核(systemd 或 init),都没有对应的文件了,当然启动不了

其实,也可能压根重启不了,因为 Linux 的命令分为内部命令( shell 中的)和外部命令(硬盘上的,如:/usr/loca/bin ),所谓的内部命令就是 Linux 启动的时候,shell 会直接加载到内存中,所以 shell 下的命令也会加载进内存;但是,对于外部命令就不会了,外部命令会通过 hash 算法缓存起来,以便加快访问速度,可以通过 hash 命令来查看。

D 进程只是表象,原因有很多,比如 nfs 挂了,显卡挂了,系统忙于 swap 等等都有可能。你需要解决的是对应的具体问题

没考虑过,直接手动删除 /proc/ 下对应的文件,估计没这么简单你纠结能不能清理有啥意义呢,大概率是想眼不见为净,那就从读取进程信息的地方看起,不让它读出来,你应该去看读这块的代码

D 状态的进程是无法杀掉的。事实上,在 Linux 内核里,内核中是无法杀掉任何进程的,所有的进程都只能自杀。kill 的本质是向进程发送一个信号,每个进程每次在离开内核态前(例如刚被切换过来、从某个中断函数出来等),会检查自己是否收到信号,如果有就做相应的动作,如果是 SIGKILL ,就自杀。D 状态的进程,处于不可中断的状态,因此无法得知自己收到了信号,也就无法被杀掉。很多 D 状态( Uninterruptible Sleep State )进程都是硬件离线之类的故障导致的,基本不可控制。 用 strace 查看 进程发起哪些系统调用,是什么导致这个原因。强行的做法 是写一个内核模块,插入模块修改进程结构将一个 uninterruptable 的进程变成 stopped 并杀掉,不过你自己承担可能出现的各种问题。 blog.chinaunix.net/uid-20301055-id-2741526.html

我就是希望能有一种通用的方案自动处理这种情况

.........我只是举个例子

一楼我说错了,自旋锁是防止内核抢占,不是 D 状态,记错了

我就是希望有一个通用的方案来解决 D 住的问题,至于原因 cat kstack ,看下源码,大概率就知道为啥卡住了。比如现在一种情况,插了一个 u 盘,dd 读写,然后我 u 盘在读写的某个过程中拔掉了,并且物理破坏了这个 u 盘,虽然有些极端,但是存在很多场景相应的块设备无法再恢复的情况,这种情况居然没有一种办法恢复!我一直深受其扰

这个不现实,/proc 下面应该很多都没有实现删除的方法吧,直接报错的

这个想法挺好。既然能破坏性的删掉根目录,也应该允许 kill 掉 D 进程。有一个方法是 gdb 或许可以尝试,比如跳过卡住的代码,设置直接搞挂进程。

哥,我试过修改进程状态了,不好使,不过你针对 D 状态的说法很多。

大部分卡在内核栈,gdb 修改不了

之前在线上解决过同事写的一个大量产生 D 进程的程序,我的解决方案是跑在 Docker 中即可,主程序自己判断当前的 D 进程数量,超过 1000 就自杀,容器重启,D 进程就自然而然的消失了。

sysrq-trigger 就可以看到 D 进程状态echo w > /proc/sysrq-trigger 然后看内核日志

容器命名空间啥的和主机上的是隔离的,容器内的应该是可以释放掉,我改天研究下看能不能有思路,谢谢

你整句都和问题没啥关系啊

KILL 、STOP 、CONT 等很多信号都是发给内核的,和进程没什么关系,它都没有任何感觉就直接消失了