Linux df -h 卡住不动?不重启定位并解决挂载点阻塞问题

发布时间:2026/10/22 3:42:55
Linux df -h 卡住不动?不重启定位并解决挂载点阻塞问题
1. 一次诡异的运维现场df -h 卡住不动了那天下午同事在群里甩了一张截图终端里敲完df -h之后光标就一直停在那里等了快两分钟没有任何输出CtrlC 也退不出来只能另开一个窗口。第一反应是“机器是不是挂了”但top能正常刷、ssh也没断、业务进程照跑唯独这个查磁盘的命令像被点了穴。df -h这个命令干运维的没人陌生就是看各个挂载点的磁盘使用率平时零点几秒就出结果。它一旦卡住基本可以断定不是命令本身的问题而是它在执行过程中被某个内核层面的阻塞操作给绊住了。这篇文章就把我这次排查的完整过程拆开讲清楚为什么会卡、卡在哪一步、怎么在不重启机器的前提下定位并解决以及后续怎么防止同类问题再发生。适合有一定 Linux 基础、日常需要维护服务器磁盘和挂载点的同学参考新手也能跟着思路一步步看下来。先说结论方便赶时间的同学df卡住绝大多数情况是有挂载点对应的后端存储失联了比如网络存储NFS、CIFS 之类的对端不可达或者本地块设备出现 I/O 挂起。df在统计文件系统信息时会去逐个访问挂载点只要有一个挂载点“叫不应”它就会一直等下去。下面把整个推理和操作过程完整还原。2. 先搞清楚 df 到底在干什么2.1 df 的执行流程拆解很多人以为df就是读一下某个文件其实它的工作比想象中重。它大致做了这么几件事读取/proc/self/mountinfo或/etc/mtab拿到当前所有挂载点列表对每一个挂载点调用statfs()系统调用去获取该文件系统的块总数、可用块数、inode 等信息把结果格式化输出。关键就在第 2 步。statfs()是一个会真正触达后端存储的操作。对于本地磁盘这个调用几乎瞬间返回但对于网络文件系统它需要向远端发起请求。如果远端没有响应这个系统调用就会一直阻塞进程处于不可中断睡眠状态D 状态连kill -9都杀不掉。所以df -h卡住本质是某个挂载点的 statfs 调用回不来了。理解了这一点排查方向就非常明确了找出是哪个挂载点拖住了它。2.2 为什么 CtrlC 也杀不掉这里有个容易被忽略的细节。普通进程收到 SIGINTCtrlC会退出但如果进程正卡在一个不可中断的系统调用里信号是不会被处理的要等系统调用返回后才会响应。这就是为什么按 CtrlC 没反应——不是终端死了是那个进程根本没机会处理信号。提示遇到这种情况不要反复按 CtrlC也不要急着kill -9先按下面的方法定位是哪个挂载点的问题否则强杀也可能无效反而丢失现场信息。2.3 和磁盘满不是一回事顺便澄清一个常见误解df卡住和“磁盘满了”是两码事。磁盘满的时候df照样秒出结果只是使用率显示 100%。卡住是访问不到不是写不进去。这两个问题的排查路径完全不同别一上来就du找大文件方向错了白费功夫。3. 不重启机器定位卡住的挂载点3.1 用 strace 抓住卡在哪一步最直接的办法是strace。新开一个终端找到卡住的df进程 PID然后 attach 上去看它停在哪个系统调用# 找到卡住的 df 进程 ps aux | grep df -h # 假设 PID 是 12345attach 上去 strace -p 12345如果输出停在类似这样的地方statfs(/data/nfs_share, {st_modeS_IFDIR|0755, ...}) ? unfinished ...那答案就出来了——卡在/data/nfs_share这个挂载点的statfs上。unfinished ...就是它一直没返回的铁证。如果机器上没装strace也可以用/proc直接看进程状态cat /proc/12345/status | grep State # 输出 State: D (disk sleep) 就说明卡在 I/O 上了 cat /proc/12345/wchan # 会显示内核里正在等待的函数名比如 rpc_wait_bit_killablewchan这个文件很有用它告诉你进程在内核里等什么。看到rpc相关的字样基本就是网络文件系统的问题。3.2 用 mount 和 findmnt 列出所有挂载点定位到可疑挂载点后把所有挂载点列出来对照一下findmnt -t nfs,nfs4,cifs # 或者 mount | grep -E nfs|cifs|fuse重点看那些网络类型的挂载点。本地 ext4、xfs 一般不会无故卡住除非硬盘真的出问题了。网络存储才是重灾区。3.3 逐个挂载点试探如果strace不方便用可以写个小脚本逐个挂载点去stat看哪个会卡#!/bin/bash while read -r mp; do echo -n checking $mp ... timeout 3 stat -f $mp /dev/null 21 if [ $? -eq 124 ]; then echo TIMEOUT (卡住了) else echo ok fi done (awk {print $2} /proc/self/mountinfo)这个脚本给每个挂载点 3 秒超时超时的那个就是罪魁祸首。timeout命令在这里是关键它保证脚本本身不会被拖死。注意timeout对处于 D 状态的进程同样可能无效因为信号处理不了。所以这个脚本更适用于“响应慢但没完全死”的场景。真遇到完全卡死的还是得靠strace或wchan。4. 常见成因与对应处理方案4.1 网络存储对端失联这是最常见的原因。NFS、CIFS 这类网络文件系统一旦服务端宕机、网络中断、或者防火墙规则变更导致端口不通客户端上所有涉及该挂载点的操作都会挂起。判断方法# 看服务端是否可达 ping nfs_server_ip # 看 NFS 端口是否通 nc -zv nfs_server_ip 2049 # 看当前 NFS 挂载状态 nfsstat -m如果确认对端不可达处理方式分两种能恢复对端把服务端拉起来或修好网络挂载点会自动恢复df也就正常了。对端短期恢复不了需要强制卸载这个挂载点。强制卸载网络文件系统umount -f /data/nfs_share # 如果 -f 也不行用 -l 做懒卸载 umount -l /data/nfs_share-llazy的意思是先从命名空间里摘掉这个挂载点等所有引用它的进程退出后再真正清理。这样df就不会再去访问它了。4.2 本地磁盘 I/O 挂起如果不是网络存储那就要怀疑本地磁盘了。硬盘出现坏道、RAID 卡故障、或者存储控制器异常都会导致 I/O 请求长时间不返回。排查手段# 看内核日志有没有 I/O 错误 dmesg -T | tail -50 # 看磁盘健康状态需要 smartctl smartctl -a /dev/sdX # 看 I/O 等待情况 iostat -x 2 5dmesg里如果出现I/O error、ata超时、medium error之类的字样基本可以确定是硬件层面的问题。这种情况就不是软件能解决的了得联系硬件维护必要时做数据迁移。4.3 挂载点被删除但未卸载还有一种比较隐蔽的情况挂载点目录被rmdir删掉了但挂载关系还在。这时候df去访问这个“不存在的挂载点”就可能出问题。# 找出挂载点目录已经不存在的挂载 findmnt -rno TARGET | while read -r mp; do [ -d $mp ] || echo 挂载点目录丢失: $mp done处理办法是重新创建目录再卸载或者直接用umount -l懒卸载。4.4 成因速查表现象可能原因快速判断处理方式df 卡住wchan 显示 rpc网络存储失联ping/nc 对端恢复对端或 umount -f/-ldf 卡住dmesg 有 I/O error本地磁盘故障smartctl、iostat硬件维护、数据迁移df 卡住挂载点目录消失目录被误删findmnt 对照重建目录后卸载df 慢但能出结果网络存储响应慢测延迟优化网络或换存储5. 实操复盘一次完整的处理过程5.1 现场还原回到开头那次。机器上挂了一个网络存储到/data/share用于存放备份文件。当天机房那边做网络调整导致这台机器到存储服务端的链路中断了。我按下面的顺序操作第一步确认df进程状态ps -eo pid,stat,wchan:32,cmd | grep df -h # 输出12345 D rpc_wait_bit_killable df -hD状态加上rpc_wait_bit_killable直接锁定是网络文件系统的问题。第二步确认是哪个挂载点strace -p 12345 21 | head -5 # statfs(/data/share, ... unfinished ...第三步验证对端ping -c 2 storage_ip # 100% packet loss到这里结论已经很清楚了/data/share对应的存储服务端不可达df卡在它的statfs上。5.2 处理动作因为机房网络调整不是几分钟能恢复的我选择先把这个挂载点摘掉让df和其他依赖它的命令恢复正常umount -f /data/share # 报错 device is busy因为有进程在用 # 改用懒卸载 umount -l /data/share懒卸载执行后再敲df -h秒出结果问题解决。那个卡住的df进程也随之退出了。5.3 善后与验证卸载之后做了几件事确认系统状态# 确认挂载点已摘除 findmnt | grep share # 确认没有残留的 D 状态进程 ps -eo pid,stat,cmd | awk $2 ~ /D/ # 确认磁盘使用率正常 df -h同时把/etc/fstab里这个挂载项检查了一遍发现当初是用hard模式挂载的没有加超时参数。这就是问题根源之一——hard模式下客户端会无限重试永远不会放弃。6. 从根上预防挂载参数怎么配6.1 网络存储挂载参数的选择这次踩坑之后我把所有网络存储挂载参数重新梳理了一遍。核心是别用无限等待的默认配置。对于 NFS推荐加上这些参数server:/path /data/share nfs defaults,soft,timeo30,retrans3,_netdev 0 0逐个解释soft软挂载。请求失败达到重试次数后返回错误而不是无限等待。这是避免df卡死的关键。timeo30单次请求超时 30 个 0.1 秒也就是 3 秒。retrans3重试 3 次。_netdev告诉系统等网络就绪后再挂载避免开机时网络没起来导致挂载失败。注意soft模式有个副作用如果网络只是短暂抖动可能会返回 I/O 错误给应用。所以对数据一致性要求极高的场景有人仍坚持用hard但会配合intr参数允许中断。具体选哪种取决于你的业务能接受哪种失败方式。我的经验是备份、日志这类场景用soft完全够用数据库文件千万别放网络存储上。6.2 本地磁盘的监控本地磁盘虽然不容易卡df但一旦出问题更严重。建议常态化监控# 定期检查 SMART 健康 smartctl -H /dev/sdX # 监控 I/O 等待 iostat -x 1iostat里重点看%util和await。%util长期接近 100% 说明磁盘是瓶颈await突然飙高往往预示硬件要出问题。6.3 加一层超时保护对于任何可能卡住的命令养成用timeout包一层的习惯timeout 10 df -h || echo df 超时可能有挂载点异常这样即使真卡了10 秒后也会自动放弃不会把整个脚本或终端拖死。在自动化脚本里尤其重要。7. 几个容易踩的坑和实操心得7.1 别用 kill -9 硬刚前面说过D 状态的进程收不到信号kill -9也没用。更糟的是如果这个进程正持有某些资源强杀可能引发其他问题。正确做法是先解决挂载点进程自然就退出了。7.2 umount 报 busy 怎么办umount报device is busy是家常便饭。先用lsof或fuser找出谁在用lsof D /data/share fuser -mv /data/share找到进程后能停的停掉不能停的就用umount -l懒卸载。懒卸载不会立刻断开但会从命名空间摘除新命令不会再访问它。7.3 排查顺序很重要我总结的排查顺序是先看进程状态D 还是 R→ 再看 wchan → 再 strace 定位挂载点 → 最后验证对端。这个顺序从粗到细每一步都能缩小范围避免上来就瞎试。7.4 记录现场再动手处理这类问题动手前先把现场信息存下来ps输出、strace结果、dmesg日志、mount列表。因为一旦卸载或重启这些信息就没了事后复盘或者提工单都用得上。我习惯存到一个临时文件里{ date ps -eo pid,stat,wchan:32,cmd cat /proc/self/mountinfo dmesg -T | tail -100 } /tmp/df_hang_$(date %s).log7.5 常见问题速查问题排查命令解决方向df 卡住无输出ps wchan定位 D 状态进程不知道卡在哪个挂载点strace -p看 statfs 参数umount 报 busylsof / fuser停进程或懒卸载怀疑磁盘故障dmesg / smartctl硬件维护想避免再次发生检查 fstab 参数改用 soft timeo这套流程走下来df卡住这类问题基本都能在不重启的前提下解决。核心就一句话df 卡住不是 df 的错是它访问的某个挂载点回不来了找到那个挂载点问题就解决了一大半。剩下的就是根据对端能不能恢复决定是等还是卸。我个人现在的习惯是所有网络存储一律配soft加超时参数宁可让应用收到一个错误也不要让整个系统被一个失联的挂载点拖住。