问题源于一个 freeshell 内的两个进程在退出过程中,mmap 加载的 exe 文件在关闭时,NFS 的 CTO(close to open)功能为保证缓存一致性,会发起 NFS 请求来检查该缓存的文件项是否过期了。如果此操作被卡住,则该进程就成了不可中断状态的僵尸进程,如下所示。

root      893850  0.0  0.0      0     0 ?        D    Aug30   0:00 [ifup]
root      893903  0.0  0.0      0     0 ?        D    Aug30   0:00 [sleep]

尽管 RPC wait 使用的是 killable,但在退出过程中的进程已经变成 uninterruptible,因此 SIGKILL 信号是不起作用的。当然可以编写内核模块,把进程状态强制改成 Ready,这样 CPU 再次调度到此进程时就会走完退出流程,但我现在没有该版本内核的编译环境。简单起见,决定白天物理重启该服务器。

内核 stack trace(两个导致问题的进程相同)

[<ffffffffa04f69b4>] rpc_wait_bit_killable+0x24/0x40 [sunrpc]
[<ffffffffa04f698d>] __rpc_wait_for_completion_task+0x2d/0x30 [sunrpc]
[<ffffffffa05b64d3>] nfs4_do_close+0x203/0x270 [nfs]
[<ffffffffa05c4565>] __nfs4_close+0xc5/0x180 [nfs]
[<ffffffffa05c4638>] nfs4_close_sync+0x18/0x20 [nfs]
[<ffffffffa05b1320>] nfs4_close_context+0x30/0x40 [nfs]
[<ffffffffa0594d33>] __put_nfs_open_context+0xb3/0x110 [nfs]
[<ffffffffa0594e45>] nfs_release+0xb5/0xd0 [nfs]
[<ffffffffa0592b31>] nfs_file_release+0x61/0x90 [nfs]
[<ffffffff811ae468>] __fput+0xf8/0x280
[<ffffffff811ae615>] fput+0x25/0x30
[<ffffffff8121d289>] removed_exe_file_vma+0x39/0x50
[<ffffffff81170978>] remove_vma+0x118/0x130
[<ffffffff81170a68>] exit_mmap+0xd8/0x190
[<ffffffff8107305c>] mmput+0x5c/0x1f0
[<ffffffff81079a09>] exit_mm+0x109/0x150
[<ffffffff8107b7d7>] do_exit+0x187/0x930
[<ffffffff8107bfd8>] do_group_exit+0x58/0xd0
[<ffffffff8107c067>] sys_exit_group+0x17/0x20
[<ffffffff8100b102>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff

为避免此问题再次出现,考虑到 freeshell 外部存储的实际情况,现已关闭 CTO(close to open)功能。